import assert from "node:assert/strict"; import test from "node:test"; import { createDeviceManagerAuth } from "./device-manager-auth.mjs"; const internalToken = "launcher-internal-token-must-stay-server-side"; const launcherSessionId = "launcher-session-id-must-stay-server-side"; test("Launcher handoff becomes an opaque Device Manager session and trusted actor", async () => { const calls = []; const auth = createDeviceManagerAuth({ env: productionEnv(), fetchImpl: async (url, init) => { calls.push({ url: String(url), init }); return jsonResponse(200, { ok: true, launcherSessionId, access: { allowed: true, hubRole: "owner", ownerScopes: [ { scopeKind: "company", ownerRef: "client:client_dctouch", displayName: "DC Touch", }, { scopeKind: "personal", ownerRef: "user:user_root", displayName: "DC SUDO", }, ], }, user: { id: "user_root", email: "root@example.test", name: "DC SUDO", groups: ["nodedc:superadmin", "nodedc:device-core:admin"], }, }); }, }); const response = mockResponse(); await auth.handleHandoff( { method: "GET", headers: {} }, response, new URL("https://device.example.test/auth/nodedc/handoff?token=handoff-secret&next_path=%2F"), ); assert.equal(response.statusCode, 302); assert.equal(calls.length, 1); assert.equal(calls[0].init.headers.Authorization, `Bearer ${internalToken}`); assert.deepEqual(JSON.parse(calls[0].init.body), { token: "handoff-secret", serviceSlug: "device-core", }); const cookie = String(response.getHeader("set-cookie")).split(";", 1)[0]; assert.match(cookie, /^nodedc_device_manager_session=[A-Za-z0-9_-]{40,}$/); assert.equal(cookie.includes("user_root"), false); assert.equal(cookie.includes(launcherSessionId), false); const request = { method: "GET", headers: { cookie, accept: "application/json" } }; const authorized = await auth.authorize( request, mockResponse(), new URL("https://device.example.test/api/device-manager/session"), ); assert.equal(authorized, false); const context = auth.currentContext(request); assert.equal(context.actor.userRef, "user:user_root"); assert.equal(context.actor.hubRole, "owner"); assert.deepEqual(context.actor.ownerScopes, [ { scopeKind: "company", ownerRef: "client:client_dctouch", displayName: "DC Touch", }, { scopeKind: "personal", ownerRef: "user:user_root", displayName: "DC SUDO", }, ]); assert.deepEqual(context.actor.groupRefs, [ "group:nodedc:device-core:admin", "group:nodedc:superadmin", ]); assert.equal(JSON.stringify(context).includes(launcherSessionId), false); assert.equal(JSON.stringify(context).includes(internalToken), false); }); test("invalid identity and explicit Device Core block never produce an actor", async () => { for (const user of [ { id: "?", groups: ["nodedc:device-core:admin"] }, { id: "valid-user", groups: ["nodedc:superadmin", "nodedc:device-core:blocked"] }, ]) { const auth = createDeviceManagerAuth({ env: productionEnv(), fetchImpl: async () => jsonResponse(200, { ok: true, launcherSessionId, access: { allowed: true, hubRole: "admin", ownerScopes: [], }, user, }), }); const handoff = mockResponse(); await auth.handleHandoff( { method: "GET", headers: {} }, handoff, new URL("https://device.example.test/auth/nodedc/handoff?token=handoff-secret"), ); const cookie = String(handoff.getHeader("set-cookie")).split(";", 1)[0]; const request = { method: "GET", headers: { cookie, accept: "application/json" } }; const response = mockResponse(); assert.equal(await auth.authorize( request, response, new URL("https://device.example.test/api/device-manager/session"), ), true); assert.equal(response.statusCode, 403); } }); test("production auth fails closed when Launcher omits trusted Device Core access", async () => { const auth = createDeviceManagerAuth({ env: productionEnv(), fetchImpl: async () => jsonResponse(200, { ok: true, launcherSessionId, user: { id: "user_root", email: "root@example.test", name: "DC SUDO", groups: ["nodedc:superadmin"], }, }), }); const handoff = mockResponse(); await auth.handleHandoff( { method: "GET", headers: {} }, handoff, new URL("https://device.example.test/auth/nodedc/handoff?token=handoff-secret"), ); const cookie = String(handoff.getHeader("set-cookie")).split(";", 1)[0]; const response = mockResponse(); assert.equal(await auth.authorize( { method: "GET", headers: { cookie, accept: "application/json" } }, response, new URL("https://device.example.test/api/device-manager/session"), ), true); assert.equal(response.statusCode, 403); assert.equal(JSON.parse(response.body).error, "device_manager_access_denied"); }); test("an injected file-backed token takes precedence over broad platform env tokens", async () => { const calls = []; const auth = createDeviceManagerAuth({ env: { ...productionEnv(), NODEDC_INTERNAL_ACCESS_TOKEN: "broad-platform-token" }, internalToken: "scoped-file-token", fetchImpl: async (url, init) => { calls.push({ url, init }); return jsonResponse(200, { ok: true, launcherSessionId, access: { allowed: true, hubRole: "member", ownerScopes: [] }, user: { id: "device-member", email: "member@example.test", name: "Device Member", groups: ["nodedc:device-core:access"], }, }); }, }); await auth.handleHandoff( { method: "GET", headers: {} }, mockResponse(), new URL("https://device.example.test/auth/nodedc/handoff?token=handoff-secret"), ); assert.equal(calls[0].init.headers.Authorization, "Bearer scoped-file-token"); }); function productionEnv() { return { NODE_ENV: "production", NODEDC_DEVICE_MANAGER_AUTH_REQUIRED: "true", NODEDC_DEVICE_MANAGER_COOKIE_SECURE: "false", NODEDC_LAUNCHER_BASE_URL: "https://launcher.example.test", NODEDC_LAUNCHER_INTERNAL_URL: "http://launcher.internal.test", NODEDC_INTERNAL_ACCESS_TOKEN: internalToken, }; } function mockResponse() { const headers = new Map(); return { statusCode: 200, body: "", setHeader(name, value) { headers.set(String(name).toLowerCase(), value); }, getHeader(name) { return headers.get(String(name).toLowerCase()); }, end(body = "") { this.body = String(body); }, }; } function jsonResponse(status, body) { return new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" }, }); }