1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-23 17:02:25 +03:00

Signal key backup in cache (#3928)

* Signal key backup in cache

* code review

* quick doc

* code review
This commit is contained in:
Valere
2023-11-30 09:15:37 +01:00
committed by GitHub
parent 48d9d9b4c9
commit 2e98da4224
5 changed files with 43 additions and 11 deletions

View File

@@ -1259,14 +1259,11 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
const requestId = await requestPromises.get("m.megolm_backup.v1"); const requestId = await requestPromises.get("m.megolm_backup.v1");
const keyBackupIsCached = emitPromise(aliceClient, CryptoEvent.KeyBackupDecryptionKeyCached);
await sendBackupGossipAndExpectVersion(requestId!, BACKUP_DECRYPTION_KEY_BASE64, matchingBackupInfo); await sendBackupGossipAndExpectVersion(requestId!, BACKUP_DECRYPTION_KEY_BASE64, matchingBackupInfo);
// We are lacking a way to signal that the secret has been received, so we wait a bit.. await keyBackupIsCached;
jest.useRealTimers();
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
jest.useFakeTimers();
// the backup secret should be cached // the backup secret should be cached
const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey(); const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();

View File

@@ -951,6 +951,7 @@ type CryptoEvents =
| CryptoEvent.KeyBackupStatus | CryptoEvent.KeyBackupStatus
| CryptoEvent.KeyBackupFailed | CryptoEvent.KeyBackupFailed
| CryptoEvent.KeyBackupSessionsRemaining | CryptoEvent.KeyBackupSessionsRemaining
| CryptoEvent.KeyBackupDecryptionKeyCached
| CryptoEvent.RoomKeyRequest | CryptoEvent.RoomKeyRequest
| CryptoEvent.RoomKeyRequestCancellation | CryptoEvent.RoomKeyRequestCancellation
| CryptoEvent.VerificationRequest | CryptoEvent.VerificationRequest
@@ -2359,6 +2360,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
CryptoEvent.KeyBackupStatus, CryptoEvent.KeyBackupStatus,
CryptoEvent.KeyBackupSessionsRemaining, CryptoEvent.KeyBackupSessionsRemaining,
CryptoEvent.KeyBackupFailed, CryptoEvent.KeyBackupFailed,
CryptoEvent.KeyBackupDecryptionKeyCached,
]); ]);
} }

View File

