diff --git a/apps/api/src/application/resources/instance-resource-service.test.ts b/apps/api/src/application/resources/instance-resource-service.test.ts index 6c316c8..09feecb 100644 --- a/apps/api/src/application/resources/instance-resource-service.test.ts +++ b/apps/api/src/application/resources/instance-resource-service.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { parseSim, parseStats } from './instance-resource-service.js'; +import { InstanceResourceService, parseSim, parseStats } from './instance-resource-service.js'; const response = (body: unknown) => ({ status: 200, @@ -41,6 +41,31 @@ describe('instance resource allowlist parsing', () => { ).toEqual({ phoneNumbers: ['+86 138-0000-0000'] }); }); + it('probes passwordless instances without manufacturing a cookie', async () => { + const requests: Array<{ headers: Readonly> }> = []; + const service = new InstanceResourceService({ + instances: { get: async () => ({ origin: 'http://192.168.3.55:3000' }) } as never, + sessions: { sessionFor: () => undefined } as never, + request: async (request) => { + requests.push(request); + return response( + request.url.endsWith('/api/stats') + ? { data: { cpu_load: { load_percent: 12 }, memory: { used_percent: 34 } } } + : { data: { phone_numbers: ['13800000000'] } }, + ); + }, + }); + await expect(service.get('device-1')).resolves.toEqual({ + cpuPercent: 12, + memoryPercent: 34, + phoneNumbers: ['13800000000'], + }); + expect(requests.map((request) => request.headers)).toEqual([ + { accept: 'application/json' }, + { accept: 'application/json' }, + ]); + }); + it('fails closed for malformed and oversized payloads', () => { expect(parseStats({ status: 200, headers: {}, body: '{' })).toEqual({}); expect(parseSim({ status: 200, headers: {}, body: 'x'.repeat(40_000) })).toEqual({}); diff --git a/apps/api/src/application/resources/instance-resource-service.ts b/apps/api/src/application/resources/instance-resource-service.ts index d0af8d9..68c6ec9 100644 --- a/apps/api/src/application/resources/instance-resource-service.ts +++ b/apps/api/src/application/resources/instance-resource-service.ts @@ -77,12 +77,16 @@ export class InstanceResourceService { this.options.instances.get(instanceId), Promise.resolve(this.options.sessions.sessionFor(instanceId)), ]); - if (!instance || !session || session.origin !== instance.origin) return {}; + if (!instance) return {}; + if (session && session.origin !== instance.origin) return {}; const get = (path: '/api/stats' | '/api/sim') => this.options.request({ url: `${instance.origin}${path}`, method: 'GET', - headers: { cookie: session.cookie, accept: 'application/json' }, + headers: { + accept: 'application/json', + ...(session ? { cookie: session.cookie } : {}), + }, }); const [stats, sim] = await Promise.allSettled([get('/api/stats'), get('/api/sim')]); return {