From ce7b7bf44f4c1b539d93c1fdeffaeb5ba2c5422c Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 26 Oct 2023 15:57:37 +0200 Subject: [PATCH] Element-R: Wire up `globalBlacklistUnverifiedDevices` field to rust crypto encryption settings (#3790) * Wire up `globalBlacklistUnverifiedDevices` rust crypto encrypted settings * Improve test comment * Update comments * Review changes * Fix lint due to merge --- spec/integ/crypto/crypto.spec.ts | 34 ++++++++++++++++++++++++++++++++ src/rust-crypto/RoomEncryptor.ts | 18 +++++++++++++---- src/rust-crypto/rust-crypto.ts | 4 ++-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/spec/integ/crypto/crypto.spec.ts b/spec/integ/crypto/crypto.spec.ts index 2c5be4657..0cd01000b 100644 --- a/spec/integ/crypto/crypto.spec.ts +++ b/spec/integ/crypto/crypto.spec.ts @@ -95,6 +95,7 @@ import { establishOlmSession, getTestOlmAccountKeys, } from "./olm-utils"; +import { ToDevicePayload } from "../../../src/models/ToDeviceMessage"; afterEach(() => { // reset fake-indexeddb after each test, to make sure we don't leak connections @@ -943,6 +944,39 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, aliceClient.sendTextMessage(ROOM_ID, "test"), ]); }); + + it("should send a m.unverified code in toDevice messages to an unverified device when globalBlacklistUnverifiedDevices=true", async () => { + aliceClient.getCrypto()!.globalBlacklistUnverifiedDevices = true; + + expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); + await startClientAndAwaitFirstSync(); + await establishOlmSession(aliceClient, keyReceiver, syncResponder, testOlmAccount); + + // Tell alice we share a room with bob + syncResponder.sendOrQueueSyncResponse(getSyncResponse(["@bob:xyz"])); + await syncPromise(aliceClient); + + // Force alice to download bob keys + expectAliceKeyQuery(getTestKeysQueryResponse("@bob:xyz")); + + // Wait to receive the toDevice message and return bob device content + const toDevicePromise = new Promise((resolve) => { + fetchMock.putOnce(new RegExp("/sendToDevice/m.room_key.withheld/"), (url, request) => { + const content = JSON.parse(request.body as string); + resolve(content.messages["@bob:xyz"]["DEVICE_ID"]); + return {}; + }); + }); + + // Mock endpoint of message sending + fetchMock.put(new RegExp("/send/"), { event_id: "$event_id" }); + + await aliceClient.sendTextMessage(ROOM_ID, "test"); + + // Finally, check that the toDevice message has the m.unverified code + const toDeviceContent = await toDevicePromise; + expect(toDeviceContent.code).toBe("m.unverified"); + }); }); describe("Session should rotate according to encryption settings", () => { diff --git a/src/rust-crypto/RoomEncryptor.ts b/src/rust-crypto/RoomEncryptor.ts index 0e4d1a2dd..c384a9335 100644 --- a/src/rust-crypto/RoomEncryptor.ts +++ b/src/rust-crypto/RoomEncryptor.ts @@ -21,6 +21,7 @@ import { RoomId, UserId, HistoryVisibility as RustHistoryVisibility, + ToDeviceRequest, } from "@matrix-org/matrix-sdk-crypto-wasm"; import { EventType } from "../@types/event"; @@ -43,6 +44,7 @@ export class RoomEncryptor { /** * @param olmMachine - The rust-sdk's OlmMachine * @param keyClaimManager - Our KeyClaimManager, which manages the queue of one-time-key claim requests + * @param outgoingRequestProcessor - The OutgoingRequestProcessor, which sends outgoing requests * @param room - The room we want to encrypt for * @param encryptionSettings - body of the m.room.encryption event currently in force in this room */ @@ -91,8 +93,10 @@ export class RoomEncryptor { * * This ensures that we have a megolm session ready to use and that we have shared its key with all the devices * in the room. + * + * @param globalBlacklistUnverifiedDevices - When `true`, it will not send encrypted messages to unverified devices */ - public async ensureEncryptionSession(): Promise { + public async ensureEncryptionSession(globalBlacklistUnverifiedDevices: boolean): Promise { if (this.encryptionSettings.algorithm !== "m.megolm.v1.aes-sha2") { throw new Error( `Cannot encrypt in ${this.room.roomId} for unsupported algorithm '${this.encryptionSettings.algorithm}'`, @@ -127,7 +131,12 @@ export class RoomEncryptor { rustEncryptionSettings.rotationPeriodMessages = BigInt(this.encryptionSettings.rotation_period_msgs); } - const shareMessages = await this.olmMachine.shareRoomKey( + // When this.room.getBlacklistUnverifiedDevices() === null, the global settings should be used + // See Room#getBlacklistUnverifiedDevices + rustEncryptionSettings.onlyAllowTrustedDevices = + this.room.getBlacklistUnverifiedDevices() ?? globalBlacklistUnverifiedDevices; + + const shareMessages: ToDeviceRequest[] = await this.olmMachine.shareRoomKey( new RoomId(this.room.roomId), userList, rustEncryptionSettings, @@ -156,9 +165,10 @@ export class RoomEncryptor { * then encrypt the event using the session. * * @param event - Event to be encrypted. + * @param globalBlacklistUnverifiedDevices - When `true`, it will not send encrypted messages to unverified devices */ - public async encryptEvent(event: MatrixEvent): Promise { - await this.ensureEncryptionSession(); + public async encryptEvent(event: MatrixEvent, globalBlacklistUnverifiedDevices: boolean): Promise { + await this.ensureEncryptionSession(globalBlacklistUnverifiedDevices); const encryptedContent = await this.olmMachine.encryptRoomEvent( new RoomId(this.room.roomId), diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index d02bd4004..7a9383906 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -282,7 +282,7 @@ export class RustCrypto extends TypedEventEmitter { @@ -376,7 +376,7 @@ export class RustCrypto extends TypedEventEmitter