You've already forked matrix-js-sdk
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:
@@ -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();
|
||||||
|
|||||||
@@ -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,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user