@@ -232,6 +232,18 @@ export enum CryptoEvent {
KeyBackupStatus = "crypto.keyBackupStatus", KeyBackupStatus = "crypto.keyBackupStatus",
KeyBackupFailed = "crypto.keyBackupFailed", KeyBackupFailed = "crypto.keyBackupFailed",
KeyBackupSessionsRemaining = "crypto.keyBackupSessionsRemaining", KeyBackupSessionsRemaining = "crypto.keyBackupSessionsRemaining",
/**
* Fires when a new valid backup decryption key is in cache.
* This will happen when a secret is received from another session, from secret storage,
* or when a new backup is created from this session.
*
* The payload is the version of the backup for which we have the key for.
*
* This event is only fired by the rust crypto backend.
*/
KeyBackupDecryptionKeyCached = "crypto.keyBackupDecryptionKeyCached",
KeySignatureUploadFailure = "crypto.keySignatureUploadFailure", KeySignatureUploadFailure = "crypto.keySignatureUploadFailure",
/** @deprecated Use `VerificationRequestReceived`. */ /** @deprecated Use `VerificationRequestReceived`. */
VerificationRequest = "crypto.verification.request", VerificationRequest = "crypto.verification.request",
@@ -297,6 +309,13 @@ export type CryptoEventHandlerMap = {
[CryptoEvent.KeyBackupStatus]: (enabled: boolean) => void; [CryptoEvent.KeyBackupStatus]: (enabled: boolean) => void;
[CryptoEvent.KeyBackupFailed]: (errcode: string) => void; [CryptoEvent.KeyBackupFailed]: (errcode: string) => void;
[CryptoEvent.KeyBackupSessionsRemaining]: (remaining: number) => void; [CryptoEvent.KeyBackupSessionsRemaining]: (remaining: number) => void;
/**
* Fires when the backup decryption key is received and cached.
*
* @param version - The version of the backup for which we have the key for.
*/
[CryptoEvent.KeyBackupDecryptionKeyCached]: (version: string) => void;
[CryptoEvent.KeySignatureUploadFailure]: ( [CryptoEvent.KeySignatureUploadFailure]: (
failures: IUploadKeySignaturesResponse["failures"], failures: IUploadKeySignaturesResponse["failures"],
source: "checkOwnCrossSigningTrust" | "afterCrossSigningLocalKeyChange" | "setDeviceVerification", source: "checkOwnCrossSigningTrust" | "afterCrossSigningLocalKeyChange" | "setDeviceVerification",

View File

@@ -154,8 +154,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
logger.info( logger.info(
`handleBackupSecretReceived: A valid backup decryption key has been received and stored in cache.`, `handleBackupSecretReceived: A valid backup decryption key has been received and stored in cache.`,
); );
await this.saveBackupDecryptionKey(backupDecryptionKey, backupCheck.backupInfo.version);
await this.olmMachine.saveBackupDecryptionKey(backupDecryptionKey, backupCheck.backupInfo.version);
return true; return true;
} catch (e) { } catch (e) {
logger.warn("handleBackupSecretReceived: Invalid backup decryption key", e); logger.warn("handleBackupSecretReceived: Invalid backup decryption key", e);
@@ -164,6 +163,16 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
return false; return false;
} }
public async saveBackupDecryptionKey(
backupDecryptionKey: RustSdkCryptoJs.BackupDecryptionKey,
version: string,
): Promise<void> {
await this.olmMachine.saveBackupDecryptionKey(backupDecryptionKey, version);
// Emit an event that we have a new backup decryption key, so that the sdk can start
// importing keys from backup if needed.
this.emit(CryptoEvent.KeyBackupDecryptionKeyCached, version);
}
private keyBackupCheckInProgress: Promise<KeyBackupCheck | null> | null = null; private keyBackupCheckInProgress: Promise<KeyBackupCheck | null> | null = null;
/** Helper for `checkKeyBackup` */ /** Helper for `checkKeyBackup` */
@@ -393,7 +402,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
}, },
); );
this.olmMachine.saveBackupDecryptionKey(randomKey, res.version); await this.saveBackupDecryptionKey(randomKey, res.version);
return { return {
version: res.version, version: res.version,
@@ -503,10 +512,12 @@ export class RustBackupDecryptor implements BackupDecryptor {
export type RustBackupCryptoEvents = export type RustBackupCryptoEvents =
| CryptoEvent.KeyBackupStatus | CryptoEvent.KeyBackupStatus
| CryptoEvent.KeyBackupSessionsRemaining | CryptoEvent.KeyBackupSessionsRemaining
| CryptoEvent.KeyBackupFailed; | CryptoEvent.KeyBackupFailed
| CryptoEvent.KeyBackupDecryptionKeyCached;
export type RustBackupCryptoEventMap = { export type RustBackupCryptoEventMap = {
[CryptoEvent.KeyBackupStatus]: (enabled: boolean) => void; [CryptoEvent.KeyBackupStatus]: (enabled: boolean) => void;
[CryptoEvent.KeyBackupSessionsRemaining]: (remaining: number) => void; [CryptoEvent.KeyBackupSessionsRemaining]: (remaining: number) => void;
[CryptoEvent.KeyBackupFailed]: (errCode: string) => void; [CryptoEvent.KeyBackupFailed]: (errCode: string) => void;
[CryptoEvent.KeyBackupDecryptionKeyCached]: (version: string) => void;
}; };

View File

@@ -150,6 +150,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
CryptoEvent.KeyBackupStatus, CryptoEvent.KeyBackupStatus,
CryptoEvent.KeyBackupSessionsRemaining, CryptoEvent.KeyBackupSessionsRemaining,
CryptoEvent.KeyBackupFailed, CryptoEvent.KeyBackupFailed,
CryptoEvent.KeyBackupDecryptionKeyCached,
]); ]);
this.crossSigningIdentity = new CrossSigningIdentity(olmMachine, this.outgoingRequestProcessor, secretStorage); this.crossSigningIdentity = new CrossSigningIdentity(olmMachine, this.outgoingRequestProcessor, secretStorage);
@@ -1148,7 +1149,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
throw new Error("storeSessionBackupPrivateKey: version is required"); throw new Error("storeSessionBackupPrivateKey: version is required");
} }
await this.olmMachine.saveBackupDecryptionKey( await this.backupManager.saveBackupDecryptionKey(
RustSdkCryptoJs.BackupDecryptionKey.fromBase64(base64Key), RustSdkCryptoJs.BackupDecryptionKey.fromBase64(base64Key),
version, version,
); );
@@ -1867,4 +1868,6 @@ type RustCryptoEventMap = {
* Fires when the trust status of a user changes. * Fires when the trust status of a user changes.
*/ */
[CryptoEvent.UserTrustStatusChanged]: (userId: string, userTrustLevel: UserVerificationStatus) => void; [CryptoEvent.UserTrustStatusChanged]: (userId: string, userTrustLevel: UserVerificationStatus) => void;
[CryptoEvent.KeyBackupDecryptionKeyCached]: (version: string) => void;
} & RustBackupCryptoEventMap; } & RustBackupCryptoEventMap;