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 keyBackupIsCached = emitPromise(aliceClient, CryptoEvent.KeyBackupDecryptionKeyCached);
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..
jest.useRealTimers();
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
jest.useFakeTimers();
await keyBackupIsCached;
// the backup secret should be cached
const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();

View File

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

View File

@@ -232,6 +232,18 @@ export enum CryptoEvent {
KeyBackupStatus = "crypto.keyBackupStatus",
KeyBackupFailed = "crypto.keyBackupFailed",
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",
/** @deprecated Use `VerificationRequestReceived`. */
VerificationRequest = "crypto.verification.request",
@@ -297,6 +309,13 @@ export type CryptoEventHandlerMap = {
[CryptoEvent.KeyBackupStatus]: (enabled: boolean) => void;
[CryptoEvent.KeyBackupFailed]: (errcode: string) => 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]: (
failures: IUploadKeySignaturesResponse["failures"],
source: "checkOwnCrossSigningTrust" | "afterCrossSigningLocalKeyChange" | "setDeviceVerification",

View File

@@ -154,8 +154,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
logger.info(
`handleBackupSecretReceived: A valid backup decryption key has been received and stored in cache.`,
);
await this.olmMachine.saveBackupDecryptionKey(backupDecryptionKey, backupCheck.backupInfo.version);
await this.saveBackupDecryptionKey(backupDecryptionKey, backupCheck.backupInfo.version);
return true;
} catch (e) {
logger.warn("handleBackupSecretReceived: Invalid backup decryption key", e);
@@ -164,6 +163,16 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
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;
/** 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 {
version: res.version,
@@ -503,10 +512,12 @@ export class RustBackupDecryptor implements BackupDecryptor {
export type RustBackupCryptoEvents =
| CryptoEvent.KeyBackupStatus
| CryptoEvent.KeyBackupSessionsRemaining
| CryptoEvent.KeyBackupFailed;
| CryptoEvent.KeyBackupFailed
| CryptoEvent.KeyBackupDecryptionKeyCached;
export type RustBackupCryptoEventMap = {
[CryptoEvent.KeyBackupStatus]: (enabled: boolean) => void;
[CryptoEvent.KeyBackupSessionsRemaining]: (remaining: number) => 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.KeyBackupSessionsRemaining,
CryptoEvent.KeyBackupFailed,
CryptoEvent.KeyBackupDecryptionKeyCached,
]);
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");
}
await this.olmMachine.saveBackupDecryptionKey(
await this.backupManager.saveBackupDecryptionKey(
RustSdkCryptoJs.BackupDecryptionKey.fromBase64(base64Key),
version,
);
@@ -1867,4 +1868,6 @@ type RustCryptoEventMap = {
* Fires when the trust status of a user changes.
*/
[CryptoEvent.UserTrustStatusChanged]: (userId: string, userTrustLevel: UserVerificationStatus) => void;
[CryptoEvent.KeyBackupDecryptionKeyCached]: (version: string) => void;
} & RustBackupCryptoEventMap;