You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Element-R: Wire up room rotation (#3807)
* Wire up rotation * Wire up algorithm * Add encryption settings test * Update comments
This commit is contained in:
@ -157,7 +157,7 @@ async function expectSendRoomKey(
|
|||||||
/**
|
/**
|
||||||
* Return the event received on rooms/{roomId}/send/m.room.encrypted endpoint.
|
* Return the event received on rooms/{roomId}/send/m.room.encrypted endpoint.
|
||||||
* See https://spec.matrix.org/latest/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid
|
* See https://spec.matrix.org/latest/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid
|
||||||
* @returns the content of event (no decryption)
|
* @returns the content of the encrypted event
|
||||||
*/
|
*/
|
||||||
function expectEncryptedSendMessage() {
|
function expectEncryptedSendMessage() {
|
||||||
return new Promise<IContent>((resolve) => {
|
return new Promise<IContent>((resolve) => {
|
||||||
@ -938,6 +938,122 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string,
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Session should rotate according to encryption settings", () => {
|
||||||
|
/**
|
||||||
|
* Send a message to bob and get the encrypted message
|
||||||
|
* @returns {Promise<IContent>} The encrypted message
|
||||||
|
*/
|
||||||
|
async function sendEncryptedMessage(): Promise<IContent> {
|
||||||
|
const [encryptedMessage] = await Promise.all([
|
||||||
|
expectEncryptedSendMessage(),
|
||||||
|
aliceClient.sendTextMessage(ROOM_ID, "test"),
|
||||||
|
]);
|
||||||
|
return encryptedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
newBackendOnly("should rotate the session after 2 messages", async () => {
|
||||||
|
expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} });
|
||||||
|
await startClientAndAwaitFirstSync();
|
||||||
|
const p2pSession = await establishOlmSession(aliceClient, keyReceiver, syncResponder, testOlmAccount);
|
||||||
|
|
||||||
|
const syncResponse = getSyncResponse(["@bob:xyz"]);
|
||||||
|
// Every 2 messages in the room, the session should be rotated
|
||||||
|
syncResponse.rooms[Category.Join][ROOM_ID].state.events[0].content = {
|
||||||
|
algorithm: "m.megolm.v1.aes-sha2",
|
||||||
|
rotation_period_msgs: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tell alice we share a room with bob
|
||||||
|
syncResponder.sendOrQueueSyncResponse(syncResponse);
|
||||||
|
await syncPromise(aliceClient);
|
||||||
|
|
||||||
|
// Force alice to download bob keys
|
||||||
|
expectAliceKeyQuery(getTestKeysQueryResponse("@bob:xyz"));
|
||||||
|
|
||||||
|
// Send a message to bob and get the encrypted message
|
||||||
|
const [encryptedMessage] = await Promise.all([
|
||||||
|
sendEncryptedMessage(),
|
||||||
|
expectSendRoomKey("@bob:xyz", testOlmAccount, p2pSession),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Check that the session id exists
|
||||||
|
const sessionId = encryptedMessage.session_id;
|
||||||
|
expect(sessionId).toBeDefined();
|
||||||
|
|
||||||
|
// Send a second message to bob and get the current message
|
||||||
|
const secondEncryptedMessage = await sendEncryptedMessage();
|
||||||
|
|
||||||
|
// Check that the same session id is shared between the two messages
|
||||||
|
const secondSessionId = secondEncryptedMessage.session_id;
|
||||||
|
expect(secondSessionId).toBe(sessionId);
|
||||||
|
|
||||||
|
// The session should be rotated, we are expecting the room key to be sent
|
||||||
|
const [thirdEncryptedMessage] = await Promise.all([
|
||||||
|
sendEncryptedMessage(),
|
||||||
|
expectSendRoomKey("@bob:xyz", testOlmAccount, p2pSession),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// The session is rotated every 2 messages, we should have a new session id
|
||||||
|
const thirdSessionId = thirdEncryptedMessage.session_id;
|
||||||
|
expect(thirdSessionId).not.toBe(sessionId);
|
||||||
|
});
|
||||||
|
|
||||||
|
newBackendOnly("should rotate the session after 1h", async () => {
|
||||||
|
expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} });
|
||||||
|
await startClientAndAwaitFirstSync();
|
||||||
|
const p2pSession = await establishOlmSession(aliceClient, keyReceiver, syncResponder, testOlmAccount);
|
||||||
|
|
||||||
|
// We need to fake the timers to advance the time
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
|
const syncResponse = getSyncResponse(["@bob:xyz"]);
|
||||||
|
|
||||||
|
// The minimum rotation period is 1h
|
||||||
|
// https://github.com/matrix-org/matrix-rust-sdk/blob/f75b2cd1d0981db42751dadb08c826740af1018e/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs#L410-L415
|
||||||
|
const oneHourInMs = 60 * 60 * 1000;
|
||||||
|
|
||||||
|
// Every 1h the session should be rotated
|
||||||
|
syncResponse.rooms[Category.Join][ROOM_ID].state.events[0].content = {
|
||||||
|
algorithm: "m.megolm.v1.aes-sha2",
|
||||||
|
rotation_period_ms: oneHourInMs,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tell alice we share a room with bob
|
||||||
|
syncResponder.sendOrQueueSyncResponse(syncResponse);
|
||||||
|
await syncPromise(aliceClient);
|
||||||
|
|
||||||
|
// Force alice to download bob keys
|
||||||
|
expectAliceKeyQuery(getTestKeysQueryResponse("@bob:xyz"));
|
||||||
|
|
||||||
|
// Send a message to bob and get the encrypted message
|
||||||
|
const [encryptedMessage] = await Promise.all([
|
||||||
|
sendEncryptedMessage(),
|
||||||
|
expectSendRoomKey("@bob:xyz", testOlmAccount, p2pSession),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Check that the session id exists
|
||||||
|
const sessionId = encryptedMessage.session_id;
|
||||||
|
expect(sessionId).toBeDefined();
|
||||||
|
|
||||||
|
// Advance the time by 1h
|
||||||
|
jest.advanceTimersByTime(oneHourInMs);
|
||||||
|
|
||||||
|
// Send a second message to bob and get the encrypted message
|
||||||
|
const [secondEncryptedMessage] = await Promise.all([
|
||||||
|
sendEncryptedMessage(),
|
||||||
|
expectSendRoomKey("@bob:xyz", testOlmAccount, p2pSession),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// The session should be rotated
|
||||||
|
const secondSessionId = secondEncryptedMessage.session_id;
|
||||||
|
expect(secondSessionId).not.toBe(sessionId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
newBackendOnly("should rotate the session when the history visibility changes", async () => {
|
newBackendOnly("should rotate the session when the history visibility changes", async () => {
|
||||||
expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} });
|
expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} });
|
||||||
await startClientAndAwaitFirstSync();
|
await startClientAndAwaitFirstSync();
|
||||||
|
@ -15,6 +15,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
EncryptionAlgorithm,
|
||||||
EncryptionSettings,
|
EncryptionSettings,
|
||||||
OlmMachine,
|
OlmMachine,
|
||||||
RoomId,
|
RoomId,
|
||||||
@ -110,10 +111,22 @@ export class RoomEncryptor {
|
|||||||
this.prefixedLogger.debug("Sessions for users are ready; now sharing room key");
|
this.prefixedLogger.debug("Sessions for users are ready; now sharing room key");
|
||||||
|
|
||||||
const rustEncryptionSettings = new EncryptionSettings();
|
const rustEncryptionSettings = new EncryptionSettings();
|
||||||
/* FIXME rotation, etc */
|
|
||||||
|
|
||||||
rustEncryptionSettings.historyVisibility = toRustHistoryVisibility(this.room.getHistoryVisibility());
|
rustEncryptionSettings.historyVisibility = toRustHistoryVisibility(this.room.getHistoryVisibility());
|
||||||
|
|
||||||
|
// We only support megolm
|
||||||
|
rustEncryptionSettings.algorithm = EncryptionAlgorithm.MegolmV1AesSha2;
|
||||||
|
|
||||||
|
// We need to convert the rotation period from milliseconds to microseconds
|
||||||
|
// See https://spec.matrix.org/v1.8/client-server-api/#mroomencryption and
|
||||||
|
// https://matrix-org.github.io/matrix-rust-sdk-crypto-wasm/classes/EncryptionSettings.html#rotationPeriod
|
||||||
|
if (typeof this.encryptionSettings.rotation_period_ms === "number") {
|
||||||
|
rustEncryptionSettings.rotationPeriod = BigInt(this.encryptionSettings.rotation_period_ms * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.encryptionSettings.rotation_period_msgs === "number") {
|
||||||
|
rustEncryptionSettings.rotationPeriodMessages = BigInt(this.encryptionSettings.rotation_period_msgs);
|
||||||
|
}
|
||||||
|
|
||||||
const shareMessages = await this.olmMachine.shareRoomKey(
|
const shareMessages = await this.olmMachine.shareRoomKey(
|
||||||
new RoomId(this.room.roomId),
|
new RoomId(this.room.roomId),
|
||||||
userList,
|
userList,
|
||||||
|
Reference in New Issue
Block a user