Skip to content

Commit c57c473

Browse files
authored
MatrixRTC: comply with the manageMediaKeys EncryptionConfig option (#4942)
* MatrixRTC: comply with the `manageMediaKeys` JoinConfig option * add additional test for reception * add comments about temporary solution
1 parent 812d0aa commit c57c473

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

spec/unit/matrixrtc/RTCEncryptionManager.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,23 @@ describe("RTCEncryptionManager", () => {
448448

449449
expect(statistics.counters.roomEventEncryptionKeysSent).toBe(2);
450450
});
451+
452+
it("Should not distribute keys if encryption is disabled", async () => {
453+
jest.useFakeTimers();
454+
const members = [
455+
aCallMembership("@bob:example.org", "BOBDEVICE"),
456+
aCallMembership("@bob:example.org", "BOBDEVICE2"),
457+
aCallMembership("@carl:example.org", "CARLDEVICE"),
458+
];
459+
getMembershipMock.mockReturnValue(members);
460+
461+
encryptionManager.join({ manageMediaKeys: false });
462+
encryptionManager.onMembershipsUpdate();
463+
await jest.runOnlyPendingTimersAsync();
464+
465+
expect(mockTransport.sendKey).not.toHaveBeenCalled();
466+
expect(onEncryptionKeysChanged).not.toHaveBeenCalled();
467+
});
451468
});
452469

453470
describe("Receiving Keys", () => {
@@ -471,6 +488,29 @@ describe("RTCEncryptionManager", () => {
471488
);
472489
});
473490

491+
it("should not accept keys when manageMediaKeys is disabled", async () => {
492+
jest.useFakeTimers();
493+
494+
const members = [aCallMembership("@bob:example.org", "BOBDEVICE")];
495+
getMembershipMock.mockReturnValue(members);
496+
497+
encryptionManager.join({ manageMediaKeys: false });
498+
encryptionManager.onMembershipsUpdate();
499+
await jest.advanceTimersByTimeAsync(10);
500+
501+
mockTransport.emit(
502+
KeyTransportEvents.ReceivedKeys,
503+
"@bob:example.org",
504+
"BOBDEVICE",
505+
"AAAAAAAAAAA",
506+
0 /* KeyId */,
507+
0 /* Timestamp */,
508+
);
509+
510+
expect(onEncryptionKeysChanged).not.toHaveBeenCalled();
511+
expect(statistics.counters.roomEventEncryptionKeysReceived).toBe(0);
512+
});
513+
474514
it("should accept keys from transport", async () => {
475515
jest.useFakeTimers();
476516

src/matrixrtc/RTCEncryptionManager.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ import {
4646
* XXX In the future we want to distribute a ratcheted key not the current one for new joiners.
4747
*/
4848
export class RTCEncryptionManager implements IEncryptionManager {
49+
// This is a stop-gap solution for now. The preferred way to handle this case would be instead
50+
// to create a NoOpEncryptionManager that does nothing and use it for the session.
51+
// This will be done when removing the legacy EncryptionManager.
52+
private manageMediaKeys = false;
53+
4954
/**
5055
* Store the key rings for each participant.
5156
* The encryption manager stores the keys because the application layer might not be ready yet to handle the keys.
@@ -126,6 +131,8 @@ export class RTCEncryptionManager implements IEncryptionManager {
126131
}
127132

128133
public join(joinConfig: EncryptionConfig | undefined): void {
134+
this.manageMediaKeys = joinConfig?.manageMediaKeys ?? true; // default to true
135+
129136
this.logger?.info(`Joining room`);
130137
this.useKeyDelay = joinConfig?.useKeyDelay ?? 1000;
131138
this.keyRotationGracePeriodMs = joinConfig?.keyRotationGracePeriodMs ?? 10_000;
@@ -174,6 +181,10 @@ export class RTCEncryptionManager implements IEncryptionManager {
174181
* the calls will be coalesced to a single new distribution (that will start just after the current one has completed).
175182
*/
176183
private ensureKeyDistribution(): void {
184+
// `manageMediaKeys` is a stop-gap solution for now. The preferred way to handle this case would be instead
185+
// to create a NoOpEncryptionManager that does nothing and use it for the session.
186+
// This will be done when removing the legacy EncryptionManager.
187+
if (!this.manageMediaKeys) return;
177188
if (this.currentKeyDistributionPromise == null) {
178189
this.logger?.debug(`No active rollout, start a new one`);
179190
// start a rollout
@@ -196,6 +207,15 @@ export class RTCEncryptionManager implements IEncryptionManager {
196207
}
197208

198209
public onNewKeyReceived: KeyTransportEventListener = (userId, deviceId, keyBase64Encoded, index, timestamp) => {
210+
// `manageMediaKeys` is a stop-gap solution for now. The preferred way to handle this case would be instead
211+
// to create a NoOpEncryptionManager that does nothing and use it for the session.
212+
// This will be done when removing the legacy EncryptionManager.
213+
if (!this.manageMediaKeys) {
214+
this.logger?.warn(
215+
`Received key over transport ${userId}:${deviceId} at index ${index} but media keys are disabled`,
216+
);
217+
return;
218+
}
199219
this.logger?.debug(`Received key over transport ${userId}:${deviceId} at index ${index}`);
200220

201221
// We received a new key, notify the video layer of this new key so that it can decrypt the frames properly.

0 commit comments

Comments
 (0)