From 3c0d81844fe25aefbc85c4d1666b364a49fc9e56 Mon Sep 17 00:00:00 2001 From: Timo <16718859+toger5@users.noreply.github.com> Date: Fri, 11 Apr 2025 10:07:50 +0200 Subject: [PATCH] Add option to enable to-device-encryption (#3167) * enable to-device-encryption * add logging for key provider * make rooms encrypted * add dev setting to choose to-device or room encryption * add indicator when to-device is used. --- locales/en/app.json | 3 +- package.json | 2 +- src/livekit/useLiveKit.ts | 3 ++ src/room/GroupCallView.tsx | 51 +++++++++------------------ src/room/InCallView.tsx | 19 +++++++++- src/rtcSessionHelpers.test.ts | 1 + src/rtcSessionHelpers.ts | 2 ++ src/settings/DeveloperSettingsTab.tsx | 19 ++++++++++ src/settings/settings.ts | 6 ++++ yarn.lock | 10 +++--- 10 files changed, 74 insertions(+), 42 deletions(-) diff --git a/locales/en/app.json b/locales/en/app.json index 51beef1b..be75681a 100644 --- a/locales/en/app.json +++ b/locales/en/app.json @@ -73,7 +73,8 @@ "show_connection_stats": "Show connection statistics", "show_non_member_tiles": "Show tiles for non-member media", "url_params": "URL parameters", - "use_new_membership_manager": "Use the new implementation of the call MembershipManager" + "use_new_membership_manager": "Use the new implementation of the call MembershipManager", + "use_to_device_key_transport": "Use to device messages to distribute keys for matrixRTC media" }, "disconnected_banner": "Connectivity to the server has been lost.", "error": { diff --git a/package.json b/package.json index 64e49806..065fbf9f 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "livekit-client": "2.11.1", "lodash-es": "^4.17.21", "loglevel": "^1.9.1", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#8395919f0fd1af7cab1e793d736f2cdf18ef7686", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#e3a3a52f2a56cb5cc52b57b36e9a915faed0b5db", "matrix-widget-api": "1.11.0", "normalize.css": "^8.0.1", "observable-hooks": "^4.2.3", diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts index 0500a04d..da180ab8 100644 --- a/src/livekit/useLiveKit.ts +++ b/src/livekit/useLiveKit.ts @@ -49,11 +49,14 @@ export function useLiveKit( if (e2eeSystem.kind === E2eeType.NONE) return undefined; if (e2eeSystem.kind === E2eeType.PER_PARTICIPANT) { + logger.info("Created MatrixKeyProvider (per participant)"); return { keyProvider: new MatrixKeyProvider(), worker: new E2EEWorker(), }; } else if (e2eeSystem.kind === E2eeType.SHARED_KEY && e2eeSystem.secret) { + logger.info("Created ExternalE2EEKeyProvider (shared key)"); + return { keyProvider: new ExternalE2EEKeyProvider(), worker: new E2EEWorker(), diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 3d9b9808..0d727485 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -62,6 +62,7 @@ import { } from "../utils/errors.ts"; import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary.tsx"; import { + useExperimentalToDeviceTransportSetting, useNewMembershipManagerSetting as useNewMembershipManagerSetting, useSetting, } from "../settings/settings"; @@ -151,6 +152,9 @@ export const GroupCallView: FC = ({ const { perParticipantE2EE, returnToLobby } = useUrlParams(); const e2eeSystem = useRoomEncryptionSystem(room.roomId); const [useNewMembershipManager] = useSetting(useNewMembershipManagerSetting); + const [useExperimentalToDeviceTransport] = useSetting( + useExperimentalToDeviceTransportSetting, + ); usePageTitle(roomName); @@ -178,16 +182,13 @@ export const GroupCallView: FC = ({ const latestMuteStates = useLatest(muteStates); const enterRTCSessionOrError = useCallback( - async ( - rtcSession: MatrixRTCSession, - perParticipantE2EE: boolean, - newMembershipManager: boolean, - ): Promise => { + async (rtcSession: MatrixRTCSession): Promise => { try { await enterRTCSession( rtcSession, perParticipantE2EE, - newMembershipManager, + useNewMembershipManager, + useExperimentalToDeviceTransport, ); } catch (e) { if (e instanceof ElementCallError) { @@ -201,7 +202,11 @@ export const GroupCallView: FC = ({ } } }, - [setExternalError], + [ + perParticipantE2EE, + useExperimentalToDeviceTransport, + useNewMembershipManager, + ], ); useEffect(() => { @@ -253,11 +258,7 @@ export const GroupCallView: FC = ({ await defaultDeviceSetup( ev.detail.data as unknown as JoinCallData, ); - await enterRTCSessionOrError( - rtcSession, - perParticipantE2EE, - useNewMembershipManager, - ); + await enterRTCSessionOrError(rtcSession); widget.api.transport.reply(ev.detail, {}); })().catch((e) => { logger.error("Error joining RTC session", e); @@ -270,21 +271,13 @@ export const GroupCallView: FC = ({ } else { // No lobby and no preload: we enter the rtc session right away (async (): Promise => { - await enterRTCSessionOrError( - rtcSession, - perParticipantE2EE, - useNewMembershipManager, - ); + await enterRTCSessionOrError(rtcSession); })().catch((e) => { logger.error("Error joining RTC session", e); }); } } else { - void enterRTCSessionOrError( - rtcSession, - perParticipantE2EE, - useNewMembershipManager, - ); + void enterRTCSessionOrError(rtcSession); } } }, [ @@ -407,13 +400,7 @@ export const GroupCallView: FC = ({ client={client} matrixInfo={matrixInfo} muteStates={muteStates} - onEnter={() => - void enterRTCSessionOrError( - rtcSession, - perParticipantE2EE, - useNewMembershipManager, - ) - } + onEnter={() => void enterRTCSessionOrError(rtcSession)} confineToRoom={confineToRoom} hideHeader={hideHeader} participantCount={participantCount} @@ -491,11 +478,7 @@ export const GroupCallView: FC = ({ recoveryActionHandler={(action) => { if (action == "reconnect") { setLeft(false); - enterRTCSessionOrError( - rtcSession, - perParticipantE2EE, - useNewMembershipManager, - ).catch((e) => { + enterRTCSessionOrError(rtcSession).catch((e) => { logger.error("Error re-entering RTC session", e); }); } diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index 53742fc2..b8718ba7 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -10,6 +10,7 @@ import { RoomContext, useLocalParticipant, } from "@livekit/components-react"; +import { Text } from "@vector-im/compound-web"; import { ConnectionState, type Room } from "livekit-client"; import { type MatrixClient } from "matrix-js-sdk"; import { @@ -94,11 +95,11 @@ import { ReactionsOverlay } from "./ReactionsOverlay"; import { CallEventAudioRenderer } from "./CallEventAudioRenderer"; import { debugTileLayout as debugTileLayoutSetting, + useExperimentalToDeviceTransportSetting, useSetting, } from "../settings/settings"; import { ReactionsReader } from "../reactions/ReactionsReader"; import { ConnectionLostError } from "../utils/errors.ts"; - const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {}); const maxTapDurationMs = 400; @@ -216,6 +217,10 @@ export const InCallView: FC = ({ room: livekitRoom, }); + const [toDeviceEncryption] = useSetting( + useExperimentalToDeviceTransportSetting, + ); + const toggleMicrophone = useCallback( () => muteStates.audio.setEnabled?.((e) => !e), [muteStates], @@ -662,6 +667,18 @@ export const InCallView: FC = ({ ))} + { + // TODO: remove this once we remove the developer flag + // and find a better way to device what key transport to use. + toDeviceEncryption && ( + + using to Device key transport + + ) + } {renderContent()} diff --git a/src/rtcSessionHelpers.test.ts b/src/rtcSessionHelpers.test.ts index fe7465b3..ecfd44f7 100644 --- a/src/rtcSessionHelpers.test.ts +++ b/src/rtcSessionHelpers.test.ts @@ -112,6 +112,7 @@ test("It joins the correct Session", async () => { manageMediaKeys: false, useLegacyMemberEvents: false, useNewMembershipManager: true, + useExperimentalToDeviceTransport: false, }, ); }); diff --git a/src/rtcSessionHelpers.ts b/src/rtcSessionHelpers.ts index fbaa7ed7..51bc79b8 100644 --- a/src/rtcSessionHelpers.ts +++ b/src/rtcSessionHelpers.ts @@ -98,6 +98,7 @@ export async function enterRTCSession( rtcSession: MatrixRTCSession, encryptMedia: boolean, useNewMembershipManager = true, + useExperimentalToDeviceTransport = false, ): Promise { PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId); @@ -125,6 +126,7 @@ export async function enterRTCSession( membershipKeepAlivePeriod: matrixRtcSessionConfig?.membership_keep_alive_period, makeKeyDelay: matrixRtcSessionConfig?.key_rotation_on_leave_delay, + useExperimentalToDeviceTransport, }, ); if (widget) { diff --git a/src/settings/DeveloperSettingsTab.tsx b/src/settings/DeveloperSettingsTab.tsx index 0981a843..67de0e0d 100644 --- a/src/settings/DeveloperSettingsTab.tsx +++ b/src/settings/DeveloperSettingsTab.tsx @@ -16,6 +16,7 @@ import { showNonMemberTiles as showNonMemberTilesSetting, showConnectionStats as showConnectionStatsSetting, useNewMembershipManagerSetting, + useExperimentalToDeviceTransportSetting, } from "./settings"; import type { MatrixClient } from "matrix-js-sdk"; import type { Room as LivekitRoom } from "livekit-client"; @@ -44,6 +45,10 @@ export const DeveloperSettingsTab: FC = ({ client, livekitRoom }) => { useNewMembershipManagerSetting, ); + const [ + useExperimentalToDeviceTransport, + setUseExperimentalToDeviceTransport, + ] = useSetting(useExperimentalToDeviceTransportSetting); const urlParams = useUrlParams(); const sfuUrl = useMemo((): URL | null => { @@ -156,6 +161,20 @@ export const DeveloperSettingsTab: FC = ({ client, livekitRoom }) => { )} /> + + ): void => { + setUseExperimentalToDeviceTransport(event.target.checked); + }, + [setUseExperimentalToDeviceTransport], + )} + /> + {livekitRoom ? ( <>

diff --git a/src/settings/settings.ts b/src/settings/settings.ts index 7babcfde..5a7b7a36 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -117,4 +117,10 @@ export const useNewMembershipManagerSetting = new Setting( "new-membership-manager", true, ); + +export const useExperimentalToDeviceTransportSetting = new Setting( + "experimental-to-device-transport", + false, +); + export const alwaysShowSelf = new Setting("always-show-self", true); diff --git a/yarn.lock b/yarn.lock index baa3d11f..cfd29564 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6913,7 +6913,7 @@ __metadata: livekit-client: "npm:2.11.1" lodash-es: "npm:^4.17.21" loglevel: "npm:^1.9.1" - matrix-js-sdk: "github:matrix-org/matrix-js-sdk#8395919f0fd1af7cab1e793d736f2cdf18ef7686" + matrix-js-sdk: "github:matrix-org/matrix-js-sdk#e3a3a52f2a56cb5cc52b57b36e9a915faed0b5db" matrix-widget-api: "npm:1.11.0" normalize.css: "npm:^8.0.1" observable-hooks: "npm:^4.2.3" @@ -9504,9 +9504,9 @@ __metadata: languageName: node linkType: hard -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#8395919f0fd1af7cab1e793d736f2cdf18ef7686": - version: 37.1.0 - resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=8395919f0fd1af7cab1e793d736f2cdf18ef7686" +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#e3a3a52f2a56cb5cc52b57b36e9a915faed0b5db": + version: 37.3.0 + resolution: "matrix-js-sdk@https://github.com/matrix-org/matrix-js-sdk.git#commit=e3a3a52f2a56cb5cc52b57b36e9a915faed0b5db" dependencies: "@babel/runtime": "npm:^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm": "npm:^14.0.1" @@ -9523,7 +9523,7 @@ __metadata: sdp-transform: "npm:^2.14.1" unhomoglyph: "npm:^1.0.6" uuid: "npm:11" - checksum: 10c0/a0eb3be822e07cfe53965f6ca4f0c3cdf8ba3728d03a15f2322a463a7543206583e0c2f34d6b6d45089ce36eec60d77d9e90eb0635d3c65a343f77728908fe57 + checksum: 10c0/1baf50f93576a6fdf46d76c7a84cf43adeb0b04e692165f749f15c56e8e3fd0f5f354a1702b9f9de1688cebbdee176f7056b71e8a526ef9b0fbbe23405c2aee2 languageName: node linkType: hard