You've already forked matrix-js-sdk
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:
@@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user