From 15d3e7574d0582803db1922a4ffa4a5c8fc19ae1 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 16 Oct 2023 17:45:06 +0100 Subject: [PATCH 01/16] Re-apply Simon's emebdded e2ee work on latest livekit branch Replaces https://github.com/vector-im/element-call/pull/1350 --- src/UrlParams.ts | 5 +++ src/e2ee/matrixKeyProvider.ts | 70 +++++++++++++++++++++++++++++++++++ src/livekit/useLiveKit.ts | 44 ++++++++++++++++------ src/room/GroupCallView.tsx | 24 +++++++----- src/room/InCallView.tsx | 1 + src/rtcSessionHelpers.ts | 7 +++- src/widget.ts | 2 + 7 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 src/e2ee/matrixKeyProvider.ts diff --git a/src/UrlParams.ts b/src/UrlParams.ts index 498d7cc5..fb203375 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -111,6 +111,10 @@ interface UrlParams { * E2EE password */ password: string | null; + /** + * Whether we the app should use per participant keys for E2EE. + */ + perParticipantE2EE: boolean; } // This is here as a stopgap, but what would be far nicer is a function that @@ -206,6 +210,7 @@ export const getUrlParams = ( fontScale: Number.isNaN(fontScale) ? null : fontScale, analyticsID: parser.getParam("analyticsID"), allowIceFallback: parser.getFlagParam("allowIceFallback"), + perParticipantE2EE: true /*parser.getFlagParam("perParticipantE2EE")*/, }; }; diff --git a/src/e2ee/matrixKeyProvider.ts b/src/e2ee/matrixKeyProvider.ts new file mode 100644 index 00000000..7053054a --- /dev/null +++ b/src/e2ee/matrixKeyProvider.ts @@ -0,0 +1,70 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { BaseKeyProvider, createKeyMaterialFromString } from "livekit-client"; +import { logger } from "matrix-js-sdk/src/logger"; +import { + MatrixRTCSession, + MatrixRTCSessionEvent, +} from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; + +export class MatrixKeyProvider extends BaseKeyProvider { + private rtcSession?: MatrixRTCSession; + + public setRTCSession(rtcSession: MatrixRTCSession): void { + if (this.rtcSession) { + this.rtcSession.off( + MatrixRTCSessionEvent.EncryptionKeyChanged, + this.onEncryptionKeyChanged, + ); + } + + this.rtcSession = rtcSession; + + this.rtcSession.on( + MatrixRTCSessionEvent.EncryptionKeyChanged, + this.onEncryptionKeyChanged, + ); + + // The new session could be aware of keys of which the old session wasn't, + // so emit a key changed event. + for (const [ + participant, + encryptionKeys, + ] of this.rtcSession.getEncryptionKeys()) { + for (const [index, encryptionKey] of encryptionKeys.entries()) { + this.onEncryptionKeyChanged(encryptionKey, index, participant); + } + } + } + + private onEncryptionKeyChanged = async ( + encryptionKey: string, + encryptionKeyIndex: number, + participantId: string, + ): Promise => { + this.onSetEncryptionKey( + await createKeyMaterialFromString(encryptionKey), + participantId, + encryptionKeyIndex, + ); + + logger.debug( + `Embedded-E2EE-LOG onEncryptionKeyChanged participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex} encryptionKey=${encryptionKey}`, + this.getKeys(), + ); + }; +} diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts index 814eb096..b6741058 100644 --- a/src/livekit/useLiveKit.ts +++ b/src/livekit/useLiveKit.ts @@ -26,6 +26,7 @@ import { useLiveKitRoom } from "@livekit/components-react"; import { useEffect, useMemo, useRef, useState } from "react"; import E2EEWorker from "livekit-client/e2ee-worker?worker"; import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { defaultLiveKitOptions } from "./options"; import { SFUConfig } from "./openIDSFU"; @@ -39,9 +40,16 @@ import { ECConnectionState, useECConnectionState, } from "./useECConnectionState"; +import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider"; + +export enum E2EEMode { + PerParticipantKey = "per_participant_key", + SharedKey = "shared_key", +} export type E2EEConfig = { - sharedKey: string; + mode: E2EEMode; + sharedKey?: string; }; interface UseLivekitResult { @@ -50,26 +58,38 @@ interface UseLivekitResult { } export function useLiveKit( + rtcSession: MatrixRTCSession, muteStates: MuteStates, sfuConfig?: SFUConfig, e2eeConfig?: E2EEConfig, ): UseLivekitResult { - const e2eeOptions = useMemo(() => { - if (!e2eeConfig?.sharedKey) return undefined; + const e2eeOptions = useMemo((): E2EEOptions | undefined => { + if (!e2eeConfig) return undefined; - return { - keyProvider: new ExternalE2EEKeyProvider(), - worker: new E2EEWorker(), - } as E2EEOptions; + if (e2eeConfig.mode === E2EEMode.PerParticipantKey) { + return { + keyProvider: new MatrixKeyProvider(), + worker: new E2EEWorker(), + }; + } else if (e2eeConfig.mode === E2EEMode.SharedKey && e2eeConfig.sharedKey) { + return { + keyProvider: new ExternalE2EEKeyProvider(), + worker: new E2EEWorker(), + }; + } }, [e2eeConfig]); useEffect(() => { - if (!e2eeConfig?.sharedKey || !e2eeOptions) return; + if (!e2eeConfig || !e2eeOptions) return; - (e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey( - e2eeConfig?.sharedKey, - ); - }, [e2eeOptions, e2eeConfig?.sharedKey]); + if (e2eeConfig.mode === E2EEMode.PerParticipantKey) { + (e2eeOptions.keyProvider as MatrixKeyProvider).setRTCSession(rtcSession); + } else if (e2eeConfig.mode === E2EEMode.SharedKey && e2eeConfig.sharedKey) { + (e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey( + e2eeConfig.sharedKey, + ); + } + }, [e2eeOptions, e2eeConfig, rtcSession]); const initialMuteStates = useRef(muteStates); const devices = useMediaDevices(); diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 4b2f4cfa..9103b56b 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -44,6 +44,8 @@ import { useRoomAvatar } from "./useRoomAvatar"; import { useRoomName } from "./useRoomName"; import { useJoinRule } from "./useJoinRule"; import { InviteModal } from "./InviteModal"; +import { E2EEConfig, E2EEMode } from "../livekit/useLiveKit"; +import { useUrlParams } from "../UrlParams"; declare global { interface Window { @@ -85,6 +87,7 @@ export const GroupCallView: FC = ({ const roomName = useRoomName(rtcSession.room); const roomAvatar = useRoomAvatar(rtcSession.room); const roomEncrypted = useIsRoomE2EE(rtcSession.room.roomId)!; + const { perParticipantE2EE } = useUrlParams(); const matrixInfo = useMemo((): MatrixInfo => { return { @@ -176,7 +179,7 @@ export const GroupCallView: FC = ({ } } - enterRTCSession(rtcSession); + enterRTCSession(rtcSession, perParticipantE2EE); PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); // we only have room sessions right now, so call ID is the emprty string - we use the room ID @@ -195,7 +198,7 @@ export const GroupCallView: FC = ({ widget!.lazyActions.off(ElementWidgetActions.JoinCall, onJoin); }; } - }, [rtcSession, preload]); + }, [rtcSession, preload, perParticipantE2EE]); const [left, setLeft] = useState(false); const [leaveError, setLeaveError] = useState(undefined); @@ -255,16 +258,19 @@ export const GroupCallView: FC = ({ } }, [isJoined, rtcSession]); - const e2eeConfig = useMemo( - () => (e2eeSharedKey ? { sharedKey: e2eeSharedKey } : undefined), - [e2eeSharedKey], - ); + const e2eeConfig = useMemo((): E2EEConfig | undefined => { + if (perParticipantE2EE) { + return { mode: E2EEMode.PerParticipantKey }; + } else if (e2eeSharedKey) { + return { mode: E2EEMode.SharedKey, sharedKey: e2eeSharedKey }; + } + }, [perParticipantE2EE, e2eeSharedKey]); const onReconnect = useCallback(() => { setLeft(false); setLeaveError(undefined); - enterRTCSession(rtcSession); - }, [rtcSession]); + enterRTCSession(rtcSession, perParticipantE2EE); + }, [rtcSession, perParticipantE2EE]); const joinRule = useJoinRule(rtcSession.room); @@ -380,7 +386,7 @@ export const GroupCallView: FC = ({ client={client} matrixInfo={matrixInfo} muteStates={muteStates} - onEnter={(): void => enterRTCSession(rtcSession)} + onEnter={(): void => enterRTCSession(rtcSession, perParticipantE2EE)} confineToRoom={confineToRoom} hideHeader={hideHeader} participantCount={participantCount} diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index bd0fd1a7..373c8b14 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -100,6 +100,7 @@ export interface ActiveCallProps export const ActiveCall: FC = (props) => { const sfuConfig = useOpenIDSFU(props.client, props.rtcSession); const { livekitRoom, connState } = useLiveKit( + props.rtcSession, props.muteStates, sfuConfig, props.e2eeConfig, diff --git a/src/rtcSessionHelpers.ts b/src/rtcSessionHelpers.ts index 1ea00160..bcde93e5 100644 --- a/src/rtcSessionHelpers.ts +++ b/src/rtcSessionHelpers.ts @@ -33,7 +33,10 @@ function makeFocus(livekitAlias: string): LivekitFocus { }; } -export function enterRTCSession(rtcSession: MatrixRTCSession): void { +export function enterRTCSession( + rtcSession: MatrixRTCSession, + encryptMedia: boolean, +): void { PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId); @@ -44,7 +47,7 @@ export function enterRTCSession(rtcSession: MatrixRTCSession): void { // right now we assume everything is a room-scoped call const livekitAlias = rtcSession.room.roomId; - rtcSession.joinRoomSession([makeFocus(livekitAlias)]); + rtcSession.joinRoomSession([makeFocus(livekitAlias)], encryptMedia); } export async function leaveRTCSession( diff --git a/src/widget.ts b/src/widget.ts index e0a0d340..3a7549f8 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -77,6 +77,8 @@ export const widget = ((): WidgetHelpers | null => { logger.info("Widget API is available"); const api = new WidgetApi(widgetId, parentOrigin); api.requestCapability(MatrixCapabilities.AlwaysOnScreen); + api.requestCapabilityToSendEvent(EventType.CallEncryptionPrefix); + api.requestCapabilityToReceiveEvent(EventType.CallEncryptionPrefix); // Set up the lazy action emitter, but only for select actions that we // intend for the app to handle From 74e4c2fd08bcccc8ee07ffd0b4dafb7cdc76b593 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 16 Oct 2023 17:58:21 +0100 Subject: [PATCH 02/16] Remove testing hack --- src/UrlParams.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UrlParams.ts b/src/UrlParams.ts index fb203375..f757af51 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -210,7 +210,7 @@ export const getUrlParams = ( fontScale: Number.isNaN(fontScale) ? null : fontScale, analyticsID: parser.getParam("analyticsID"), allowIceFallback: parser.getFlagParam("allowIceFallback"), - perParticipantE2EE: true /*parser.getFlagParam("perParticipantE2EE")*/, + perParticipantE2EE: parser.getFlagParam("perParticipantE2EE"), }; }; From 97aba9c315d65ad197f1a837ef848a188b16f8a1 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 16 Oct 2023 18:21:08 +0100 Subject: [PATCH 03/16] Update js-sdk branch --- package.json | 2 +- yarn.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 43414002..dc96bf84 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "i18next-http-backend": "^2.0.0", "livekit-client": "^1.12.3", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#c8f8fb587d29dce22d314bfc16bf25a76b04e8bb", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#798953b8d181604d7b18647f16f199baaa645141", "matrix-widget-api": "^1.3.1", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/yarn.lock b/yarn.lock index 91916c60..1b4a12da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1992,10 +1992,10 @@ clsx "^2.0.0" usehooks-ts "^2.9.1" -"@matrix-org/matrix-sdk-crypto-wasm@^1.2.3-alpha.0": - version "1.2.3-alpha.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-1.2.3-alpha.0.tgz#f6f93e3ee44c5f1e0e255badd26f4a7d3fb1dab8" - integrity sha512-BFLqfq/WbYZ+83r4UWLhwtBYvTp5DKTHNeWUSDBVvudFtqBvkntNAAUz+xmhmO1XkyNm+sBaElxF8IS9S8zdww== +"@matrix-org/matrix-sdk-crypto-wasm@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-2.0.0.tgz#a4e9682705f090c94a58f6b851054f7598de9e83" + integrity sha512-8tKmI9u35URvtAr6zcfNGphImWt1y458iKq2PSPOSARlsmVk2lkrhsBFihBnWJY1oJC2EMsyfI8XTRuVYv00TQ== "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz": version "3.2.14" @@ -7369,12 +7369,12 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#c8f8fb587d29dce22d314bfc16bf25a76b04e8bb": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#798953b8d181604d7b18647f16f199baaa645141": version "29.0.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/c8f8fb587d29dce22d314bfc16bf25a76b04e8bb" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/798953b8d181604d7b18647f16f199baaa645141" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^1.2.3-alpha.0" + "@matrix-org/matrix-sdk-crypto-wasm" "^2.0.0" another-json "^0.2.0" bs58 "^5.0.0" content-type "^1.0.4" From 635badbda1cd61d11045e5a0695be12424f3cc8e Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 18 Oct 2023 15:19:25 +0100 Subject: [PATCH 04/16] Bump to latest js-sdk PR commit --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index dc96bf84..e22cbb24 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "i18next-http-backend": "^2.0.0", "livekit-client": "^1.12.3", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#798953b8d181604d7b18647f16f199baaa645141", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#df62adcec665e7ff3b602dffa72d7e175b38b9d3", "matrix-widget-api": "^1.3.1", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/yarn.lock b/yarn.lock index 1b4a12da..f786e8dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7369,9 +7369,9 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#798953b8d181604d7b18647f16f199baaa645141": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#df62adcec665e7ff3b602dffa72d7e175b38b9d3": version "29.0.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/798953b8d181604d7b18647f16f199baaa645141" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/df62adcec665e7ff3b602dffa72d7e175b38b9d3" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm" "^2.0.0" From ba999e7bc3c6ef91d00dcd2d23f58311441c8093 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 18 Oct 2023 15:27:44 +0100 Subject: [PATCH 05/16] Update event name --- src/widget.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget.ts b/src/widget.ts index 3a7549f8..7b8f4fe7 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -77,8 +77,8 @@ export const widget = ((): WidgetHelpers | null => { logger.info("Widget API is available"); const api = new WidgetApi(widgetId, parentOrigin); api.requestCapability(MatrixCapabilities.AlwaysOnScreen); - api.requestCapabilityToSendEvent(EventType.CallEncryptionPrefix); - api.requestCapabilityToReceiveEvent(EventType.CallEncryptionPrefix); + api.requestCapabilityToSendEvent(EventType.CallEncryptionKeysPrefix); + api.requestCapabilityToReceiveEvent(EventType.CallEncryptionKeysPrefix); // Set up the lazy action emitter, but only for select actions that we // intend for the app to handle From 550315e8d7af365448ea9fad7c4380919149466e Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 19 Oct 2023 14:40:59 +0100 Subject: [PATCH 06/16] Update js-sdk branch --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index dd40a1e3..59ecf93e 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "i18next-http-backend": "^2.0.0", "livekit-client": "^1.12.3", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#df62adcec665e7ff3b602dffa72d7e175b38b9d3", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#9a42886e26267e0e4508bb4f40f4ab4de6db9a2e", "matrix-widget-api": "^1.3.1", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/yarn.lock b/yarn.lock index 7fe3ca28..2aa05444 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7037,9 +7037,9 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#df62adcec665e7ff3b602dffa72d7e175b38b9d3": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#9a42886e26267e0e4508bb4f40f4ab4de6db9a2e": version "29.0.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/df62adcec665e7ff3b602dffa72d7e175b38b9d3" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/9a42886e26267e0e4508bb4f40f4ab4de6db9a2e" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm" "^2.0.0" From 22ef625b55a69362e7e2a2a698dfa396ae81c95f Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 19 Oct 2023 16:50:29 +0100 Subject: [PATCH 07/16] Disable ratcheting The auto ratcheting sets the keys and so looks like it can clobber us setting a key from the app if they race, so just disable it, at least for now - we aren't using it. --- src/e2ee/matrixKeyProvider.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/e2ee/matrixKeyProvider.ts b/src/e2ee/matrixKeyProvider.ts index 7053054a..fcef3d8e 100644 --- a/src/e2ee/matrixKeyProvider.ts +++ b/src/e2ee/matrixKeyProvider.ts @@ -24,6 +24,10 @@ import { export class MatrixKeyProvider extends BaseKeyProvider { private rtcSession?: MatrixRTCSession; + public constructor() { + super({ ratchetWindowSize: 0 }); + } + public setRTCSession(rtcSession: MatrixRTCSession): void { if (this.rtcSession) { this.rtcSession.off( @@ -63,7 +67,7 @@ export class MatrixKeyProvider extends BaseKeyProvider { ); logger.debug( - `Embedded-E2EE-LOG onEncryptionKeyChanged participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex} encryptionKey=${encryptionKey}`, + `Embedded-E2EE-LOG onEncryptionKeyChanged room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex} encryptionKey=${encryptionKey}`, this.getKeys(), ); }; From 7b538363be59e52fda925a9b5e62131d905736c9 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 19 Oct 2023 17:43:31 +0100 Subject: [PATCH 08/16] Don't require shared key in ppe2ee mode --- src/room/GroupCallView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 9103b56b..9f9935e3 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -296,7 +296,7 @@ export const GroupCallView: FC = ({ const { t } = useTranslation(); - if (isRoomE2EE && !e2eeSharedKey) { + if (isRoomE2EE && !perParticipantE2EE && !e2eeSharedKey) { return ( Date: Fri, 20 Oct 2023 17:31:15 +0100 Subject: [PATCH 09/16] Fix key format on the wire to be base64 --- package.json | 2 +- src/e2ee/matrixKeyProvider.ts | 6 +++--- src/matrix-utils.ts | 20 ++------------------ yarn.lock | 4 ++-- 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 59ecf93e..d68729f3 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "i18next-http-backend": "^2.0.0", "livekit-client": "^1.12.3", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#9a42886e26267e0e4508bb4f40f4ab4de6db9a2e", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#4120641b3d3983733044967812e475bc3610d1e7", "matrix-widget-api": "^1.3.1", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/src/e2ee/matrixKeyProvider.ts b/src/e2ee/matrixKeyProvider.ts index fcef3d8e..73b788d8 100644 --- a/src/e2ee/matrixKeyProvider.ts +++ b/src/e2ee/matrixKeyProvider.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { BaseKeyProvider, createKeyMaterialFromString } from "livekit-client"; +import { BaseKeyProvider, createKeyMaterialFromBuffer } from "livekit-client"; import { logger } from "matrix-js-sdk/src/logger"; import { MatrixRTCSession, @@ -56,12 +56,12 @@ export class MatrixKeyProvider extends BaseKeyProvider { } private onEncryptionKeyChanged = async ( - encryptionKey: string, + encryptionKey: Uint8Array, encryptionKeyIndex: number, participantId: string, ): Promise => { this.onSetEncryptionKey( - await createKeyMaterialFromString(encryptionKey), + await createKeyMaterialFromBuffer(encryptionKey), participantId, encryptionKeyIndex, ); diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 52c55959..7c0966fb 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -28,6 +28,7 @@ import { GroupCallIntent, GroupCallType, } from "matrix-js-sdk/src/webrtc/groupCall"; +import { secureRandomBase64 } from "matrix-js-sdk/src/randomstring"; import type { MatrixClient } from "matrix-js-sdk/src/client"; import type { Room } from "matrix-js-sdk/src/models/room"; @@ -73,23 +74,6 @@ function waitForSync(client: MatrixClient): Promise { }); } -function secureRandomString(entropyBytes: number): string { - const key = new Uint8Array(entropyBytes); - crypto.getRandomValues(key); - // encode to base64url as this value goes into URLs - // base64url is just base64 with thw two non-alphanum characters swapped out for - // ones that can be put in a URL without encoding. Browser JS has a native impl - // for base64 encoding but only a string (there isn't one that takes a UInt8Array - // yet) so just use the built-in one and convert, replace the chars and strip the - // padding from the end (otherwise we'd need to pull in another dependency). - return btoa( - key.reduce((acc, current) => acc + String.fromCharCode(current), ""), - ) - .replace("+", "-") - .replace("/", "_") - .replace(/=*$/, ""); -} - /** * Initialises and returns a new standalone Matrix Client. * If true is passed for the 'restore' parameter, a check will be made @@ -363,7 +347,7 @@ export async function createRoom( let password; if (e2ee) { - password = secureRandomString(16); + password = secureRandomBase64(16); setLocalStorageItem( getRoomSharedKeyLocalStorageKey(result.room_id), password, diff --git a/yarn.lock b/yarn.lock index 253e6e1d..3d2988ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7042,9 +7042,9 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#9a42886e26267e0e4508bb4f40f4ab4de6db9a2e": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#4120641b3d3983733044967812e475bc3610d1e7": version "29.0.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/9a42886e26267e0e4508bb4f40f4ab4de6db9a2e" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/4120641b3d3983733044967812e475bc3610d1e7" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-wasm" "^2.0.0" From f04beab99fd763c4c8db9417185bc2ac4df470b9 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 23 Oct 2023 12:10:25 +0100 Subject: [PATCH 10/16] Make e2ee type clearer hopefully --- src/home/RegisteredView.tsx | 7 ++++++- src/home/UnauthenticatedView.tsx | 7 ++++++- src/matrix-utils.ts | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/home/RegisteredView.tsx b/src/home/RegisteredView.tsx index c5ff8cfa..4da46696 100644 --- a/src/home/RegisteredView.tsx +++ b/src/home/RegisteredView.tsx @@ -40,6 +40,7 @@ import { Caption } from "../typography/Typography"; import { Form } from "../form/Form"; import { useOptInAnalytics } from "../settings/useSetting"; import { AnalyticsNotice } from "../analytics/AnalyticsNotice"; +import { E2eeType } from "../e2ee/e2eeType"; interface Props { client: MatrixClient; @@ -72,7 +73,11 @@ export const RegisteredView: FC = ({ client }) => { setError(undefined); setLoading(true); - const createRoomResult = await createRoom(client, roomName, true); + const createRoomResult = await createRoom( + client, + roomName, + E2eeType.SHARED_KEY, + ); history.push( getRelativeRoomUrl( diff --git a/src/home/UnauthenticatedView.tsx b/src/home/UnauthenticatedView.tsx index 91e8b56e..732f0633 100644 --- a/src/home/UnauthenticatedView.tsx +++ b/src/home/UnauthenticatedView.tsx @@ -43,6 +43,7 @@ import { generateRandomName } from "../auth/generateRandomName"; import { AnalyticsNotice } from "../analytics/AnalyticsNotice"; import { useOptInAnalytics } from "../settings/useSetting"; import { Config } from "../config/Config"; +import { E2eeType } from "../e2ee/e2eeType"; export const UnauthenticatedView: FC = () => { const { setClient } = useClient(); @@ -84,7 +85,11 @@ export const UnauthenticatedView: FC = () => { let createRoomResult; try { - createRoomResult = await createRoom(client, roomName, true); + createRoomResult = await createRoom( + client, + roomName, + E2eeType.SHARED_KEY, + ); } catch (error) { if (!setClient) { throw error; diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 7c0966fb..6a1ea37d 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -38,6 +38,7 @@ import { loadOlm } from "./olm"; import { Config } from "./config/Config"; import { setLocalStorageItem } from "./useLocalStorage"; import { getRoomSharedKeyLocalStorageKey } from "./e2ee/sharedKeyManagement"; +import { E2eeType } from "./e2ee/e2eeType"; export const fallbackICEServerAllowed = import.meta.env.VITE_FALLBACK_STUN_ALLOWED === "true"; @@ -278,10 +279,20 @@ interface CreateRoomResult { password?: string; } +/** + * Create a new room ready for calls + * + * @param client Matrix client to use + * @param name The name of the room + * @param e2ee The type of e2ee call to create. Note that we would currently never + * create a room for per-participant e2ee calls: since it's used in + * embedded mode, we use the existing room. + * @returns Object holding information about the new room + */ export async function createRoom( client: MatrixClient, name: string, - e2ee: boolean, + e2ee: E2eeType, ): Promise { logger.log(`Creating room for group call`); const createPromise = client.createRoom({ @@ -346,7 +357,7 @@ export async function createRoom( ); let password; - if (e2ee) { + if (e2ee == E2eeType.SHARED_KEY) { password = secureRandomBase64(16); setLocalStorageItem( getRoomSharedKeyLocalStorageKey(result.room_id), From 74f1aa0cbad1fbf11584de618491d03cb7ac5f32 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 23 Oct 2023 12:17:28 +0100 Subject: [PATCH 11/16] Add the file --- src/e2ee/e2eeType.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/e2ee/e2eeType.ts diff --git a/src/e2ee/e2eeType.ts b/src/e2ee/e2eeType.ts new file mode 100644 index 00000000..be4a4ba9 --- /dev/null +++ b/src/e2ee/e2eeType.ts @@ -0,0 +1,21 @@ +/* +Copyright 2023 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export enum E2eeType { + NONE = 0, + PER_PARTICIPANT = 1, + SHARED_KEY = 2, +} From 99d5103dfa60131ca59196e0418629af66525e14 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 23 Oct 2023 12:31:37 +0100 Subject: [PATCH 12/16] Stop logging encryption keys --- src/e2ee/matrixKeyProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/e2ee/matrixKeyProvider.ts b/src/e2ee/matrixKeyProvider.ts index 73b788d8..52111806 100644 --- a/src/e2ee/matrixKeyProvider.ts +++ b/src/e2ee/matrixKeyProvider.ts @@ -67,7 +67,7 @@ export class MatrixKeyProvider extends BaseKeyProvider { ); logger.debug( - `Embedded-E2EE-LOG onEncryptionKeyChanged room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex} encryptionKey=${encryptionKey}`, + `Embedded-E2EE-LOG onEncryptionKeyChanged room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`, this.getKeys(), ); }; From 8a18dadc02af83e20d480771654e5ea8c51dbb09 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 25 Oct 2023 15:30:58 +0100 Subject: [PATCH 13/16] Don't log keys Although I'm not sure this actually did anyway, but it was very spammy --- src/e2ee/matrixKeyProvider.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/e2ee/matrixKeyProvider.ts b/src/e2ee/matrixKeyProvider.ts index 52111806..7fac8193 100644 --- a/src/e2ee/matrixKeyProvider.ts +++ b/src/e2ee/matrixKeyProvider.ts @@ -67,8 +67,7 @@ export class MatrixKeyProvider extends BaseKeyProvider { ); logger.debug( - `Embedded-E2EE-LOG onEncryptionKeyChanged room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`, - this.getKeys(), + `Sent new key to livekit room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`, ); }; } From c65ce86001b49da77f72364e6645b36d8a45e482 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 30 Oct 2023 16:55:16 +0000 Subject: [PATCH 14/16] Update for renamed function and new js-sdk containing it --- package.json | 2 +- src/matrix-utils.ts | 4 ++-- yarn.lock | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 99e1c61a..f0fbbccf 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "i18next-http-backend": "^2.0.0", "livekit-client": "^1.12.3", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#4120641b3d3983733044967812e475bc3610d1e7", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#bf40656220f62f214c8ebb3247b840eaafb2874b", "matrix-widget-api": "^1.3.1", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 6a1ea37d..90fdc705 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -28,7 +28,7 @@ import { GroupCallIntent, GroupCallType, } from "matrix-js-sdk/src/webrtc/groupCall"; -import { secureRandomBase64 } from "matrix-js-sdk/src/randomstring"; +import { secureRandomBase64Url } from "matrix-js-sdk/src/randomstring"; import type { MatrixClient } from "matrix-js-sdk/src/client"; import type { Room } from "matrix-js-sdk/src/models/room"; @@ -358,7 +358,7 @@ export async function createRoom( let password; if (e2ee == E2eeType.SHARED_KEY) { - password = secureRandomBase64(16); + password = secureRandomBase64Url(16); setLocalStorageItem( getRoomSharedKeyLocalStorageKey(result.room_id), password, diff --git a/yarn.lock b/yarn.lock index 5361242d..b45de6b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1992,10 +1992,10 @@ clsx "^2.0.0" usehooks-ts "^2.9.1" -"@matrix-org/matrix-sdk-crypto-wasm@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-2.0.0.tgz#a4e9682705f090c94a58f6b851054f7598de9e83" - integrity sha512-8tKmI9u35URvtAr6zcfNGphImWt1y458iKq2PSPOSARlsmVk2lkrhsBFihBnWJY1oJC2EMsyfI8XTRuVYv00TQ== +"@matrix-org/matrix-sdk-crypto-wasm@^2.1.1": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-2.2.0.tgz#7c60afe01915281a6b71502821bc8e01afbfa70d" + integrity sha512-txmvaTiZpVV0/kWCRcE7tZvRESCEc1ynLJDVh9OUsFlaXfl13c7qdD3E6IJEJ8YiPMIn+PHogdfBZsO84reaMg== "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz": version "3.2.14" @@ -7023,12 +7023,12 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#4120641b3d3983733044967812e475bc3610d1e7": - version "29.0.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/4120641b3d3983733044967812e475bc3610d1e7" +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#bf40656220f62f214c8ebb3247b840eaafb2874b": + version "29.1.0" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/bf40656220f62f214c8ebb3247b840eaafb2874b" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^2.0.0" + "@matrix-org/matrix-sdk-crypto-wasm" "^2.1.1" another-json "^0.2.0" bs58 "^5.0.0" content-type "^1.0.4" From 49c90a461271a0281af921f6eb4950b4027bbb47 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 30 Oct 2023 17:06:59 +0000 Subject: [PATCH 15/16] Amalgamate E2EEMode & E2eeType --- src/livekit/useLiveKit.ts | 24 +++++++++++++----------- src/room/GroupCallView.tsx | 7 ++++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts index 49044b61..3e6f6397 100644 --- a/src/livekit/useLiveKit.ts +++ b/src/livekit/useLiveKit.ts @@ -41,14 +41,10 @@ import { useECConnectionState, } from "./useECConnectionState"; import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider"; - -export enum E2EEMode { - PerParticipantKey = "per_participant_key", - SharedKey = "shared_key", -} +import { E2eeType } from "../e2ee/e2eeType"; export type E2EEConfig = { - mode: E2EEMode; + mode: E2eeType; sharedKey?: string; }; @@ -64,14 +60,17 @@ export function useLiveKit( e2eeConfig?: E2EEConfig, ): UseLivekitResult { const e2eeOptions = useMemo((): E2EEOptions | undefined => { - if (!e2eeConfig) return undefined; + if (!e2eeConfig || e2eeConfig.mode === E2eeType.NONE) return undefined; - if (e2eeConfig.mode === E2EEMode.PerParticipantKey) { + if (e2eeConfig.mode === E2eeType.PER_PARTICIPANT) { return { keyProvider: new MatrixKeyProvider(), worker: new E2EEWorker(), }; - } else if (e2eeConfig.mode === E2EEMode.SharedKey && e2eeConfig.sharedKey) { + } else if ( + e2eeConfig.mode === E2eeType.SHARED_KEY && + e2eeConfig.sharedKey + ) { return { keyProvider: new ExternalE2EEKeyProvider(), worker: new E2EEWorker(), @@ -82,9 +81,12 @@ export function useLiveKit( useEffect(() => { if (!e2eeConfig || !e2eeOptions) return; - if (e2eeConfig.mode === E2EEMode.PerParticipantKey) { + if (e2eeConfig.mode === E2eeType.PER_PARTICIPANT) { (e2eeOptions.keyProvider as MatrixKeyProvider).setRTCSession(rtcSession); - } else if (e2eeConfig.mode === E2EEMode.SharedKey && e2eeConfig.sharedKey) { + } else if ( + e2eeConfig.mode === E2eeType.SHARED_KEY && + e2eeConfig.sharedKey + ) { (e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey( e2eeConfig.sharedKey, ); diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index f13c40ff..69c88971 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -44,8 +44,9 @@ import { useRoomAvatar } from "./useRoomAvatar"; import { useRoomName } from "./useRoomName"; import { useJoinRule } from "./useJoinRule"; import { InviteModal } from "./InviteModal"; -import { E2EEConfig, E2EEMode } from "../livekit/useLiveKit"; +import { E2EEConfig } from "../livekit/useLiveKit"; import { useUrlParams } from "../UrlParams"; +import { E2eeType } from "../e2ee/e2eeType"; declare global { interface Window { @@ -262,9 +263,9 @@ export const GroupCallView: FC = ({ const e2eeConfig = useMemo((): E2EEConfig | undefined => { if (perParticipantE2EE) { - return { mode: E2EEMode.PerParticipantKey }; + return { mode: E2eeType.PER_PARTICIPANT }; } else if (e2eeSharedKey) { - return { mode: E2EEMode.SharedKey, sharedKey: e2eeSharedKey }; + return { mode: E2eeType.SHARED_KEY, sharedKey: e2eeSharedKey }; } }, [perParticipantE2EE, e2eeSharedKey]); From ba376d700544709cd67f73f4f834b39fbac9c344 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 31 Oct 2023 20:00:48 +0000 Subject: [PATCH 16/16] Back to js-sdk develop branch now it's merged --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f0fbbccf..ec7d76ca 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "i18next-http-backend": "^2.0.0", "livekit-client": "^1.12.3", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#bf40656220f62f214c8ebb3247b840eaafb2874b", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#bf81c4bfebd52532d67d30a66e651e3658c8aaad", "matrix-widget-api": "^1.3.1", "normalize.css": "^8.0.1", "pako": "^2.0.4", diff --git a/yarn.lock b/yarn.lock index b45de6b1..3d118883 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1992,7 +1992,7 @@ clsx "^2.0.0" usehooks-ts "^2.9.1" -"@matrix-org/matrix-sdk-crypto-wasm@^2.1.1": +"@matrix-org/matrix-sdk-crypto-wasm@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-2.2.0.tgz#7c60afe01915281a6b71502821bc8e01afbfa70d" integrity sha512-txmvaTiZpVV0/kWCRcE7tZvRESCEc1ynLJDVh9OUsFlaXfl13c7qdD3E6IJEJ8YiPMIn+PHogdfBZsO84reaMg== @@ -7023,12 +7023,12 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#bf40656220f62f214c8ebb3247b840eaafb2874b": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#bf81c4bfebd52532d67d30a66e651e3658c8aaad": version "29.1.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/bf40656220f62f214c8ebb3247b840eaafb2874b" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/bf81c4bfebd52532d67d30a66e651e3658c8aaad" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^2.1.1" + "@matrix-org/matrix-sdk-crypto-wasm" "^2.2.0" another-json "^0.2.0" bs58 "^5.0.0" content-type "^1.0.4"