Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ A powerful command line utility for the Unity Game Engine. Automate Unity projec
npm install -g @rage-against-the-pixel/unity-cli
```

> [!IMPORTANT]
> Requires Node v22.12 or higher.

## Usage

In general, the command structure is:
Expand Down Expand Up @@ -96,7 +99,7 @@ unity-cli license-version
- `-e`, `--email`: Email associated with the Unity account. Required when activating a personal or professional license.
- `-p`, `--password`: Password for the Unity account. Required when activating a personal or professional license.
- `-s`, `--serial`: License serial number. Required when activating a professional license.
- `-c`, `--config`: Path to the configuration file, or base64 encoded JSON string. Required when activating a floating license.
- `-c`, `--config`: Path to the configuration file, raw JSON, or base64 encoded JSON string. Required when activating a floating license.
- `--json`: Prints the last line of output as JSON string.
- `--verbose`: Enable verbose output.

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rage-against-the-pixel/unity-cli",
"version": "1.6.5",
"version": "1.6.6",
"description": "A command line utility for the Unity Game Engine.",
"author": "RageAgainstThePixel",
"license": "MIT",
Expand Down
44 changes: 42 additions & 2 deletions src/license-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class LicensingClient {
switch (process.platform) {
case 'win32':
// %PROGRAMDATA%\Unity\Config
servicesConfigDirectory = path.join(process.env.PROGRAMDATA || '', 'Unity', 'Config');
servicesConfigDirectory = path.join(process.env.PROGRAMDATA || 'C:\\ProgramData', 'Unity', 'Config');
break;
case 'darwin':
// /Library/Application Support/Unity/config
Expand All @@ -119,6 +119,45 @@ export class LicensingClient {
return path.join(servicesConfigDirectory, 'services-config.json');
}

private tryParseJson(content: string | undefined): string | undefined {
if (!content) {
return undefined;
}

try {
JSON.parse(content);
return content;
} catch {
return undefined;
}
}

private resolveServicesConfigContent(input: string): string {
const trimmedInput = input.trim();

if (trimmedInput.length === 0) {
throw new Error('Services config value is empty. Provide a file path, JSON, or base64 encoded JSON string.');
}

const directJson = this.tryParseJson(trimmedInput);

if (directJson) {
return directJson;
}

const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
if (base64Regex.test(trimmedInput)) {
const decoded = Buffer.from(trimmedInput, 'base64').toString('utf-8').trim();
const decodedJson = this.tryParseJson(decoded);

if (decodedJson) {
return decodedJson;
}
}

throw new Error('Services config value is not a valid JSON string or base64 encoded JSON string.');
}

/**
* Gets the path to the Unity Licensing Client log file.
* @see https://docs.unity.com/en-us/licensing-server/troubleshooting-client#logs
Expand Down Expand Up @@ -441,7 +480,8 @@ export class LicensingClient {
fs.copyFileSync(options.servicesConfig, servicesConfigPath);
}
else {
fs.writeFileSync(servicesConfigPath, Buffer.from(options.servicesConfig, 'base64'));
const configContent = this.resolveServicesConfigContent(options.servicesConfig);
fs.writeFileSync(servicesConfigPath, configContent, { encoding: 'utf-8' });
}

if (process.platform !== 'win32') {
Expand Down
27 changes: 27 additions & 0 deletions tests/license-client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { LicensingClient } from '../src/license-client';

describe('LicensingClient services config handling', () => {
const invokeResolver = (input: string) => {
const client = new LicensingClient();
return (client as any).resolveServicesConfigContent(input);
};

it('accepts raw JSON input', () => {
const json = '{"floatingServer":"https://example.com"}';
expect(invokeResolver(json)).toBe(json);
});

it('accepts base64 encoded JSON input', () => {
const json = '{"floatingServer":"https://example.com"}';
const encoded = Buffer.from(json, 'utf-8').toString('base64');
expect(invokeResolver(encoded)).toBe(json);
});

it('rejects invalid inline config', () => {
expect(() => invokeResolver('not-a-valid-config')).toThrow('Services config value is not a valid JSON string or base64 encoded JSON string.');
});

it('rejects empty inline config', () => {
expect(() => invokeResolver(' ')).toThrow('Services config value is empty. Provide a file path, JSON, or base64 encoded JSON string.');
});
});
Loading