feat(device-manager): add standalone project workspace
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
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,
|
||||
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: "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,
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
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" },
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user