Skip to content

Commit e5c8c20

Browse files
authored
MatrixRTC: Refactor | Introduce a new Encryption manager (used with experimental to device transport) (#4799)
* refactor: New encryption manager BasicEncryptionManager for todevice fixup: bad do not commit * fix: ToDevice transport not setting the sent_ts * test: BasicEncryptionManager add statistics tests * code review * feat: Encryption manager just reshare on new joiner * refactor: Rename BasicEncryptionManger to RTCEncryptionManager * fixup: RTC experimental todevice should use new encryption mgr * fixup: use proper logger hierarchy * fixup: RTC rollout first key asap even if no members to send to * fixup: RTC add test for first key use * fixup! emitting outbound key before anyone registered * fix: quick patch for transport switch, need test * test: RTC encryption manager, add test for transport switch * post rebase fix * Remove bad corepack commit * review: cleaning, renaming * review: cleaning and renaming * stop using root logger in favor of a parent logger * post merge fix broken test * remove corepack again * fix reverted changes after a merge * review: Properly deprecate getEncryptionKeys * review: rename ensureMediaKeyDistribution to ensureKeyDistribution * review: use OutdatedKeyFilter instead of KeyBuffer
1 parent 137379b commit e5c8c20

14 files changed

+1165
-65
lines changed

spec/unit/matrixrtc/MatrixRTCSession.spec.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { MatrixRTCSession, MatrixRTCSessionEvent } from "../../../src/matrixrtc/
2121
import { type EncryptionKeysEventContent } from "../../../src/matrixrtc/types";
2222
import { secureRandomString } from "../../../src/randomstring";
2323
import { makeMockEvent, makeMockRoom, makeMockRoomState, membershipTemplate, makeKey } from "./mocks";
24+
import { RTCEncryptionManager } from "../../../src/matrixrtc/RTCEncryptionManager.ts";
2425

2526
const mockFocus = { type: "mock" };
2627

@@ -745,11 +746,27 @@ describe("MatrixRTCSession", () => {
745746
expect(sendKeySpy).toHaveBeenCalledTimes(1);
746747
// check that we send the key with index 1 even though the send gets delayed when leaving.
747748
// this makes sure we do not use an index that is one too old.
748-
expect(sendKeySpy).toHaveBeenLastCalledWith(expect.any(String), 1, sess.memberships);
749+
expect(sendKeySpy).toHaveBeenLastCalledWith(
750+
expect.any(String),
751+
1,
752+
sess.memberships.map((m) => ({
753+
userId: m.sender,
754+
deviceId: m.deviceId,
755+
membershipTs: m.createdTs(),
756+
})),
757+
);
749758
// fake a condition in which we send another encryption key event.
750759
// this could happen do to someone joining the call.
751760
(sess as unknown as any).encryptionManager.sendEncryptionKeysEvent();
752-
expect(sendKeySpy).toHaveBeenLastCalledWith(expect.any(String), 1, sess.memberships);
761+
expect(sendKeySpy).toHaveBeenLastCalledWith(
762+
expect.any(String),
763+
1,
764+
sess.memberships.map((m) => ({
765+
userId: m.sender,
766+
deviceId: m.deviceId,
767+
membershipTs: m.createdTs(),
768+
})),
769+
);
753770
jest.advanceTimersByTime(7000);
754771

755772
const secondKeysPayload = await keysSentPromise2;
@@ -862,10 +879,14 @@ describe("MatrixRTCSession", () => {
862879
manageMediaKeys: true,
863880
useExperimentalToDeviceTransport: true,
864881
});
882+
sess.onRTCSessionMemberUpdate();
865883

866884
await keySentPromise;
867885

868886
expect(sendToDeviceMock).toHaveBeenCalled();
887+
888+
// Access private to test
889+
expect(sess["encryptionManager"]).toBeInstanceOf(RTCEncryptionManager);
869890
} finally {
870891
jest.useRealTimers();
871892
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright 2025 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { OutdatedKeyFilter } from "../../../src/matrixrtc/utils.ts";
18+
import { type InboundEncryptionSession } from "../../../src/matrixrtc";
19+
20+
describe("OutdatedKeyFilter Test", () => {
21+
it("Should buffer and disambiguate keys by timestamp", () => {
22+
const filter = new OutdatedKeyFilter();
23+
24+
const aKey = fakeInboundSessionWithTimestamp(1000);
25+
const olderKey = fakeInboundSessionWithTimestamp(300);
26+
// Simulate receiving out of order keys
27+
28+
expect(filter.isOutdated(aKey.participantId, aKey)).toBe(false);
29+
// Then we receive the most recent key out of order
30+
const isOutdated = filter.isOutdated(aKey.participantId, olderKey);
31+
// this key is older and should be ignored even if received after
32+
expect(isOutdated).toBe(true);
33+
});
34+
35+
function fakeInboundSessionWithTimestamp(ts: number): InboundEncryptionSession {
36+
return {
37+
keyIndex: 0,
38+
creationTS: ts,
39+
participantId: "@alice:localhost|ABCDE",
40+
key: new Uint8Array(16),
41+
};
42+
}
43+
});

0 commit comments

Comments
 (0)