@@ -4,7 +4,10 @@ import * as path from 'path';
44import { spawn } from 'child_process' ;
55import { Logger } from './logging' ;
66import { UnityHub } from './unity-hub' ;
7- import { ResolveGlobToPath } from './utilities' ;
7+ import {
8+ ResolveGlobToPath ,
9+ tryParseJson
10+ } from './utilities' ;
811
912export enum LicenseType {
1013 personal = 'personal' ,
@@ -119,45 +122,59 @@ export class LicensingClient {
119122 return path . join ( servicesConfigDirectory , 'services-config.json' ) ;
120123 }
121124
122- private tryParseJson ( content : string | undefined ) : string | undefined {
123- if ( ! content ) {
124- return undefined ;
125- }
126-
127- try {
128- JSON . parse ( content ) ;
129- return content ;
130- } catch {
131- return undefined ;
132- }
133- }
134-
135125 private resolveServicesConfigContent ( input : string ) : string {
136126 const trimmedInput = input . trim ( ) ;
137127
138128 if ( trimmedInput . length === 0 ) {
139129 throw new Error ( 'Services config value is empty. Provide a file path, JSON, or base64 encoded JSON string.' ) ;
140130 }
141131
142- const directJson = this . tryParseJson ( trimmedInput ) ;
132+ const rawJson = tryParseJson ( trimmedInput ) ;
143133
144- if ( directJson ) {
145- return directJson ;
134+ if ( rawJson ) {
135+ return rawJson ;
146136 }
147137
148- const base64Regex = / ^ [ A - Z a - z 0 - 9 + / ] * = { 0 , 2 } $ / ;
149- if ( base64Regex . test ( trimmedInput ) ) {
150- const decoded = Buffer . from ( trimmedInput , 'base64' ) . toString ( 'utf-8' ) . trim ( ) ;
151- const decodedJson = this . tryParseJson ( decoded ) ;
138+ try {
139+ const base64Regex = / ^ [ A - Z a - z 0 - 9 + / ] * = { 0 , 2 } $ / ;
140+
141+ if ( base64Regex . test ( trimmedInput ) ) {
142+ const decoded = Buffer . from ( trimmedInput , 'base64' ) . toString ( 'utf-8' ) . trim ( ) ;
143+ const decodedJson = tryParseJson ( decoded ) ;
152144
153- if ( decodedJson ) {
154- return decodedJson ;
145+ if ( decodedJson ) {
146+ return decodedJson ;
147+ }
148+ } else {
149+ throw new Error ( 'Input does not match base64 format.' ) ;
155150 }
156151 }
152+ catch ( error ) {
153+ throw new Error ( `Failed to decode services config as base64: ${ error } ` ) ;
154+ }
157155
158156 throw new Error ( 'Services config value is not a valid JSON string or base64 encoded JSON string.' ) ;
159157 }
160158
159+ private async setupServicesConfig ( configSource : string ) : Promise < string > {
160+ const servicesConfigPath = this . servicesConfigPath ( ) ;
161+
162+ if ( fs . existsSync ( configSource ) ) {
163+ fs . copyFileSync ( configSource , servicesConfigPath ) ;
164+ }
165+ else {
166+ const configContent = this . resolveServicesConfigContent ( configSource ) ;
167+ fs . writeFileSync ( servicesConfigPath , configContent , { encoding : 'utf-8' } ) ;
168+ }
169+
170+ if ( process . platform !== 'win32' ) {
171+ fs . chmodSync ( servicesConfigPath , 0o644 ) ;
172+ }
173+
174+ fs . accessSync ( servicesConfigPath , fs . constants . R_OK ) ;
175+ return servicesConfigPath ;
176+ }
177+
161178 /**
162179 * Gets the path to the Unity Licensing Client log file.
163180 * @see https://docs.unity.com/en-us/licensing-server/troubleshooting-client#logs
@@ -459,8 +476,19 @@ export class LicensingClient {
459476 * @throws Error if activation fails or required parameters are missing.
460477 */
461478 public async Activate ( options : ActivateOptions , skipEntitlementCheck : boolean = false ) : Promise < string | undefined > {
479+ let servicesConfigPath : string | undefined ;
480+
481+ if ( options . licenseType === LicenseType . floating ) {
482+ if ( ! options . servicesConfig ) {
483+ throw new Error ( 'Services config path is required for floating license activation' ) ;
484+ }
485+
486+ servicesConfigPath = await this . setupServicesConfig ( options . servicesConfig ) ;
487+ this . logger . debug ( `Using services config at: ${ servicesConfigPath } ` ) ;
488+ }
489+
462490 if ( ! skipEntitlementCheck ) {
463- let activeLicenses = await this . GetActiveEntitlements ( ) ;
491+ const activeLicenses = await this . GetActiveEntitlements ( ) ;
464492
465493 if ( activeLicenses . includes ( options . licenseType ) ) {
466494 this . logger . info ( `License of type '${ options . licenseType } ' is already active, skipping activation` ) ;
@@ -470,27 +498,6 @@ export class LicensingClient {
470498
471499 switch ( options . licenseType ) {
472500 case LicenseType . floating : {
473- if ( ! options . servicesConfig ) {
474- throw new Error ( 'Services config path is required for floating license activation' ) ;
475- }
476-
477- const servicesConfigPath = this . servicesConfigPath ( ) ;
478-
479- if ( fs . existsSync ( options . servicesConfig ) ) {
480- fs . copyFileSync ( options . servicesConfig , servicesConfigPath ) ;
481- }
482- else {
483- const configContent = this . resolveServicesConfigContent ( options . servicesConfig ) ;
484- fs . writeFileSync ( servicesConfigPath , configContent , { encoding : 'utf-8' } ) ;
485- }
486-
487- if ( process . platform !== 'win32' ) {
488- fs . chmodSync ( servicesConfigPath , 0o644 ) ;
489- }
490-
491- fs . accessSync ( servicesConfigPath , fs . constants . R_OK ) ;
492- this . logger . debug ( `Using services config at: ${ servicesConfigPath } ` ) ;
493-
494501 const output = await this . exec ( [ `--acquire-floating` ] , true ) ;
495502 const tokenMatch = output . match ( / w i t h t o k e n : \s * " (?< token > [ \w - ] + ) " / ) ;
496503
0 commit comments