import test from 'node:test'; import assert from 'node:assert/strict'; import { createApp } from '../server.js'; import { makeJwt, makePbCookie, startServer, stopServer, urlOf, cookieValue, } from './helpers.js'; // Fake YOUreka portal: web-auth session + openfga verify. async function startFakePortal({ cookieStatus = 'Activated', allowed = true } = {}) { return startServer((req, res) => { let raw = ''; req.on('data', (c) => (raw += c)); req.on('end', () => { const json = (status, body) => { res.writeHead(status, { 'content-type': 'application/json' }); res.end(JSON.stringify(body)); }; if (req.method === 'POST' && req.url === '/api/web/auth') { const body = JSON.parse(raw || '{}'); if (!body.returnUrl) return json(200, { ok: false, message: 'returnUrl is required' }); return json(200, { ok: true, sessionId: 's1', loginUrl: 'https://portal.example/login?return=1' }); } if (req.method === 'GET' && req.url.startsWith('/api/web/auth/s1/cookie')) { return json(200, { ok: true, sessionId: 's1', status: cookieStatus, cookie: makePbCookie(makeJwt({ expiresInSec: 3600 })), phone: '+2348068287222', firstName: 'Ada', lastName: 'Obi', }); } if (req.method === 'POST' && req.url === '/api/openfga/verify') { return json(200, { ok: true, allowed }); } json(404, { ok: false }); }); }); } // Fake PocketBase: auth-refresh always succeeds with a fresh token. async function startFakePb() { return startServer((req, res) => { res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ token: makeJwt({ expiresInSec: 3600 }), record: { id: 'u1', collectionId: 'c1', collectionName: 'users', phone: '+2348068287222' } })); }); } // Fake a2loft: records requests, echoes a staff profile. async function startFakeA2loft() { const calls = []; const server = await startServer((req, res) => { let raw = ''; req.on('data', (c) => (raw += c)); req.on('end', () => { calls.push({ method: req.method, url: req.url, body: raw ? JSON.parse(raw) : null }); const staff = { ok: true, data: { name: 'Ada Obi', reference: 'UC/0231', domainReference: 'dom-1', domainRankDescription: 'Director', fingerPrintCaptureCount: 0, }, }; res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify(req.url.includes('/fingerprints') ? { ok: true, message: 'saved' } : staff)); }); }); return { server, calls, url: null, stop: () => stopServer(server) }; } async function bootApp(appOverrides = {}, portalOpts) { const portal = await startFakePortal(portalOpts); const pb = await startFakePb(); const a2loft = await startFakeA2loft(); a2loft.url = urlOf(a2loft.server); const app = createApp({ portalUrl: urlOf(portal), pbUrl: urlOf(pb), a2loftBase: a2loft.url, ...appOverrides, }); const httpServer = await new Promise((resolve) => { const s = app.listen(0, '127.0.0.1', () => resolve(s)); }); const base = urlOf(httpServer); const stop = async () => { await new Promise((r) => httpServer.close(r)); await stopServer(portal); await stopServer(pb); await a2loft.stop(); }; return { base, a2loft, stop }; } const manual = { redirect: 'manual' }; async function login(base) { // exercises /auth/login → portal, then /auth/callback → cookies const loginRes = await fetch(`${base}/auth/login`, manual); assert.equal(loginRes.status, 302); const callbackRes = await fetch(`${base}/auth/callback?sessionId=s1`, manual); assert.equal(callbackRes.status, 302); assert.equal(callbackRes.headers.get('location'), '/fingerprint'); const session = cookieValue(callbackRes, 'session'); const profile = cookieValue(callbackRes, 'user_profile'); assert.ok(session, 'session cookie set'); assert.ok(profile, 'profile cookie set'); assert.match(profile, /2348068287222/); return `session=${session}; user_profile=${profile}`; } test('landing page links both tools', async () => { const { base, stop } = await bootApp(); try { const res = await fetch(`${base}/`); const html = await res.text(); assert.equal(res.status, 200); assert.match(html, /href="\/cropper"/); assert.match(html, /href="\/fingerprint"/); } finally { await stop(); } }); test('anonymous /fingerprint redirects to login; session APIs 401', async () => { const { base, stop } = await bootApp(); try { const page = await fetch(`${base}/fingerprint`, manual); assert.equal(page.status, 302); assert.equal(page.headers.get('location'), '/auth/login'); const api = await fetch(`${base}/auth/session`); assert.equal(api.status, 401); } finally { await stop(); } }); test('auth callback rejects unredeemable sessions without setting cookies', async () => { const { base, stop } = await bootApp({}, { cookieStatus: 'TimedOut' }); try { const res = await fetch(`${base}/auth/callback?sessionId=s1`, manual); assert.equal(res.status, 401); assert.equal(cookieValue(res, 'session'), undefined); const html = await res.text(); assert.match(html, /timed out/i); } finally { await stop(); } }); test('session endpoint returns token, profile, agent URL and permitted domains', async () => { const { base, stop } = await bootApp(); try { const cookies = await login(base); const res = await fetch(`${base}/auth/session`, { headers: { cookie: cookies } }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.ok, true); assert.match(body.token, /\./); // JWT-ish assert.equal(body.phone, '+2348068287222'); assert.equal(body.firstName, 'Ada'); assert.equal(body.agentUrl, 'http://127.0.0.1:9000'); assert.equal(body.domains.length, 5, 'all catalog domains allowed by the fake portal'); assert.equal(body.domains[0].code, 'uc'); assert.ok(body.domainsCheckedAt > 0); assert.equal(body.domainCacheTtlMs, 5 * 60 * 1000); } finally { await stop(); } }); test('domain refresh refuses while the cache is fresh, succeeds after the TTL', async () => { const { base, stop } = await bootApp({ ttlMs: 30 }); try { const cookies = await login(base); const first = await fetch(`${base}/auth/session`, { headers: { cookie: cookies } }); assert.equal(first.status, 200); // populates the permission cache const fresh = await fetch(`${base}/auth/domains/refresh`, { method: 'POST', headers: { cookie: cookies } }); assert.equal(fresh.status, 409); const body = await fresh.json(); assert.equal(body.ok, false); await new Promise((r) => setTimeout(r, 40)); const stale = await fetch(`${base}/auth/domains/refresh`, { method: 'POST', headers: { cookie: cookies } }); assert.equal(stale.status, 200); const body2 = await stale.json(); assert.equal(body2.ok, true); assert.ok(body2.domainsCheckedAt > 0); } finally { await stop(); } }); test('staff lookup proxy injects the session phone and forwards a2loft responses', async () => { const { base, a2loft, stop } = await bootApp(); try { const cookies = await login(base); const res = await fetch(`${base}/api/uc/staff/UC%2F0231?otp=4455`, { method: 'POST', headers: { cookie: cookies }, }); assert.equal(res.status, 200); const body = await res.json(); assert.equal(body.ok, true); assert.equal(body.data.name, 'Ada Obi'); assert.equal(a2loft.calls.length, 1); const call = a2loft.calls[0]; assert.equal(call.method, 'GET'); const u = new URL(call.url, 'http://x'); assert.equal(decodeURIComponent(u.pathname), '/identity/uc/UC/0231'); assert.equal(u.searchParams.get('phone'), '+2348068287222'); assert.equal(u.searchParams.get('otp'), '4455'); } finally { await stop(); } }); test('fingerprint save proxy forwards the body unchanged', async () => { const { base, a2loft, stop } = await bootApp(); try { const cookies = await login(base); const payload = { fingerprints: [{ finger: 'right-thumb', fingerprint: 'QUJD' }] }; const res = await fetch(`${base}/api/uc/staff/UC0231/fingerprints?otp=99`, { method: 'POST', headers: { cookie: cookies, 'content-type': 'application/json' }, body: JSON.stringify(payload), }); assert.equal(res.status, 200); assert.deepEqual(await res.json(), { ok: true, message: 'saved' }); const call = a2loft.calls[0]; assert.equal(call.method, 'POST'); assert.ok(call.url.startsWith('/identity/uc/fingerprints/UC0231?'), `save URL shape, got: ${call.url}`); assert.deepEqual(call.body, payload); } finally { await stop(); } }); test('proxy validation: auth, otp, and domain are enforced before contacting a2loft', async () => { const { base, a2loft, stop } = await bootApp(); try { const cookies = await login(base); const anon = await fetch(`${base}/api/uc/staff/REF?otp=1`, { method: 'POST' }); assert.equal(anon.status, 401); const noOtp = await fetch(`${base}/api/uc/staff/REF`, { method: 'POST', headers: { cookie: cookies }, }); assert.equal(noOtp.status, 400); const badDomain = await fetch(`${base}/api/nope/staff/REF?otp=1`, { method: 'POST', headers: { cookie: cookies }, }); assert.equal(badDomain.status, 400); assert.equal(a2loft.calls.length, 0, 'a2loft never contacted for rejected calls'); } finally { await stop(); } });