From 62445340cb9b9f7562e6e56e9eb70c5473860591 Mon Sep 17 00:00:00 2001
From: Timo
Date: Tue, 15 Apr 2025 18:23:23 +0200
Subject: [PATCH] developer settings for ratcheting
---
src/e2ee/matrixKeyProvider.ts | 20 ++++++++++++++++++--
src/livekit/useLiveKit.ts | 11 ++++++++++-
src/room/InCallView.tsx | 6 +++++-
src/settings/DeveloperSettingsTab.tsx | 16 ++++++++++++++--
src/settings/SettingsModal.tsx | 10 +++++++++-
5 files changed, 56 insertions(+), 7 deletions(-)
diff --git a/src/e2ee/matrixKeyProvider.ts b/src/e2ee/matrixKeyProvider.ts
index 6ee3615c..43b5abca 100644
--- a/src/e2ee/matrixKeyProvider.ts
+++ b/src/e2ee/matrixKeyProvider.ts
@@ -5,7 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
-import { BaseKeyProvider, createKeyMaterialFromBuffer } from "livekit-client";
+import {
+ BaseKeyProvider,
+ createKeyMaterialFromBuffer,
+ KeyProviderEvent,
+} from "livekit-client";
import { logger } from "matrix-js-sdk/lib/logger";
import {
type MatrixRTCSession,
@@ -16,7 +20,11 @@ export class MatrixKeyProvider extends BaseKeyProvider {
private rtcSession?: MatrixRTCSession;
public constructor() {
- super({ ratchetWindowSize: 100, keyringSize: 256 });
+ // ratchetWindowSize the amount of ratchets we try consecutively before
+ // throwing an error log. After those attempts we will still try more retry batches.
+ // So there can be more than 10 ratchets in total.
+ super({ ratchetWindowSize: 10, keyringSize: 256 });
+ this.on(KeyProviderEvent.KeyRatcheted, this.onKeyRatcheted);
}
public setRTCSession(rtcSession: MatrixRTCSession): void {
@@ -60,4 +68,12 @@ export class MatrixKeyProvider extends BaseKeyProvider {
},
);
};
+
+ public onKeyRatcheted = (material: CryptoKey, keyIndex?: number): void => {
+ logger.debug(
+ `Key ratcheted event received for livekit room=${this.rtcSession?.room.roomId} keyIndex=${keyIndex}`,
+ `material:`,
+ material,
+ );
+ };
}
diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts
index da180ab8..833735f2 100644
--- a/src/livekit/useLiveKit.ts
+++ b/src/livekit/useLiveKit.ts
@@ -13,7 +13,7 @@ import {
type RoomOptions,
Track,
} from "livekit-client";
-import { useEffect, useMemo, useRef } from "react";
+import { useCallback, useEffect, useMemo, useRef } from "react";
import E2EEWorker from "livekit-client/e2ee-worker?worker";
import { logger } from "matrix-js-sdk/lib/logger";
import { type MatrixRTCSession } from "matrix-js-sdk/lib/matrixrtc";
@@ -37,6 +37,7 @@ import { type EncryptionSystem } from "../e2ee/sharedKeyManagement";
interface UseLivekitResult {
livekitRoom?: Room;
connState: ECConnectionState;
+ doKeyRatchet: () => void;
}
export function useLiveKit(
@@ -331,8 +332,16 @@ export function useLiveKit(
}
}, [room, devices, connectionState]);
+ const doKeyRatchet = useCallback(() => {
+ // not providing a key index will default to the current key
+ e2eeOptions?.keyProvider.ratchetKey(
+ room.localParticipant.identity,
+ undefined,
+ );
+ }, [e2eeOptions?.keyProvider, room.localParticipant.identity]);
return {
connState: connectionState,
livekitRoom: room,
+ doKeyRatchet,
};
}
diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx
index b434a1da..3fb3ad3b 100644
--- a/src/room/InCallView.tsx
+++ b/src/room/InCallView.tsx
@@ -114,7 +114,7 @@ export interface ActiveCallProps
export const ActiveCall: FC = (props) => {
const sfuConfig = useOpenIDSFU(props.client, props.rtcSession);
- const { livekitRoom, connState } = useLiveKit(
+ const { livekitRoom, connState, doKeyRatchet } = useLiveKit(
props.rtcSession,
props.muteStates,
sfuConfig,
@@ -164,6 +164,7 @@ export const ActiveCall: FC = (props) => {
vm={vm}
livekitRoom={livekitRoom}
connState={connState}
+ doKeyRatchet={doKeyRatchet}
/>
@@ -184,6 +185,7 @@ export interface InCallViewProps {
otelGroupCallMembership?: OTelGroupCallMembership;
connState: ECConnectionState;
onShareClick: (() => void) | null;
+ doKeyRatchet?: () => void;
}
export const InCallView: FC = ({
@@ -198,6 +200,7 @@ export const InCallView: FC = ({
hideHeader,
connState,
onShareClick,
+ doKeyRatchet,
}) => {
const { supportsReactions, sendReaction, toggleRaisedHand } =
useReactionsSender();
@@ -710,6 +713,7 @@ export const InCallView: FC = ({
tab={settingsTab}
onTabChange={setSettingsTab}
livekitRoom={livekitRoom}
+ doKeyRatchet={doKeyRatchet}
/>
>
)}
diff --git a/src/settings/DeveloperSettingsTab.tsx b/src/settings/DeveloperSettingsTab.tsx
index 67de0e0d..2993ec0d 100644
--- a/src/settings/DeveloperSettingsTab.tsx
+++ b/src/settings/DeveloperSettingsTab.tsx
@@ -7,6 +7,7 @@ Please see LICENSE in the repository root for full details.
import { type ChangeEvent, type FC, useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
+import { Button } from "@vector-im/compound-web";
import { FieldRow, InputField } from "../input/Input";
import {
@@ -25,9 +26,14 @@ import { useUrlParams } from "../UrlParams";
interface Props {
client: MatrixClient;
livekitRoom?: LivekitRoom;
+ doKeyRatchet?: () => void;
}
-export const DeveloperSettingsTab: FC = ({ client, livekitRoom }) => {
+export const DeveloperSettingsTab: FC = ({
+ client,
+ livekitRoom,
+ doKeyRatchet,
+}) => {
const { t } = useTranslation();
const [duplicateTiles, setDuplicateTiles] = useSetting(duplicateTilesSetting);
const [debugTileLayout, setDebugTileLayout] = useSetting(
@@ -88,7 +94,13 @@ export const DeveloperSettingsTab: FC = ({ client, livekitRoom }) => {
{t("developer_mode.device_id", {
id: client.getDeviceId() || "unknown",
})}
-
+ {" "}
+
+ {" "}
+
void;
}
export const defaultSettingsTab: SettingsTab = "audio";
@@ -61,6 +62,7 @@ export const SettingsModal: FC = ({
client,
roomId,
livekitRoom,
+ doKeyRatchet,
}) => {
const { t } = useTranslation();
@@ -144,7 +146,13 @@ export const SettingsModal: FC = ({
const developerTab: Tab = {
key: "developer",
name: t("settings.developer_tab_title"),
- content: ,
+ content: (
+
+ ),
};
const tabs = [audioTab, videoTab];