From 92d61fa0f159e3c65e6fc2ab2f8c78b769fbe237 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 16 Nov 2023 16:32:25 +0000 Subject: [PATCH] Hide rooms we don't have the key for in recents list --- src/UrlParams.ts | 2 +- src/e2ee/sharedKeyManagement.ts | 51 ++++++++++++++++++++------------- src/home/useGroupCallRooms.ts | 14 ++++++++- src/matrix-utils.ts | 8 ++---- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/UrlParams.ts b/src/UrlParams.ts index ea1da7d6..68d10d7a 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -32,7 +32,7 @@ interface RoomIdentifier { // the situations that call for this behavior ('isEmbedded'). This makes it // clearer what each flag means, and helps us avoid coupling Element Call's // behavior to the needs of specific consumers. -interface UrlParams { +export interface UrlParams { // Widget api related params widgetId: string | null; parentUrl: string | null; diff --git a/src/e2ee/sharedKeyManagement.ts b/src/e2ee/sharedKeyManagement.ts index bc34f673..2d23f1e4 100644 --- a/src/e2ee/sharedKeyManagement.ts +++ b/src/e2ee/sharedKeyManagement.ts @@ -15,13 +15,18 @@ limitations under the License. */ import { useEffect, useMemo } from "react"; +import { Room } from "matrix-js-sdk"; import { setLocalStorageItem, useLocalStorage } from "../useLocalStorage"; import { useClient } from "../ClientContext"; -import { useUrlParams } from "../UrlParams"; +import { UrlParams, getUrlParams, useUrlParams } from "../UrlParams"; import { widget } from "../widget"; -export const getRoomSharedKeyLocalStorageKey = (roomId: string): string => +export function saveKeyForRoom(roomId: string, password: string): void { + setLocalStorageItem(getRoomSharedKeyLocalStorageKey(roomId), password); +} + +const getRoomSharedKeyLocalStorageKey = (roomId: string): string => `room-shared-key-${roomId}`; const useInternalRoomSharedKey = (roomId: string): string | null => { @@ -31,6 +36,21 @@ const useInternalRoomSharedKey = (roomId: string): string | null => { return roomSharedKey; }; +export function getKeyForRoom(roomId: string): string | null { + saveKeyFromUrlParams(getUrlParams()); + const key = getRoomSharedKeyLocalStorageKey(roomId); + return localStorage.getItem(key); +} + +function saveKeyFromUrlParams(urlParams: UrlParams): void { + if (!urlParams.password || !urlParams.roomId) return; + + // We set the Item by only using data from the url. This way we + // make sure, we always have matching pairs in the LocalStorage, + // as they occur in the call links. + saveKeyForRoom(urlParams.roomId, urlParams.password); +} + /** * Extracts the room password from the URL if one is present, saving it in localstorage * and returning it in a tuple with the corresponding room ID from the URL. @@ -40,18 +60,7 @@ const useInternalRoomSharedKey = (roomId: string): string | null => { const useKeyFromUrl = (): [string, string] | [undefined, undefined] => { const urlParams = useUrlParams(); - useEffect(() => { - if (!urlParams.password || !urlParams.roomId) return; - if (!urlParams.roomId) return; - - setLocalStorageItem( - // We set the Item by only using data from the url. This way we - // make sure, we always have matching pairs in the LocalStorage, - // as they occur in the call links. - getRoomSharedKeyLocalStorageKey(urlParams.roomId), - urlParams.password, - ); - }, [urlParams]); + useEffect(() => saveKeyFromUrlParams(urlParams), [urlParams]); return urlParams.roomId && urlParams.password ? [urlParams.roomId, urlParams.password] @@ -74,12 +83,14 @@ export const useRoomSharedKey = (roomId: string): string | undefined => { export const useIsRoomE2EE = (roomId: string): boolean | null => { const { client } = useClient(); - const room = useMemo(() => client?.getRoom(roomId) ?? null, [roomId, client]); + const room = useMemo(() => client?.getRoom(roomId), [roomId, client]); + + return useMemo(() => !room || isRoomE2EE(room), [room]); +}; + +export function isRoomE2EE(room: Room): boolean { // For now, rooms in widget mode are never considered encrypted. // In the future, when widget mode gains encryption support, then perhaps we // should inspect the e2eEnabled URL parameter here? - return useMemo( - () => widget === null && (room === null || !room.getCanonicalAlias()), - [room], - ); -}; + return widget === null && !room.getCanonicalAlias(); +} diff --git a/src/home/useGroupCallRooms.ts b/src/home/useGroupCallRooms.ts index 77572ad6..bea7ea1e 100644 --- a/src/home/useGroupCallRooms.ts +++ b/src/home/useGroupCallRooms.ts @@ -21,6 +21,8 @@ import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { GroupCallEventHandlerEvent } from "matrix-js-sdk/src/webrtc/groupCallEventHandler"; import { useState, useEffect } from "react"; +import { getKeyForRoom, isRoomE2EE } from "../e2ee/sharedKeyManagement"; + export interface GroupCallRoom { roomAlias?: string; roomName: string; @@ -78,6 +80,14 @@ function sortRooms(client: MatrixClient, rooms: Room[]): Room[] { }); } +function roomIsJoinable(room: Room): boolean { + if (isRoomE2EE(room)) { + return Boolean(getKeyForRoom(room.roomId)); + } else { + return true; + } +} + export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] { const [rooms, setRooms] = useState([]); @@ -88,7 +98,9 @@ export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] { } const groupCalls = client.groupCallEventHandler.groupCalls.values(); - const rooms = Array.from(groupCalls).map((groupCall) => groupCall.room); + const rooms = Array.from(groupCalls) + .map((groupCall) => groupCall.room) + .filter(roomIsJoinable); const sortedRooms = sortRooms(client, rooms); const items = sortedRooms.map((room) => { const groupCall = client.getGroupCallForRoom(room.roomId)!; diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 90fdc705..08af1750 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -36,9 +36,8 @@ import IndexedDBWorker from "./IndexedDBWorker?worker"; import { getUrlParams, PASSWORD_STRING } from "./UrlParams"; import { loadOlm } from "./olm"; import { Config } from "./config/Config"; -import { setLocalStorageItem } from "./useLocalStorage"; -import { getRoomSharedKeyLocalStorageKey } from "./e2ee/sharedKeyManagement"; import { E2eeType } from "./e2ee/e2eeType"; +import { saveKeyForRoom } from "./e2ee/sharedKeyManagement"; export const fallbackICEServerAllowed = import.meta.env.VITE_FALLBACK_STUN_ALLOWED === "true"; @@ -359,10 +358,7 @@ export async function createRoom( let password; if (e2ee == E2eeType.SHARED_KEY) { password = secureRandomBase64Url(16); - setLocalStorageItem( - getRoomSharedKeyLocalStorageKey(result.room_id), - password, - ); + saveKeyForRoom(result.room_id, password); } return {