1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-07 23:02:56 +03:00

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

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

* Clarify comment

* Feedback from code review

* Update src/matrixrtc/MatrixRTCSession.ts

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>

* Fix test

---------

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>
This commit is contained in:
Hugh Nimmo-Smith
2024-09-27 16:55:07 +01:00
committed by GitHub
parent 2d6230f199
commit baa6d13506
2 changed files with 98 additions and 31 deletions

View File

@@ -585,12 +585,15 @@ describe("MatrixRTCSession", () => {
it("creates a key when joining", () => { it("creates a key when joining", () => {
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true }); sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
const keys = sess?.getKeysForParticipant("@alice:example.org", "AAAAAAA"); const encryptionKeyChangedListener = jest.fn();
expect(keys).toHaveLength(1); sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess?.reemitEncryptionKeys();
const allKeys = sess!.getEncryptionKeys(); expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(allKeys).toBeTruthy(); expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
expect(Array.from(allKeys)).toHaveLength(1); expect.any(Uint8Array),
0,
"@alice:example.org:AAAAAAA",
);
}); });
it("sends keys when joining", async () => { it("sends keys when joining", async () => {
@@ -1204,9 +1207,16 @@ describe("MatrixRTCSession", () => {
getTs: jest.fn().mockReturnValue(Date.now()), getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent); } as unknown as MatrixEvent);
const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; const encryptionKeyChangedListener = jest.fn();
expect(bobKeys).toHaveLength(1); sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
expect(bobKeys[0]).toEqual(Buffer.from("this is the key", "utf-8")); sess!.reemitEncryptionKeys();
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); expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(1);
}); });
@@ -1229,13 +1239,16 @@ describe("MatrixRTCSession", () => {
getTs: jest.fn().mockReturnValue(Date.now()), getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent); } as unknown as MatrixEvent);
const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; const encryptionKeyChangedListener = jest.fn();
expect(bobKeys).toHaveLength(5); sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
expect(bobKeys[0]).toBeFalsy(); sess!.reemitEncryptionKeys();
expect(bobKeys[1]).toBeFalsy(); expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(1);
expect(bobKeys[2]).toBeFalsy(); expect(encryptionKeyChangedListener).toHaveBeenCalledWith(
expect(bobKeys[3]).toBeFalsy(); Buffer.from("this is the key", "utf-8"),
expect(bobKeys[4]).toEqual(Buffer.from("this is the key", "utf-8")); 4,
"@bob:example.org:bobsphone",
);
expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(1); expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(1);
}); });
@@ -1258,9 +1271,16 @@ describe("MatrixRTCSession", () => {
getTs: jest.fn().mockReturnValue(Date.now()), getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent); } as unknown as MatrixEvent);
let bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; const encryptionKeyChangedListener = jest.fn();
expect(bobKeys).toHaveLength(1); sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
expect(bobKeys[0]).toEqual(Buffer.from("this is the key", "utf-8")); sess!.reemitEncryptionKeys();
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); expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(1);
sess.onCallEncryption({ sess.onCallEncryption({
@@ -1279,9 +1299,20 @@ describe("MatrixRTCSession", () => {
getTs: jest.fn().mockReturnValue(Date.now()), getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent); } as unknown as MatrixEvent);
bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; encryptionKeyChangedListener.mockClear();
expect(bobKeys).toHaveLength(5); sess!.reemitEncryptionKeys();
expect(bobKeys[4]).toEqual(Buffer.from("this is the key", "utf-8")); 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); expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(2);
}); });
@@ -1320,9 +1351,16 @@ describe("MatrixRTCSession", () => {
getTs: jest.fn().mockReturnValue(1000), // earlier timestamp than the newer key getTs: jest.fn().mockReturnValue(1000), // earlier timestamp than the newer key
} as unknown as MatrixEvent); } as unknown as MatrixEvent);
const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; const encryptionKeyChangedListener = jest.fn();
expect(bobKeys).toHaveLength(1); sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
expect(bobKeys[0]).toEqual(Buffer.from("newer key", "utf-8")); sess!.reemitEncryptionKeys();
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); expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(2);
}); });
@@ -1361,9 +1399,15 @@ describe("MatrixRTCSession", () => {
getTs: jest.fn().mockReturnValue(1000), // same timestamp as the first key getTs: jest.fn().mockReturnValue(1000), // same timestamp as the first key
} as unknown as MatrixEvent); } as unknown as MatrixEvent);
const bobKeys = sess.getKeysForParticipant("@bob:example.org", "bobsphone")!; const encryptionKeyChangedListener = jest.fn();
expect(bobKeys).toHaveLength(1); sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
expect(bobKeys[0]).toEqual(Buffer.from("second key", "utf-8")); sess!.reemitEncryptionKeys();
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", () => { it("ignores keys event for the local participant", () => {
@@ -1385,8 +1429,11 @@ describe("MatrixRTCSession", () => {
getTs: jest.fn().mockReturnValue(Date.now()), getTs: jest.fn().mockReturnValue(Date.now()),
} as unknown as MatrixEvent); } as unknown as MatrixEvent);
const myKeys = sess.getKeysForParticipant(client.getUserId()!, client.getDeviceId()!)!; const encryptionKeyChangedListener = jest.fn();
expect(myKeys).toBeFalsy(); sess!.on(MatrixRTCSessionEvent.EncryptionKeyChanged, encryptionKeyChangedListener);
sess!.reemitEncryptionKeys();
expect(encryptionKeyChangedListener).toHaveBeenCalledTimes(0);
expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(0); expect(sess!.statistics.counters.roomEventEncryptionKeysReceived).toEqual(0);
}); });

View File

@@ -405,20 +405,40 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
} }
} }
/**
* Re-emit an EncryptionKeyChanged event for each tracked encryption key. This can be used to export
* 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. * Get the known encryption keys for a given participant device.
* *
* @param userId the user ID of the participant * @param userId the user ID of the participant
* @param deviceId the device 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. * @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 { 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); 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 * 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 * 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>]> { public getEncryptionKeys(): IterableIterator<[string, Array<Uint8Array>]> {
// the returned array doesn't contain the timestamps // the returned array doesn't contain the timestamps
@@ -434,7 +454,7 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
if (!userId) throw new Error("No userId!"); if (!userId) throw new Error("No userId!");
if (!deviceId) throw new Error("No deviceId!"); if (!deviceId) throw new Error("No deviceId!");
return (this.getKeysForParticipant(userId, deviceId)?.length ?? 0) % 16; return (this.getKeysForParticipantInternal(userId, deviceId)?.length ?? 0) % 16;
} }
/** /**