import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import test from 'node:test'; import { createGatewayPresenceRoute } from '../../dist/server/http/routes/gatewayPresenceRoute.js'; const subscriptionUrl = 'https://subscription.example/0123456789abcdef0123456789abcdef'; const nonce = '0123456789abcdef0123456789abcdef'; function response() { return { writeHead(status, headers) { this.status = status; this.headers = headers; }, end(payload) { this.payload = JSON.parse(payload); }, }; } function createHarness(overrides = {}) { const events = []; const route = createGatewayPresenceRoute({ appMode: overrides.appMode || 'gateway', readState: () => { events.push('state'); if (overrides.stateError) throw overrides.stateError; return { subscriptionUrl: overrides.subscriptionUrl ?? subscriptionUrl }; }, getHwid: () => { events.push('hwid'); if (overrides.hwidError) throw overrides.hwidError; return overrides.gatewayId ?? 'gateway-1'; }, }); return { route, events }; } test('Gateway presence route preserves query nonce, read order and raw response', async () => { const harness = createHarness(); const res = response(); assert.equal(await harness.route.handle({ method: 'GET', url: `/api/gateway-presence?source=client&nonce=${nonce}&nonce=ignored`, }, res), true); assert.deepEqual(harness.events, ['state', 'hwid']); assert.equal(res.status, 200); assert.equal(res.headers['content-type'], 'application/json; charset=utf-8'); assert.deepEqual({ ...res.payload, proof: '[proof]', }, { success: true, available: true, product: 'harbor', role: 'gateway', protocolVersion: 1, gatewayId: 'gateway-1', transparentRouting: true, proof: '[proof]', }); assert.match(res.payload.proof, /^[a-f0-9]{64}$/); }); test('Gateway presence route preserves unavailable client and missing identity responses', async () => { for (const options of [ { appMode: 'client' }, { gatewayId: '' }, { subscriptionUrl: 'https://subscription.example/public-feed' }, ]) { const harness = createHarness(options); const res = response(); await harness.route.handle({ method: 'GET', url: `/api/gateway-presence?nonce=${nonce}`, }, res); assert.deepEqual(res.payload, { success: true, available: false, product: 'harbor', role: options.appMode || 'gateway', protocolVersion: 1, }); } }); test('Gateway presence route reads state and HWID before preserving nonce validation errors', async () => { for (const value of [null, 'ABCDEF0123456789ABCDEF0123456789', 'short']) { const harness = createHarness(); const url = value === null ? '/api/gateway-presence' : `/api/gateway-presence?nonce=${value}`; await assert.rejects( harness.route.handle({ method: 'GET', url }, response()), (error) => error.code === 'REQUEST_INVALID', ); assert.deepEqual(harness.events, ['state', 'hwid']); } }); test('Gateway presence route guards before dependencies and propagates dependency errors', async () => { for (const [method, url] of [ ['POST', `/api/gateway-presence?nonce=${nonce}`], ['GET', `/api/gateway-presence/extra?nonce=${nonce}`], ['GET', `/api/other?nonce=${nonce}`], ]) { const harness = createHarness(); assert.equal(await harness.route.handle({ method, url }, response()), false); assert.deepEqual(harness.events, []); } const stateError = new Error('state failed'); const brokenState = createHarness({ stateError }); await assert.rejects( brokenState.route.handle({ method: 'GET', url: `/api/gateway-presence?nonce=${nonce}` }, response()), (error) => error === stateError, ); assert.deepEqual(brokenState.events, ['state']); const hwidError = new Error('hwid failed'); const brokenHwid = createHarness({ hwidError }); await assert.rejects( brokenHwid.route.handle({ method: 'GET', url: `/api/gateway-presence?nonce=${nonce}` }, response()), (error) => error === hwidError, ); assert.deepEqual(brokenHwid.events, ['state', 'hwid']); }); test('Gateway presence route is the sole HTTP owner', () => { const index = readFileSync(new URL('../../src/server/index.ts', import.meta.url), 'utf8'); const route = readFileSync( new URL('../../src/server/http/routes/gatewayPresenceRoute.ts', import.meta.url), 'utf8', ); assert.match(index, /createGatewayPresenceRoute\(\{/); assert.match(index, /gatewayPresenceRoute\.handle\(req, res\)/); assert.doesNotMatch(index, /\/api\/gateway-presence|buildGatewayPresence|searchParams\.get\(['"]nonce/); assert.match(route, /buildGatewayPresence\(\{/); assert.match(route, /searchParams\.get\(['"]nonce['"]\)/); });