fix: enforce ws3 roles + node allowlist

This commit is contained in:
Peter Steinberger
2026-01-20 09:23:56 +00:00
parent 32a668e4d9
commit 9dbc1435a6
27 changed files with 3096 additions and 40 deletions

View File

@@ -8,6 +8,11 @@ import { WebSocket } from "ws";
import { resolveMainSessionKeyFromConfig, type SessionEntry } from "../config/sessions.js";
import { resetAgentRunContextForTest } from "../infra/agent-events.js";
import {
loadOrCreateDeviceIdentity,
publicKeyRawBase64UrlFromPem,
signDevicePayload,
} from "../infra/device-identity.js";
import { drainSystemEvents, peekSystemEvents } from "../infra/system-events.js";
import { rawDataToString } from "../infra/ws.js";
import { resetLogger, setLoggerOverride } from "../logging.js";
@@ -16,6 +21,7 @@ import { getDeterministicFreePortBlock } from "../test-utils/ports.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { PROTOCOL_VERSION } from "./protocol/index.js";
import { buildDeviceAuthPayload } from "./device-auth.js";
import type { GatewayServerOptions } from "./server.js";
import {
agentCommand,
@@ -268,10 +274,44 @@ export async function connectReq(
caps?: string[];
commands?: string[];
permissions?: Record<string, boolean>;
device?: {
id: string;
publicKey: string;
signature: string;
signedAt: number;
};
},
): Promise<ConnectResponse> {
const { randomUUID } = await import("node:crypto");
const id = randomUUID();
const client = opts?.client ?? {
id: GATEWAY_CLIENT_NAMES.TEST,
version: "1.0.0",
platform: "test",
mode: GATEWAY_CLIENT_MODES.TEST,
};
const role = opts?.role ?? "operator";
const requestedScopes = Array.isArray(opts?.scopes) ? opts?.scopes : [];
const device = (() => {
if (opts?.device) return opts.device;
const identity = loadOrCreateDeviceIdentity();
const signedAtMs = Date.now();
const payload = buildDeviceAuthPayload({
deviceId: identity.deviceId,
clientId: client.id,
clientMode: client.mode,
role,
scopes: requestedScopes,
signedAtMs,
token: opts?.token ?? null,
});
return {
id: identity.deviceId,
publicKey: publicKeyRawBase64UrlFromPem(identity.publicKeyPem),
signature: signDevicePayload(identity.privateKeyPem, payload),
signedAt: signedAtMs,
};
})();
ws.send(
JSON.stringify({
type: "req",
@@ -280,16 +320,11 @@ export async function connectReq(
params: {
minProtocol: opts?.minProtocol ?? PROTOCOL_VERSION,
maxProtocol: opts?.maxProtocol ?? PROTOCOL_VERSION,
client: opts?.client ?? {
id: GATEWAY_CLIENT_NAMES.TEST,
version: "1.0.0",
platform: "test",
mode: GATEWAY_CLIENT_MODES.TEST,
},
client,
caps: opts?.caps ?? [],
commands: opts?.commands ?? [],
permissions: opts?.permissions ?? undefined,
role: opts?.role,
role,
scopes: opts?.scopes,
auth:
opts?.token || opts?.password
@@ -298,6 +333,7 @@ export async function connectReq(
password: opts?.password,
}
: undefined,
device,
},
}),
);