mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 11:25:50 -06:00
7eec1345f9
* fix(gateway): preserve device auth upgrade recovery * fix(gateway): satisfy device auth upgrade gates * fix(doctor): clean disabled device auth bypass * fix(gateway): recheck migration operator boundary * fix(gateway): keep migration guard internal * fix(gateway): preserve insecure migration access * fix(gateway): reject stale migration handshakes * fix(gateway): revoke legacy migration sessions * fix(gateway): bound device-less migration authority * fix(gateway): require explicit migration pairing * fix(gateway): revoke alternate migration sessions * fix(gateway): close migration admission races * style(gateway): format migration pairing import * fix(security): audit pending device-auth migration * fix(gateway): reconcile migration on startup * fix(gateway): cap device auth migration scopes * fix(gateway): retain migration socket restrictions * perf(ui): trim migration startup bundle * perf(ui): lazy-load device auth migration * fix(gateway): bind migration completion to approved key * fix(gateway): preserve migration authorization bounds * fix(gateway): grant migrated device pairing capability * fix(ui): preserve device migration bundle budget * fix(ui): stabilize migration startup budget * chore(ui): retain startup budget headroom * fix(ui): split migration overlay helpers
75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
import type { GatewayBrowserClient } from "../api/gateway.ts";
|
|
import { t } from "../i18n/index.ts";
|
|
import type {
|
|
DeviceAuthMigrationController,
|
|
DeviceAuthMigrationSnapshot,
|
|
} from "./device-auth-migration.ts";
|
|
import type { ApplicationGateway } from "./gateway.ts";
|
|
|
|
export const EMPTY_DEVICE_AUTH_MIGRATION: DeviceAuthMigrationSnapshot = {
|
|
requestId: null,
|
|
busy: false,
|
|
error: null,
|
|
};
|
|
|
|
export function createDeviceAuthMigrationLoader(params: {
|
|
gateway: ApplicationGateway;
|
|
isCurrent: (client: GatewayBrowserClient, epoch: number) => boolean;
|
|
onChange: (snapshot: DeviceAuthMigrationSnapshot) => void;
|
|
}) {
|
|
let controllerPromise: Promise<DeviceAuthMigrationController | null> | null = null;
|
|
let disposed = false;
|
|
|
|
const reset = () => {
|
|
void controllerPromise?.then((controller) => controller?.reset());
|
|
params.onChange(EMPTY_DEVICE_AUTH_MIGRATION);
|
|
};
|
|
const load = (client: GatewayBrowserClient, epoch: number) => {
|
|
// This is a rare upgrade-only flow. Load it once when hello reports the
|
|
// pending transition so ordinary Control UI startup does not pay its cost.
|
|
controllerPromise ??= import("./device-auth-migration.ts")
|
|
.then(({ createDeviceAuthMigrationController }) => {
|
|
if (disposed) {
|
|
return null;
|
|
}
|
|
return createDeviceAuthMigrationController(params);
|
|
})
|
|
.catch((error: unknown) => {
|
|
controllerPromise = null;
|
|
if (params.isCurrent(client, epoch)) {
|
|
params.onChange({
|
|
...EMPTY_DEVICE_AUTH_MIGRATION,
|
|
error: t("login.deviceAuthMigration.loadFailed", {
|
|
error: error instanceof Error ? error.message : String(error),
|
|
}),
|
|
});
|
|
}
|
|
return null;
|
|
});
|
|
return controllerPromise;
|
|
};
|
|
|
|
return {
|
|
reset,
|
|
async refresh(client: GatewayBrowserClient, epoch: number) {
|
|
if (params.gateway.snapshot.hello?.deviceAuthMigration?.pending !== true) {
|
|
reset();
|
|
return;
|
|
}
|
|
const controller = await load(client, epoch);
|
|
if (!controller || !params.isCurrent(client, epoch)) {
|
|
controller?.reset();
|
|
return;
|
|
}
|
|
await controller.refresh(client, epoch);
|
|
},
|
|
async secure(client: GatewayBrowserClient | null, epoch: number) {
|
|
await (await controllerPromise)?.secure(client, epoch);
|
|
},
|
|
dispose() {
|
|
disposed = true;
|
|
void controllerPromise?.then((controller) => controller?.dispose());
|
|
},
|
|
};
|
|
}
|