mirror of https://github.com/openclaw/openclaw.git
fix(gateway): trust bootstrap-paired backend handshakes
This commit is contained in:
parent
bb738058e6
commit
ecbbc3f8ff
|
|
@ -5,6 +5,7 @@ import {
|
|||
evaluateMissingDeviceIdentity,
|
||||
isTrustedProxyControlUiOperatorAuth,
|
||||
resolveControlUiAuthPolicy,
|
||||
resolveInternalBackendClientAttestation,
|
||||
shouldSkipBackendSelfPairing,
|
||||
shouldSkipControlUiPairing,
|
||||
} from "./connect-policy.js";
|
||||
|
|
@ -643,4 +644,56 @@ describe("ws connect policy", () => {
|
|||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("promotes bootstrap-paired backend clients to internal attestation", () => {
|
||||
const backendConnect: ConnectParams = {
|
||||
client: {
|
||||
id: GATEWAY_CLIENT_IDS.GATEWAY_CLIENT,
|
||||
mode: GATEWAY_CLIENT_MODES.BACKEND,
|
||||
version: "1.0.0",
|
||||
platform: "node",
|
||||
},
|
||||
minProtocol: 1,
|
||||
maxProtocol: 1,
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveInternalBackendClientAttestation({
|
||||
connectParams: backendConnect,
|
||||
hasBrowserOriginHeader: false,
|
||||
initialIsInternalBackendClient: false,
|
||||
authMethod: "bootstrap-token",
|
||||
deviceTokenIssued: true,
|
||||
}),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
resolveInternalBackendClientAttestation({
|
||||
connectParams: backendConnect,
|
||||
hasBrowserOriginHeader: true,
|
||||
initialIsInternalBackendClient: false,
|
||||
authMethod: "bootstrap-token",
|
||||
deviceTokenIssued: true,
|
||||
}),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
resolveInternalBackendClientAttestation({
|
||||
connectParams: {
|
||||
client: {
|
||||
id: "desktop",
|
||||
mode: GATEWAY_CLIENT_MODES.TEST,
|
||||
version: "1.0.0",
|
||||
platform: "node",
|
||||
},
|
||||
minProtocol: 1,
|
||||
maxProtocol: 1,
|
||||
},
|
||||
hasBrowserOriginHeader: false,
|
||||
initialIsInternalBackendClient: false,
|
||||
authMethod: "bootstrap-token",
|
||||
deviceTokenIssued: true,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -113,6 +113,25 @@ export function shouldSkipBackendSelfPairing(params: {
|
|||
);
|
||||
}
|
||||
|
||||
export function resolveInternalBackendClientAttestation(params: {
|
||||
connectParams: ConnectParams;
|
||||
hasBrowserOriginHeader: boolean;
|
||||
initialIsInternalBackendClient: boolean;
|
||||
authMethod: GatewayAuthResult["method"];
|
||||
deviceTokenIssued: boolean;
|
||||
}): boolean {
|
||||
if (params.initialIsInternalBackendClient) {
|
||||
return true;
|
||||
}
|
||||
const isGatewayBackendClient =
|
||||
params.connectParams.client.id === GATEWAY_CLIENT_IDS.GATEWAY_CLIENT &&
|
||||
params.connectParams.client.mode === GATEWAY_CLIENT_MODES.BACKEND;
|
||||
if (!isGatewayBackendClient || params.hasBrowserOriginHeader) {
|
||||
return false;
|
||||
}
|
||||
return params.authMethod === "bootstrap-token" && params.deviceTokenIssued;
|
||||
}
|
||||
|
||||
export type MissingDeviceIdentityDecision =
|
||||
| { kind: "allow" }
|
||||
| { kind: "reject-control-ui-insecure-auth" }
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ import {
|
|||
evaluateMissingDeviceIdentity,
|
||||
isTrustedProxyControlUiOperatorAuth,
|
||||
resolveControlUiAuthPolicy,
|
||||
resolveInternalBackendClientAttestation,
|
||||
shouldSkipBackendSelfPairing,
|
||||
shouldSkipControlUiPairing,
|
||||
} from "./connect-policy.js";
|
||||
|
|
@ -891,6 +892,13 @@ export function attachGatewayWsMessageHandler(params: {
|
|||
const deviceToken = device
|
||||
? await ensureDeviceToken({ deviceId: device.id, role, scopes })
|
||||
: null;
|
||||
const attestedInternalBackendClient = resolveInternalBackendClientAttestation({
|
||||
connectParams,
|
||||
hasBrowserOriginHeader,
|
||||
initialIsInternalBackendClient: isInternalBackendClient,
|
||||
authMethod,
|
||||
deviceTokenIssued: deviceToken !== null,
|
||||
});
|
||||
|
||||
if (role === "node") {
|
||||
const cfg = loadConfig();
|
||||
|
|
@ -995,7 +1003,7 @@ export function attachGatewayWsMessageHandler(params: {
|
|||
canvasHostUrl,
|
||||
canvasCapability,
|
||||
canvasCapabilityExpiresAtMs,
|
||||
isInternalBackendClient,
|
||||
isInternalBackendClient: attestedInternalBackendClient,
|
||||
};
|
||||
setSocketMaxPayload(socket, MAX_PAYLOAD_BYTES);
|
||||
setClient(nextClient);
|
||||
|
|
|
|||
Loading…
Reference in New Issue