fix(gateway): clarify pairing and node auth guidance

This commit is contained in:
Peter Steinberger
2026-02-22 19:50:29 +01:00
parent 53ed7a0f5c
commit 0c1f491a02
16 changed files with 202 additions and 22 deletions

View File

@@ -17,6 +17,8 @@ type HandshakeConnectAuth = {
password?: string;
};
export type DeviceTokenCandidateSource = "explicit-device-token" | "shared-token-fallback";
export type ConnectAuthState = {
authResult: GatewayAuthResult;
authOk: boolean;
@@ -24,6 +26,7 @@ export type ConnectAuthState = {
sharedAuthOk: boolean;
sharedAuthProvided: boolean;
deviceTokenCandidate?: string;
deviceTokenCandidateSource?: DeviceTokenCandidateSource;
};
function trimToUndefined(value: string | undefined): string | undefined {
@@ -45,14 +48,19 @@ function resolveSharedConnectAuth(
return { token, password };
}
function resolveDeviceTokenCandidate(
connectAuth: HandshakeConnectAuth | null | undefined,
): string | undefined {
function resolveDeviceTokenCandidate(connectAuth: HandshakeConnectAuth | null | undefined): {
token?: string;
source?: DeviceTokenCandidateSource;
} {
const explicitDeviceToken = trimToUndefined(connectAuth?.deviceToken);
if (explicitDeviceToken) {
return explicitDeviceToken;
return { token: explicitDeviceToken, source: "explicit-device-token" };
}
return trimToUndefined(connectAuth?.token);
const fallbackToken = trimToUndefined(connectAuth?.token);
if (!fallbackToken) {
return {};
}
return { token: fallbackToken, source: "shared-token-fallback" };
}
export async function resolveConnectAuthState(params: {
@@ -67,9 +75,8 @@ export async function resolveConnectAuthState(params: {
}): Promise<ConnectAuthState> {
const sharedConnectAuth = resolveSharedConnectAuth(params.connectAuth);
const sharedAuthProvided = Boolean(sharedConnectAuth);
const deviceTokenCandidate = params.hasDeviceIdentity
? resolveDeviceTokenCandidate(params.connectAuth)
: undefined;
const { token: deviceTokenCandidate, source: deviceTokenCandidateSource } =
params.hasDeviceIdentity ? resolveDeviceTokenCandidate(params.connectAuth) : {};
const hasDeviceTokenCandidate = Boolean(deviceTokenCandidate);
let authResult: GatewayAuthResult = await authorizeWsControlUiGatewayConnect({
@@ -129,5 +136,6 @@ export async function resolveConnectAuthState(params: {
sharedAuthOk,
sharedAuthProvided,
deviceTokenCandidate,
deviceTokenCandidateSource,
};
}

View File

@@ -355,17 +355,23 @@ export function attachGatewayWsMessageHandler(params: {
});
const device = controlUiAuthPolicy.device;
let { authResult, authOk, authMethod, sharedAuthOk, deviceTokenCandidate } =
await resolveConnectAuthState({
resolvedAuth,
connectAuth: connectParams.auth,
hasDeviceIdentity: Boolean(device),
req: upgradeReq,
trustedProxies,
allowRealIpFallback,
rateLimiter,
clientIp,
});
let {
authResult,
authOk,
authMethod,
sharedAuthOk,
deviceTokenCandidate,
deviceTokenCandidateSource,
} = await resolveConnectAuthState({
resolvedAuth,
connectAuth: connectParams.auth,
hasDeviceIdentity: Boolean(device),
req: upgradeReq,
trustedProxies,
allowRealIpFallback,
rateLimiter,
clientIp,
});
const rejectUnauthorized = (failedAuth: GatewayAuthResult) => {
markHandshakeFailure("unauthorized", {
authMode: resolvedAuth.mode,
@@ -532,7 +538,11 @@ export function attachGatewayWsMessageHandler(params: {
authMethod = "device-token";
rateLimiter?.reset(clientIp, AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN);
} else {
authResult = { ok: false, reason: "device_token_mismatch" };
const mismatchReason =
deviceTokenCandidateSource === "explicit-device-token"
? "device_token_mismatch"
: (authResult.reason ?? "device_token_mismatch");
authResult = { ok: false, reason: mismatchReason };
rateLimiter?.recordFailure(clientIp, AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN);
}
}