mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
Matrix: retry cross-signing after secret storage repair
This commit is contained in:
@@ -159,6 +159,55 @@ describe("MatrixCryptoBootstrapper", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("recreates secret storage and retries cross-signing when explicit bootstrap hits a stale server key", async () => {
|
||||
const deps = createBootstrapperDeps();
|
||||
const bootstrapCrossSigning = vi
|
||||
.fn<() => Promise<void>>()
|
||||
.mockRejectedValueOnce(new Error("getSecretStorageKey callback returned falsey"))
|
||||
.mockResolvedValueOnce(undefined);
|
||||
const crypto = createCryptoApi({
|
||||
bootstrapCrossSigning,
|
||||
isCrossSigningReady: vi.fn(async () => true),
|
||||
userHasCrossSigningKeys: vi.fn(async () => true),
|
||||
getDeviceVerificationStatus: vi.fn(async () => ({
|
||||
isVerified: () => true,
|
||||
localVerified: true,
|
||||
crossSigningVerified: true,
|
||||
signedByOwner: true,
|
||||
})),
|
||||
});
|
||||
const bootstrapper = new MatrixCryptoBootstrapper(
|
||||
deps as unknown as MatrixCryptoBootstrapperDeps<MatrixRawEvent>,
|
||||
);
|
||||
|
||||
await bootstrapper.bootstrap(crypto, {
|
||||
strict: true,
|
||||
allowSecretStorageRecreateWithoutRecoveryKey: true,
|
||||
allowAutomaticCrossSigningReset: false,
|
||||
});
|
||||
|
||||
expect(deps.recoveryKeyStore.bootstrapSecretStorageWithRecoveryKey).toHaveBeenCalledWith(
|
||||
crypto,
|
||||
{
|
||||
allowSecretStorageRecreateWithoutRecoveryKey: true,
|
||||
forceNewSecretStorage: true,
|
||||
},
|
||||
);
|
||||
expect(bootstrapCrossSigning).toHaveBeenCalledTimes(2);
|
||||
expect(bootstrapCrossSigning).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({
|
||||
authUploadDeviceSigningKeys: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
expect(bootstrapCrossSigning).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({
|
||||
authUploadDeviceSigningKeys: expect.any(Function),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("fails in strict mode when cross-signing keys are still unpublished", async () => {
|
||||
const deps = createBootstrapperDeps();
|
||||
const crypto = createCryptoApi({
|
||||
|
||||
@@ -58,6 +58,8 @@ export class MatrixCryptoBootstrapper<TRawEvent extends MatrixRawEvent> {
|
||||
const crossSigning = await this.bootstrapCrossSigning(crypto, {
|
||||
forceResetCrossSigning: options.forceResetCrossSigning === true,
|
||||
allowAutomaticCrossSigningReset: options.allowAutomaticCrossSigningReset !== false,
|
||||
allowSecretStorageRecreateWithoutRecoveryKey:
|
||||
options.allowSecretStorageRecreateWithoutRecoveryKey === true,
|
||||
strict,
|
||||
});
|
||||
await this.bootstrapSecretStorage(crypto, {
|
||||
@@ -105,6 +107,7 @@ export class MatrixCryptoBootstrapper<TRawEvent extends MatrixRawEvent> {
|
||||
options: {
|
||||
forceResetCrossSigning: boolean;
|
||||
allowAutomaticCrossSigningReset: boolean;
|
||||
allowSecretStorageRecreateWithoutRecoveryKey: boolean;
|
||||
strict: boolean;
|
||||
},
|
||||
): Promise<{ ready: boolean; published: boolean }> {
|
||||
@@ -171,30 +174,47 @@ export class MatrixCryptoBootstrapper<TRawEvent extends MatrixRawEvent> {
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} catch (err) {
|
||||
if (!options.allowAutomaticCrossSigningReset) {
|
||||
const shouldRepairSecretStorage =
|
||||
options.allowSecretStorageRecreateWithoutRecoveryKey &&
|
||||
err instanceof Error &&
|
||||
err.message.includes("getSecretStorageKey callback returned falsey");
|
||||
if (shouldRepairSecretStorage) {
|
||||
LogService.warn(
|
||||
"MatrixClientLite",
|
||||
"Cross-signing bootstrap could not access secret storage; recreating secret storage during explicit bootstrap and retrying.",
|
||||
);
|
||||
await this.deps.recoveryKeyStore.bootstrapSecretStorageWithRecoveryKey(crypto, {
|
||||
allowSecretStorageRecreateWithoutRecoveryKey: true,
|
||||
forceNewSecretStorage: true,
|
||||
});
|
||||
await crypto.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} else if (!options.allowAutomaticCrossSigningReset) {
|
||||
LogService.warn(
|
||||
"MatrixClientLite",
|
||||
"Initial cross-signing bootstrap failed and automatic reset is disabled:",
|
||||
err,
|
||||
);
|
||||
return { ready: false, published: false };
|
||||
}
|
||||
LogService.warn(
|
||||
"MatrixClientLite",
|
||||
"Initial cross-signing bootstrap failed, trying reset:",
|
||||
err,
|
||||
);
|
||||
try {
|
||||
await crypto.bootstrapCrossSigning({
|
||||
setupNewCrossSigning: true,
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} catch (resetErr) {
|
||||
LogService.warn("MatrixClientLite", "Failed to bootstrap cross-signing:", resetErr);
|
||||
if (options.strict) {
|
||||
throw resetErr instanceof Error ? resetErr : new Error(String(resetErr));
|
||||
} else {
|
||||
LogService.warn(
|
||||
"MatrixClientLite",
|
||||
"Initial cross-signing bootstrap failed, trying reset:",
|
||||
err,
|
||||
);
|
||||
try {
|
||||
await crypto.bootstrapCrossSigning({
|
||||
setupNewCrossSigning: true,
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} catch (resetErr) {
|
||||
LogService.warn("MatrixClientLite", "Failed to bootstrap cross-signing:", resetErr);
|
||||
if (options.strict) {
|
||||
throw resetErr instanceof Error ? resetErr : new Error(String(resetErr));
|
||||
}
|
||||
return { ready: false, published: false };
|
||||
}
|
||||
return { ready: false, published: false };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ export class MatrixRecoveryKeyStore {
|
||||
options: {
|
||||
setupNewKeyBackup?: boolean;
|
||||
allowSecretStorageRecreateWithoutRecoveryKey?: boolean;
|
||||
forceNewSecretStorage?: boolean;
|
||||
} = {},
|
||||
): Promise<void> {
|
||||
let status: MatrixSecretStorageStatus | null = null;
|
||||
@@ -185,6 +186,7 @@ export class MatrixRecoveryKeyStore {
|
||||
};
|
||||
|
||||
const shouldRecreateSecretStorage =
|
||||
options.forceNewSecretStorage === true ||
|
||||
!hasDefaultSecretStorageKey ||
|
||||
(!recoveryKey && status?.ready === false) ||
|
||||
hasKnownInvalidSecrets;
|
||||
|
||||
Reference in New Issue
Block a user