diff --git a/spec/unit/rust-crypto/rust-crypto.spec.ts b/spec/unit/rust-crypto/rust-crypto.spec.ts index 7685f811d9b..ba1873b1f95 100644 --- a/spec/unit/rust-crypto/rust-crypto.spec.ts +++ b/spec/unit/rust-crypto/rust-crypto.spec.ts @@ -45,6 +45,7 @@ import { EventShieldReason, ImportRoomKeysOpts, KeyBackupCheck, + RoomKeySource, VerificationRequest, } from "../../../src/crypto-api"; import * as testData from "../../test-utils/test-data"; @@ -931,6 +932,51 @@ describe("RustCrypto", () => { await rustCrypto.onUserIdentityUpdated(new RustSdkCryptoJs.UserId(testData.TEST_USER_ID)); expect(await keyBackupStatusPromise).toBe(true); }); + + it("does not back up keys that came from backup", async () => { + const rustCrypto = await makeTestRustCrypto(); + + const olmMachine = rustCrypto.getOlmMachineOrThrow(); + + await olmMachine.enableBackupV1( + testData.SIGNED_BACKUP_DATA.auth_data.public_key, + testData.SIGNED_BACKUP_DATA.version, + ); + + // we import two keys: one "from backup", and one "from export" + const [backedUpRoomKey, exportedRoomKey, ..._] = testData.MEGOLM_SESSION_DATA_ARRAY; + await rustCrypto.importRoomKeys([backedUpRoomKey], { + source: RoomKeySource.Backup, + }); + await rustCrypto.importRoomKeys([exportedRoomKey]); + + // we ask for the keys that should be backed up + const roomKeysRequest = await olmMachine.backupRoomKeys(); + expect(roomKeysRequest).toBeTruthy(); + const roomKeys = JSON.parse(roomKeysRequest!.body); + + // we expect that the key "from export" is present + expect(roomKeys).toMatchObject({ + "rooms": { + [exportedRoomKey.room_id]: { + sessions: { + [exportedRoomKey.session_id]: {} + } + } + } + }); + + // we expect that the key "from backup" is not present + expect(roomKeys).not.toMatchObject({ + "rooms": { + [backedUpRoomKey.room_id]: { + sessions: { + [backedUpRoomKey.session_id]: {} + } + } + } + }); + }); }); }); diff --git a/src/client.ts b/src/client.ts index 5d436a1fcff..de3376c21af 100644 --- a/src/client.ts +++ b/src/client.ts @@ -211,7 +211,7 @@ import { LocalNotificationSettings } from "./@types/local_notifications"; import { buildFeatureSupportMap, Feature, ServerSupport } from "./feature"; import { CryptoBackend } from "./common-crypto/CryptoBackend"; import { RUST_SDK_STORE_PREFIX } from "./rust-crypto/constants"; -import { BootstrapCrossSigningOpts, CrossSigningKeyInfo, CryptoApi, ImportRoomKeysOpts } from "./crypto-api"; +import { BootstrapCrossSigningOpts, CrossSigningKeyInfo, CryptoApi, ImportRoomKeysOpts, RoomKeySource } from "./crypto-api"; import { DeviceInfoMap } from "./crypto/DeviceList"; import { AddSecretStorageKeyOpts, @@ -3974,7 +3974,7 @@ export class MatrixClient extends TypedEventEmitter void; // TODO, the rust SDK will always such imported keys as untrusted untrusted?: boolean; - source?: String; // TODO: Enum (backup, file, ??) + /** Where the room key came from */ + source?: RoomKeySource; } /** diff --git a/src/crypto/algorithms/megolm.ts b/src/crypto/algorithms/megolm.ts index 54d9d7fa33b..b665e25ca00 100644 --- a/src/crypto/algorithms/megolm.ts +++ b/src/crypto/algorithms/megolm.ts @@ -42,6 +42,7 @@ import { EventType, MsgType, ToDeviceMessageId } from "../../@types/event"; import { IMegolmEncryptedContent, IncomingRoomKeyRequest, IEncryptedContent } from "../index"; import { RoomKeyRequestState } from "../OutgoingRoomKeyRequestManager"; import { OlmGroupSessionExtraData } from "../../@types/crypto"; +import { RoomKeySource } from "../../crypto-api"; import { MatrixError } from "../../http-api"; import { immediate, MapWithDefault } from "../../utils"; @@ -2046,7 +2047,7 @@ export class MegolmDecryption extends DecryptionAlgorithm { extraSessionData, ) .then(() => { - if (source !== "backup") { + if (source !== RoomKeySource.Backup) { // don't wait for it to complete this.crypto.backupManager.backupGroupSession(session.sender_key, session.session_id).catch((e) => { // This throws if the upload failed, but this is fine diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index 3eeaf4cbc07..62f9cfc3df6 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -49,6 +49,7 @@ import { KeyBackupCheck, KeyBackupInfo, KeyBackupSession, + RoomKeySource, UserVerificationStatus, VerificationRequest, } from "../crypto-api"; @@ -223,7 +224,7 @@ export class RustCrypto extends TypedEventEmitter { // TODO when backup support will be added we would need to expose the `from_backup` flag in the bindings - const jsonKeys = JSON.stringify(keys); - await this.olmMachine.importRoomKeys(jsonKeys, (progress: BigInt, total: BigInt) => { + const callback = (progress: BigInt, total: BigInt) => { const importOpt: ImportRoomKeyProgressData = { total: Number(total), successes: Number(progress), @@ -399,7 +399,21 @@ export class RustCrypto extends TypedEventEmitter> = new Map(); + for (const key of keys) { + let room_id = new RustSdkCryptoJs.RoomId(key.room_id); + if (!keysByRoom.has(room_id)) { + keysByRoom.set(room_id, new Map()); + } + keysByRoom.get(room_id)!.set(key.session_id, key); + } + await this.olmMachine.importBackedUpRoomKeys(keysByRoom, callback); + } else { + const jsonKeys = JSON.stringify(keys); + await this.olmMachine.importExportedRoomKeys(jsonKeys, callback); + } } /**