refactor(gateway)!: remove legacy v1 device-auth handshake

This commit is contained in:
Peter Steinberger
2026-02-22 09:26:49 +01:00
parent ed38b50fa5
commit 8887f41d7d
17 changed files with 404 additions and 210 deletions

View File

@@ -10,7 +10,13 @@ describe("ws connect policy", () => {
const bypass = resolveControlUiAuthPolicy({
isControlUi: true,
controlUiConfig: { dangerouslyDisableDeviceAuth: true },
deviceRaw: { id: "dev-1", publicKey: "pk", signature: "sig", signedAt: Date.now() },
deviceRaw: {
id: "dev-1",
publicKey: "pk",
signature: "sig",
signedAt: Date.now(),
nonce: "nonce-1",
},
});
expect(bypass.allowBypass).toBe(true);
expect(bypass.device).toBeNull();
@@ -18,7 +24,13 @@ describe("ws connect policy", () => {
const regular = resolveControlUiAuthPolicy({
isControlUi: false,
controlUiConfig: { dangerouslyDisableDeviceAuth: true },
deviceRaw: { id: "dev-2", publicKey: "pk", signature: "sig", signedAt: Date.now() },
deviceRaw: {
id: "dev-2",
publicKey: "pk",
signature: "sig",
signedAt: Date.now(),
nonce: "nonce-2",
},
});
expect(regular.allowBypass).toBe(false);
expect(regular.device?.id).toBe("dev-2");

View File

@@ -80,7 +80,7 @@ import {
type SubsystemLogger = ReturnType<typeof createSubsystemLogger>;
const DEVICE_SIGNATURE_SKEW_MS = 10 * 60 * 1000;
const DEVICE_SIGNATURE_SKEW_MS = 2 * 60 * 1000;
export function attachGatewayWsMessageHandler(params: {
socket: WebSocket;
@@ -528,13 +528,12 @@ export function attachGatewayWsMessageHandler(params: {
rejectDeviceAuthInvalid("device-signature-stale", "device signature expired");
return;
}
const nonceRequired = !isLocalClient;
const providedNonce = typeof device.nonce === "string" ? device.nonce.trim() : "";
if (nonceRequired && !providedNonce) {
if (!providedNonce) {
rejectDeviceAuthInvalid("device-nonce-missing", "device nonce required");
return;
}
if (providedNonce && providedNonce !== connectNonce) {
if (providedNonce !== connectNonce) {
rejectDeviceAuthInvalid("device-nonce-mismatch", "device nonce mismatch");
return;
}
@@ -546,31 +545,12 @@ export function attachGatewayWsMessageHandler(params: {
scopes,
signedAtMs: signedAt,
token: connectParams.auth?.token ?? null,
nonce: providedNonce || undefined,
version: providedNonce ? "v2" : "v1",
nonce: providedNonce,
});
const rejectDeviceSignatureInvalid = () =>
rejectDeviceAuthInvalid("device-signature", "device signature invalid");
const signatureOk = verifyDeviceSignature(device.publicKey, payload, device.signature);
const allowLegacy = !nonceRequired && !providedNonce;
if (!signatureOk && allowLegacy) {
const legacyPayload = buildDeviceAuthPayload({
deviceId: device.id,
clientId: connectParams.client.id,
clientMode: connectParams.client.mode,
role,
scopes,
signedAtMs: signedAt,
token: connectParams.auth?.token ?? null,
version: "v1",
});
if (verifyDeviceSignature(device.publicKey, legacyPayload, device.signature)) {
// accepted legacy loopback signature
} else {
rejectDeviceSignatureInvalid();
return;
}
} else if (!signatureOk) {
if (!signatureOk) {
rejectDeviceSignatureInvalid();
return;
}