Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 72 additions & 38 deletions spec/unit/matrixrtc/ToDeviceKeyTransport.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

import { type Mocked } from "vitest";

import { makeMockEvent } from "./mocks.ts";
import { makeMatrixEvent } from "./mocks.ts";
import { ClientEvent, EventType, type MatrixClient } from "../../../src";
import { ToDeviceKeyTransport } from "../../../src/matrixrtc/ToDeviceKeyTransport.ts";
import { getMockClientWithEventEmitter } from "../../test-utils/client.ts";
Expand Down Expand Up @@ -122,24 +122,23 @@ describe("ToDeviceKeyTransport", () => {
const testEncoded = "ABCDEDF";
const testKeyIndex = 2;

mockClient.emit(
ClientEvent.ToDeviceEvent,
makeMockEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", undefined, {
keys: {
index: testKeyIndex,
key: testEncoded,
},
member: {
claimed_device_id: "BOBDEVICE",
},
room_id: roomId,
session: {
application: "m.call",
call_id: "",
scope: "m.room",
},
}),
);
const mockEvent = makeMatrixEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", undefined, {
keys: {
index: testKeyIndex,
key: testEncoded,
},
member: {
claimed_device_id: "BOBDEVICE",
},
room_id: roomId,
session: {
application: "m.call",
call_id: "",
scope: "m.room",
},
});
mockEvent.makeEncrypted(EventType.RoomMessageEncrypted, {}, "", "");
mockClient.emit(ClientEvent.ToDeviceEvent, mockEvent);

const { userId, deviceId, keyBase64Encoded, index } = await receivedKeyResolvers.promise;
expect(userId).toBe("@bob:example.org");
Expand All @@ -150,6 +149,41 @@ describe("ToDeviceKeyTransport", () => {
expect(statistics.counters.roomEventEncryptionKeysReceived).toBe(1);
});

it("should drop non-encrypted/clear to-device events", () => {
const receivedKeyResolvers = vi.fn();
transport.on(KeyTransportEvents.ReceivedKeys, (membership, keyBase64Encoded, index, _timestamp) => {
receivedKeyResolvers();
});
transport.start();

const testEncoded = "ABCDEDF";
const testKeyIndex = 2;

const clearEvent = makeMatrixEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", undefined, {
keys: {
index: testKeyIndex,
key: testEncoded,
},
member: {
claimed_device_id: "BOBDEVICE",
},
room_id: roomId,
session: {
application: "m.call",
call_id: "",
scope: "m.room",
},
});
mockClient.emit(ClientEvent.ToDeviceEvent, clearEvent);

expect(receivedKeyResolvers).toHaveBeenCalledTimes(0);

clearEvent.makeEncrypted(EventType.RoomMessageEncrypted, {}, "", "");
mockClient.emit(ClientEvent.ToDeviceEvent, clearEvent);

expect(receivedKeyResolvers).toHaveBeenCalledTimes(1);
});

it("should not sent to ourself", async () => {
const keyBase64Encoded = "ABCDEDF";
const keyIndex = 2;
Expand All @@ -168,24 +202,24 @@ describe("ToDeviceKeyTransport", () => {
const testEncoded = "ABCDEDF";
const testKeyIndex = 2;

mockClient.emit(
ClientEvent.ToDeviceEvent,
makeMockEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", undefined, {
keys: {
index: testKeyIndex,
key: testEncoded,
},
member: {
claimed_device_id: "BOBDEVICE",
},
room_id: "!anotherroom:id",
session: {
application: "m.call",
call_id: "",
scope: "m.room",
},
}),
);
const keyEvent = makeMatrixEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", undefined, {
keys: {
index: testKeyIndex,
key: testEncoded,
},
member: {
claimed_device_id: "BOBDEVICE",
},
room_id: "!anotherroom:id",
session: {
application: "m.call",
call_id: "",
scope: "m.room",
},
});

keyEvent.makeEncrypted(EventType.RoomMessageEncrypted, {}, "", "");
mockClient.emit(ClientEvent.ToDeviceEvent, keyEvent);

expect(mockLogger.warn).toHaveBeenCalledWith("Malformed Event: Mismatch roomId");
expect(statistics.counters.roomEventEncryptionKeysReceived).toBe(0);
Expand Down Expand Up @@ -240,7 +274,7 @@ describe("ToDeviceKeyTransport", () => {

mockClient.emit(
ClientEvent.ToDeviceEvent,
makeMockEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", undefined, event),
makeMatrixEvent(EventType.CallEncryptionKeysPrefix, "@bob:example.org", undefined, event),
);

expect(mockLogger.warn).toHaveBeenCalled();
Expand Down
21 changes: 20 additions & 1 deletion spec/unit/matrixrtc/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
import { EventEmitter } from "node:stream";
import { type Mocked, type MockedObject } from "vitest";

import { EventType, type Room, RoomEvent, type MatrixClient, type MatrixEvent } from "../../../src";
import { EventType, type Room, RoomEvent, type MatrixClient, MatrixEvent } from "../../../src";
import { CallMembership } from "../../../src/matrixrtc";
import { secureRandomString } from "../../../src/randomstring";
import { type RtcMembershipData, type SessionMembershipData } from "../../../src/matrixrtc/membershipData";
Expand Down Expand Up @@ -108,6 +108,7 @@ export type MockClient = MockedObject<
| "cancelPendingEvent"
>
>;

/**
* Mocks a object that has all required methods for a MatrixRTC session client.
*/
Expand Down Expand Up @@ -232,6 +233,24 @@ export function makeMockEvent(
} as unknown as MatrixEvent;
}

export function makeMatrixEvent(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance this can replace all usages of the above makeMockEvent?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is breaking existing tests, didn't want this PR to touch other things.

type: string,
sender: string,
roomId: string | undefined,
content: any,
timestamp?: number,
stateKey?: string,
): MatrixEvent {
return new MatrixEvent({
type,
sender,
room_id: roomId,
content,
state_key: stateKey,
origin_server_ts: timestamp,
});
}

export function mockRTCEvent(
{ user_id: sender, ...membershipData }: MembershipData,
roomId: string,
Expand Down
14 changes: 7 additions & 7 deletions src/matrixrtc/ToDeviceKeyTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ export class ToDeviceKeyTransport
return;
}

// TODO: Not possible to check if the event is encrypted or not
// see https://github.com/matrix-org/matrix-rust-sdk/issues/4883
// if (evnt.getWireType() != EventType.RoomMessageEncrypted) {
// // WARN: The call keys were sent in clear. Ignore them
// logger.warn(`Call encryption keys sent in clear from: ${event.getSender()}`);
// return;
// }
// NB: When received via the widget driver, the to-device events
// are properly reconstructed as if they are encrypted (see MatrixEvent#makeEncrypted).
if (event.getWireType() != EventType.RoomMessageEncrypted) {
// WARN: The call keys were sent in clear. Ignore them
this.logger.warn(`Call encryption keys sent in clear from: ${event.getSender()}`);
return;
}

const content = this.getValidEventContent(event);
if (!content) return;
Expand Down