Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTCSession cleanup: deprecate getKeysForParticipant() and getEncryption(); add emitEncryptionKeys() #4427

Merged
merged 5 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
107 changes: 77 additions & 30 deletions spec/unit/matrixrtc/MatrixRTCSession.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,12 +585,15 @@

it("creates a key when joining", () => {
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
const keys = sess?.getKeysForParticipant("@alice:example.org", "AAAAAAA");
expect(keys).toHaveLength(1);

const allKeys = sess!.getEncryptionKeys();
expect(allKeys).toBeTruthy();
expect(Array.from(allKeys)).toHaveLength(1);
const encryptionKeyChangedListener = jest.fn();
sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess?.emitEncryptionKeys();

Check failure on line 590 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?

Check failure on line 590 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node lts/*)

MatrixRTCSession › joining › creates a key when joining

TypeError: _sess14.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:590:19)

Check failure on line 590 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node 22)

MatrixRTCSession › joining › creates a key when joining

TypeError: _sess14.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:590:19)
hughns marked this conversation as resolved.
Show resolved Hide resolved
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
expect.any(Uint8Array),
0,
"@alice:example.org:AAAAAAA",
);
});

it("sends keys when joining", async () => {
Expand Down Expand Up @@ -1197,9 +1200,16 @@
getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent);

const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!;
expect(bobKeys).toHaveLength(1);
expect(bobKeys[0]).toEqual(Buffer.from("this is the key", "utf-8"));
const encryptionKeyChangedListener = jest.fn();
sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess!.emitEncryptionKeys();

Check failure on line 1205 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?

Check failure on line 1205 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node lts/*)

MatrixRTCSession › collects keys from encryption events

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1205:15)

Check failure on line 1205 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node 22)

MatrixRTCSession › collects keys from encryption events

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1205:15)
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
Buffer.from("this is the key", "utf-8"),
0,
"@bob:example.org:bobsphone",
);

expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(1);
});

Expand All @@ -1222,13 +1232,16 @@
getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent);

const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!;
expect(bobKeys).toHaveLength(5);
expect(bobKeys[0]).toBeFalsy();
expect(bobKeys[1]).toBeFalsy();
expect(bobKeys[2]).toBeFalsy();
expect(bobKeys[3]).toBeFalsy();
expect(bobKeys[4]).toEqual(Buffer.from("this is the key", "utf-8"));
const encryptionKeyChangedListener = jest.fn();
sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess!.emitEncryptionKeys();

Check failure on line 1237 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?

Check failure on line 1237 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node lts/*)

MatrixRTCSession › collects keys at non-zero indices

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1237:15)

Check failure on line 1237 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node 22)

MatrixRTCSession › collects keys at non-zero indices

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1237:15)
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
Buffer.from("this is the key", "utf-8"),
4,
"@bob:example.org:bobsphone",
);

expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(1);
});

Expand All @@ -1251,9 +1264,16 @@
getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent);

let bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!;
expect(bobKeys).toHaveLength(1);
expect(bobKeys[0]).toEqual(Buffer.from("this is the key", "utf-8"));
const encryptionKeyChangedListener = jest.fn();
sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess!.emitEncryptionKeys();

Check failure on line 1269 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?

Check failure on line 1269 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node lts/*)

MatrixRTCSession › collects keys by merging

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1269:15)

Check failure on line 1269 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node 22)

MatrixRTCSession › collects keys by merging

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1269:15)
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
Buffer.from("this is the key", "utf-8"),
0,
"@bob:example.org:bobsphone",
);

expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(1);

sess.onCallEncryption({
Expand All @@ -1272,9 +1292,20 @@
getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent);

bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!;
expect(bobKeys).toHaveLength(5);
expect(bobKeys[4]).toEqual(Buffer.from("this is the key", "utf-8"));
encryptionKeyChangedListener.mockClear();
sess!.emitEncryptionKeys();

Check failure on line 1296 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(2);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
Buffer.from("this is the key", "utf-8"),
0,
"@bob:example.org:bobsphone",
);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
Buffer.from("this is the key", "utf-8"),
4,
"@bob:example.org:bobsphone",
);

expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(2);
});

Expand Down Expand Up @@ -1313,9 +1344,16 @@
getTs: jest.fn().mockReturnValue(1000), // earlier timestamp than the newer key
} as unknown as MatrixEvent);

const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!;
expect(bobKeys).toHaveLength(1);
expect(bobKeys[0]).toEqual(Buffer.from("newer key", "utf-8"));
const encryptionKeyChangedListener = jest.fn();
sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess!.emitEncryptionKeys();

Check failure on line 1349 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?

Check failure on line 1349 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node lts/*)

MatrixRTCSession › ignores older keys at same index

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1349:15)

Check failure on line 1349 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node 22)

MatrixRTCSession › ignores older keys at same index

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1349:15)
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
Buffer.from("newer key", "utf-8"),
0,
"@bob:example.org:bobsphone",
);

expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(2);
});

Expand Down Expand Up @@ -1354,9 +1392,15 @@
getTs: jest.fn().mockReturnValue(1000), // same timestamp as the first key
} as unknown as MatrixEvent);

const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!;
expect(bobKeys).toHaveLength(1);
expect(bobKeys[0]).toEqual(Buffer.from("second key", "utf-8"));
const encryptionKeyChangedListener = jest.fn();
sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess!.emitEncryptionKeys();

Check failure on line 1397 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?

Check failure on line 1397 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node lts/*)

MatrixRTCSession › key timestamps are treated as monotonic

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1397:15)

Check failure on line 1397 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node 22)

MatrixRTCSession › key timestamps are treated as monotonic

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1397:15)
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
Buffer.from("second key", "utf-8"),
0,
"@bob:example.org:bobsphone",
);
});

it("ignores keys event for the local participant", () => {
Expand All @@ -1378,8 +1422,11 @@
getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent);

const myKeys = sess.getKeysForParticipant(client.getUserId()!, client.getDeviceId()!)!;
expect(myKeys).toBeFalsy();
const encryptionKeyChangedListener = jest.fn();
sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess!.emitEncryptionKeys();

Check failure on line 1427 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Typescript Syntax Check

Property 'emitEncryptionKeys' does not exist on type 'MatrixRTCSession'. Did you mean 'reemitEncryptionKeys'?

Check failure on line 1427 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node lts/*)

MatrixRTCSession › ignores keys event for the local participant

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1427:15)

Check failure on line 1427 in spec/unit/matrixrtc/MatrixRTCSession.spec.ts

View workflow job for this annotation

GitHub Actions / Jest [unit] (Node 22)

MatrixRTCSession › ignores keys event for the local participant

TypeError: sess.emitEncryptionKeys is not a function at Object.emitEncryptionKeys (spec/unit/matrixrtc/MatrixRTCSession.spec.ts:1427:15)
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(0);

expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(0);
});

Expand Down
22 changes: 21 additions & 1 deletion src/matrixrtc/MatrixRTCSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,20 +405,40 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
}
}

/**
* Re-emit EncryptionKeyChanged events for every tracked encryption keys. This can be used to export
hughns marked this conversation as resolved.
Show resolved Hide resolved
* the keys.
*/
public reemitEncryptionKeys(): void {
this.encryptionKeys.forEach((keys, participantId) => {
keys.forEach((key, index) => {
this.emit(MatrixRTCSessionEvent.EncryptionKeyChanged, key.key, index, participantId);
});
});
}

/**
* Get the known encryption keys for a given participant device.
*
* @param userId the user ID of the participant
* @param deviceId the device ID of the participant
* @returns The encryption keys for the given participant, or undefined if they are not known.
*
* @deprecated This will be made private in a future release.
*/
public getKeysForParticipant(userId: string, deviceId: string): Array<Uint8Array> | undefined {
return this.getKeysForParticipantInternal(userId, deviceId);
}

private getKeysForParticipantInternal(userId: string, deviceId: string): Array<Uint8Array> | undefined {
return this.encryptionKeys.get(getParticipantId(userId, deviceId))?.map((entry) => entry.key);
}

/**
* A map of keys used to encrypt and decrypt (we are using a symmetric
* cipher) given participant's media. This also includes our own key
*
* @deprecated This will be made private in a future release.
*/
public getEncryptionKeys(): IterableIterator<[string, Array<Uint8Array>]> {
// the returned array doesn't contain the timestamps
Expand All @@ -434,7 +454,7 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
if (!userId) throw new Error("No userId!");
if (!deviceId) throw new Error("No deviceId!");

return (this.getKeysForParticipant(userId, deviceId)?.length ?? 0) % 16;
return (this.getKeysForParticipantInternal(userId, deviceId)?.length ?? 0) % 16;
}

/**
Expand Down
Loading