Files
Alta-Proxy-Tool/test/proxy-launch.test.js
peji ace4568f81
APT build checks / build-checks (push) Successful in 37s
APT build checks / build-checks (pull_request) Successful in 37s
feat: release passwordless hierarchical APT v1.2.5
2026-08-22 16:20:12 +00:00

392 lines
13 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const { EventEmitter } = require('node:events');
const fs = require('node:fs');
const path = require('node:path');
const MODULE_PATH = '../src/proxy-launch';
const APPROVED_DIRECTORY = 'C:\\Program Files\\Alta Proxy Tool';
const APPROVED_HELPER = 'C:\\Program Files\\Alta Proxy Tool\\aware-cam-proxy.exe';
const VALID_HOST = 'tenant.avasecurity.com';
const VALID_DEVICE_ID = '123e4567-e89b-42d3-a456-426614174000';
const SYNTHETIC_COOKIE = 'HERMES_SENTINEL_SESSION_COOKIE';
function loadModule() {
return require(MODULE_PATH);
}
class FakeChild extends EventEmitter {
constructor(pid, killResult = true) {
super();
this.pid = pid;
this.killResult = killResult;
this.killCalls = [];
this.killError = null;
this.exitCode = null;
this.signalCode = null;
}
kill(signal) {
this.killCalls.push(signal);
if (this.killError) throw this.killError;
return this.killResult;
}
}
function createHarness({
helperExists = true,
children = [new FakeChild(4101)],
stopTimeoutMs = 5_000,
setTimeout = global.setTimeout,
clearTimeout = global.clearTimeout,
} = {}) {
const calls = [];
let childIndex = 0;
const spawn = (...args) => {
calls.push(args);
return children[childIndex++];
};
const fsStub = { existsSync: (candidate) => helperExists && candidate === APPROVED_HELPER };
const { createProxyManager } = loadModule();
const manager = createProxyManager({
appDirectory: APPROVED_DIRECTORY,
fs: fsStub,
spawn,
platform: 'win32',
now: () => 1_777_777_777_777,
stopTimeoutMs,
setTimeout,
clearTimeout,
});
return { manager, calls, children };
}
function validRequest(overrides = {}) {
return {
deploymentHost: VALID_HOST,
deviceId: VALID_DEVICE_ID,
cookie: SYNTHETIC_COOKIE,
...overrides
};
}
test('exports the proxy manager module', () => {
assert.doesNotThrow(() => loadModule());
});
test('launches the approved helper directly with the paired Alta session', () => {
const { manager, calls } = createHarness();
const result = manager.launchProxy(validRequest());
assert.deepEqual(calls, [[
APPROVED_HELPER,
['-a', VALID_HOST, '-d', VALID_DEVICE_ID, '-k', SYNTHETIC_COOKIE],
{
shell: false,
detached: true,
stdio: 'ignore',
windowsHide: false
}
]]);
assert.deepEqual(result, {
success: true,
processId: 4101,
deviceId: VALID_DEVICE_ID,
startedAt: 1_777_777_777_777,
status: 'running'
});
});
test('passes the paired cookie literally without invoking a shell or console prompt', () => {
const cookie = 'abc_DEF-123.456==';
const { manager, calls } = createHarness();
manager.launchProxy(validRequest({ cookie }));
assert.equal(calls[0][1][5], cookie);
assert.equal(calls[0][2].shell, false);
assert.equal(calls[0][2].stdio, 'ignore');
});
test('rejects the CRLF calc.exe reproducer in every structured input', () => {
const { manager, calls } = createHarness();
const attacks = [
{ deploymentHost: `${VALID_HOST}\r\ncalc.exe` },
{ deviceId: `${VALID_DEVICE_ID}\r\ncalc.exe` },
{ cookie: `${SYNTHETIC_COOKIE}\r\ncalc.exe` },
{ cookie: `${SYNTHETIC_COOKIE}\0calc.exe` }
];
for (const attack of attacks) {
assert.throws(() => manager.launchProxy(validRequest(attack)), /invalid|must not contain/i);
}
assert.equal(calls.length, 0);
});
test('rejects shell metacharacters in deployment hosts and device identifiers', () => {
const { manager, calls } = createHarness();
for (const deploymentHost of [
'tenant.avasecurity.com&calc.exe',
'tenant.avasecurity.com|calc.exe',
'https://tenant.avasecurity.com',
'tenant.avasecurity.com/path',
'tenant.avasecurity.com:443'
]) {
assert.throws(() => manager.launchProxy(validRequest({ deploymentHost })), /deployment host/i);
}
for (const deviceId of [
`${VALID_DEVICE_ID}&calc.exe`,
`${VALID_DEVICE_ID}|calc.exe`,
'$(calc.exe)'
]) {
assert.throws(() => manager.launchProxy(validRequest({ deviceId })), /device identifier/i);
}
assert.equal(calls.length, 0);
});
test('accepts only strict canonical UUID device identifiers', () => {
const invalidIds = [
'',
'123e4567-e89b-12d3-a456-42661417400',
'123e4567e89b42d3a456426614174000',
'123e4567-e89b-02d3-a456-426614174000',
'123e4567-e89b-42d3-c456-426614174000',
'g23e4567-e89b-42d3-a456-426614174000',
'a'.repeat(37)
];
for (const deviceId of invalidIds) {
const { manager } = createHarness();
assert.throws(() => manager.launchProxy(validRequest({ deviceId })), /device identifier/i);
}
});
test('accepts only bounded Alta subdomain hostnames from trusted session state', () => {
const invalidHosts = [
'',
'avasecurity.com',
'avigilon.com',
'evil.example',
'tenant.avasecurity.com.evil.example',
'.avasecurity.com',
'-tenant.avasecurity.com',
'tenant..avasecurity.com',
'tenant_avasecurity.com',
`tenant.${'a'.repeat(240)}.avasecurity.com`
];
for (const deploymentHost of invalidHosts) {
const { manager } = createHarness();
assert.throws(() => manager.launchProxy(validRequest({ deploymentHost })), /deployment host/i);
}
});
test('normalizes a valid Alta hostname to lowercase', () => {
const { manager, calls } = createHarness();
manager.launchProxy(validRequest({ deploymentHost: 'Tenant.AVIGILON.com' }));
assert.equal(calls[0][1][1], 'tenant.avigilon.com');
});
test('rejects empty, oversized, non-string, and control-character cookies', () => {
for (const cookie of ['', 'x'.repeat(4097), 42, 'abc\nxyz', 'abc\rxyz', 'abc\0xyz', 'abc;xyz']) {
const { manager } = createHarness();
assert.throws(() => manager.launchProxy(validRequest({ cookie })), /cookie/i);
}
});
test('fails closed when the fixed helper is missing and never spawns', () => {
const { manager, calls } = createHarness({ helperExists: false });
assert.throws(() => manager.launchProxy(validRequest()), /helper.*not found/i);
assert.equal(calls.length, 0);
});
test('requires an absolute approved application directory and Windows platform', () => {
const { createProxyManager } = loadModule();
const dependencies = { fs: { existsSync: () => true }, spawn: () => new FakeChild(1) };
assert.throws(
() => createProxyManager({ appDirectory: '..\\untrusted', platform: 'win32', ...dependencies }),
/absolute/i
);
assert.throws(
() => createProxyManager({ appDirectory: '/opt/apt', platform: 'linux', ...dependencies }),
/platform/i
);
});
test('redacts the cookie if spawn throws an error containing it', () => {
const { createProxyManager } = loadModule();
const manager = createProxyManager({
appDirectory: APPROVED_DIRECTORY,
fs: { existsSync: () => true },
platform: 'win32',
spawn: () => { throw new Error(`spawn failed for ${SYNTHETIC_COOKIE}`); }
});
assert.throws(
() => manager.launchProxy(validRequest()),
(error) => {
assert.match(error.message, /spawn failed/);
assert.match(error.message, /\[REDACTED\]/);
assert.doesNotMatch(error.message, /HERMES_SENTINEL_SESSION_COOKIE/);
return true;
}
);
});
test('tracks only safe process metadata and never exposes cookies', () => {
const { manager } = createHarness();
manager.launchProxy(validRequest());
const tracked = manager.listTrackedProxies();
assert.deepEqual(tracked, [{
processId: 4101,
deviceId: VALID_DEVICE_ID,
startedAt: 1_777_777_777_777,
status: 'running'
}]);
assert.doesNotMatch(JSON.stringify(tracked), /HERMES_SENTINEL_SESSION_COOKIE/);
});
test('stopping one tracked process waits for confirmed exit and leaves the other alive', async () => {
const first = new FakeChild(4101);
const second = new FakeChild(4102);
const { manager } = createHarness({ children: [first, second] });
manager.launchProxy(validRequest());
manager.launchProxy(validRequest({ deviceId: '123e4567-e89b-42d3-a456-426614174001' }));
const stopping = manager.stopProxy(4101);
assert.deepEqual(manager.listTrackedProxies().map((item) => [item.processId, item.status]), [
[4101, 'stopping'],
[4102, 'running'],
]);
first.emit('exit', 0, 'SIGTERM');
const result = await stopping;
assert.deepEqual(result, {
success: true,
processId: 4101,
deviceId: VALID_DEVICE_ID,
status: 'stopped'
});
assert.deepEqual(first.killCalls, ['SIGTERM']);
assert.deepEqual(second.killCalls, []);
assert.deepEqual(manager.listTrackedProxies().map((item) => item.processId), [4102]);
});
test('never stops an untracked PID', async () => {
const child = new FakeChild(4101);
const { manager } = createHarness({ children: [child] });
manager.launchProxy(validRequest());
assert.deepEqual(await manager.stopProxy(9999), {
success: false,
processId: 9999,
status: 'not-tracked'
});
assert.deepEqual(child.killCalls, []);
});
test('reports already-exited and permission-denied states honestly', async () => {
const exited = new FakeChild(4101, false);
exited.exitCode = 0;
const denied = new FakeChild(4102);
denied.killError = Object.assign(new Error('operation not permitted'), { code: 'EPERM' });
const { manager } = createHarness({ children: [exited, denied] });
manager.launchProxy(validRequest());
manager.launchProxy(validRequest({ deviceId: '123e4567-e89b-42d3-a456-426614174001' }));
assert.deepEqual(await manager.stopProxy(4101), {
success: true,
processId: 4101,
deviceId: VALID_DEVICE_ID,
status: 'already-exited'
});
assert.deepEqual(await manager.stopProxy(4102), {
success: false,
processId: 4102,
deviceId: '123e4567-e89b-42d3-a456-426614174001',
status: 'permission-denied',
message: 'Unable to stop the tracked proxy process: permission denied.'
});
assert.deepEqual(manager.listTrackedProxies().map((item) => item.processId), [4102]);
});
test('kill true is only a request and times out while the child remains tracked as stopping', async () => {
let timeoutCallback;
const child = new FakeChild(4101, true);
const { manager } = createHarness({
children: [child],
stopTimeoutMs: 25,
setTimeout(callback, delay) {
assert.equal(delay, 25);
timeoutCallback = callback;
return 123;
},
clearTimeout() {},
});
manager.launchProxy(validRequest());
const stopping = manager.stopProxy(4101);
assert.deepEqual(manager.listTrackedProxies().map(({ processId, status }) => ({ processId, status })), [
{ processId: 4101, status: 'stopping' },
]);
timeoutCallback();
assert.deepEqual(await stopping, {
success: false,
processId: 4101,
deviceId: VALID_DEVICE_ID,
status: 'stop-timeout',
message: 'Timed out waiting for the tracked proxy process to exit.',
});
assert.equal(manager.listTrackedProxies()[0].status, 'stopping');
});
test('kill false does not claim success without confirmed exit', async () => {
const child = new FakeChild(4101, false);
const { manager } = createHarness({ children: [child] });
manager.launchProxy(validRequest());
assert.deepEqual(await manager.stopProxy(4101), {
success: false,
processId: 4101,
deviceId: VALID_DEVICE_ID,
status: 'stop-failed',
message: 'Unable to confirm that the tracked proxy process exited.',
});
assert.equal(manager.listTrackedProxies()[0].status, 'stopping');
});
test('generic child errors retain tracking unless process exit is confirmed', () => {
const child = new FakeChild(4101);
const { manager } = createHarness({ children: [child] });
manager.launchProxy(validRequest());
child.emit('error', new Error('transient process error'));
assert.deepEqual(manager.listTrackedProxies().map((entry) => entry.processId), [4101]);
});
test('exit events remove only the matching owned child', () => {
const original = new FakeChild(4101);
const replacement = new FakeChild(4101);
const { manager } = createHarness({ children: [original, replacement] });
manager.launchProxy(validRequest());
original.emit('exit', 0);
manager.launchProxy(validRequest({ deviceId: '123e4567-e89b-42d3-a456-426614174001' }));
original.emit('exit', 0);
assert.deepEqual(manager.listTrackedProxies().map((item) => item.processId), [4101]);
});
test('source contains no shell launchers, broad process killers, or credential persistence APIs', () => {
const source = fs.readFileSync(path.join(__dirname, '..', 'src', 'proxy-launch.js'), 'utf8');
assert.doesNotMatch(source, /\b(?:cmd(?:\.exe)?|powershell|taskkill|pkill|wmic)\b/i);
assert.doesNotMatch(source, /\.(?:bat|command)\b/i);
assert.doesNotMatch(source, /(?:writeFile|appendFile|mkdtemp|tmpdir)/);
assert.match(source, /shell:\s*false/);
});