From 8b9d9bd9d8dc2092c6c24960760ef101f4cbd06c Mon Sep 17 00:00:00 2001 From: Timo K Date: Wed, 17 Apr 2024 15:08:37 +0200 Subject: [PATCH] review Signed-off-by: Timo K --- public/locales/en-GB/app.json | 9 ++++---- src/UrlParams.ts | 35 +++++++++++++++++++++++++++--- src/e2ee/sharedKeyManagement.ts | 18 ++++++++-------- src/home/useGroupCallRooms.ts | 6 +++--- src/matrix-utils.ts | 38 ++++----------------------------- src/room/GroupCallLoader.tsx | 12 +++++------ src/room/useLoadGroupCall.ts | 28 +++++++++++++++++------- 7 files changed, 79 insertions(+), 67 deletions(-) diff --git a/public/locales/en-GB/app.json b/public/locales/en-GB/app.json index 38b2e70e5..fb39c7729 100644 --- a/public/locales/en-GB/app.json +++ b/public/locales/en-GB/app.json @@ -61,14 +61,15 @@ "full_screen_view_description": "<0>Submitting debug logs will help us track down the problem.", "full_screen_view_h1": "<0>Oops, something's gone wrong.", "group_call_loader": { - "banned_body": "You got banned from the room.", + "banned_body": "You have been banned from the room.", "banned_heading": "Banned", - "call_ended_body": "You got removed from the call.", - "call_ended_heading": "Call Ended", + "call_ended_body": "You have been removed from the call.", + "call_ended_heading": "Call ended", "failed_heading": "Call not found", "failed_text": "Calls are now end-to-end encrypted and need to be created from the home page. This helps make sure everyone's using the same encryption key.", "knock_reject_body": "The room members declined your request to join.", - "knock_reject_heading": "Not allowed to join" + "knock_reject_heading": "Not allowed to join", + "reason": "Reason" }, "hangup_button_label": "End call", "header_label": "Element Call Home", diff --git a/src/UrlParams.ts b/src/UrlParams.ts index 547393bff..3977b3df5 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -16,12 +16,12 @@ limitations under the License. import { useMemo } from "react"; import { useLocation } from "react-router-dom"; +import { logger } from "matrix-js-sdk/src/logger"; import { Config } from "./config/Config"; +import { EncryptionSystem } from "./e2ee/sharedKeyManagement"; +import { E2eeType } from "./e2ee/e2eeType"; -export const PASSWORD_STRING = "password="; -export const PER_PARTICIPANT_STRING = "perParticipantE2EE="; -export const VIA_SERVERS_STRING = "viaServers="; interface RoomIdentifier { roomAlias: string | null; roomId: string | null; @@ -329,3 +329,32 @@ export const useRoomIdentifier = (): RoomIdentifier => { [pathname, search, hash], ); }; + +export function generateUrlSearchParams( + roomId: string, + encryptionSystem: EncryptionSystem, + viaServers?: string[], +): URLSearchParams { + const params = new URLSearchParams(); + // The password shouldn't need URL encoding here (we generate URL-safe ones) but encode + // it in case it came from another client that generated a non url-safe one + switch (encryptionSystem?.kind) { + case E2eeType.SHARED_KEY: { + const encodedPassword = encodeURIComponent(encryptionSystem.secret); + if (encodedPassword !== encryptionSystem.secret) { + logger.info( + "Encoded call password used non URL-safe chars: buggy client?", + ); + } + params.set("password", encodedPassword); + break; + } + case E2eeType.PER_PARTICIPANT: + params.set("perParticipantE2EE", "true"); + break; + } + params.set("roomId", roomId); + viaServers?.forEach((s) => params.set("viaServers", s)); + + return params; +} diff --git a/src/e2ee/sharedKeyManagement.ts b/src/e2ee/sharedKeyManagement.ts index 967ab0141..6f826cfea 100644 --- a/src/e2ee/sharedKeyManagement.ts +++ b/src/e2ee/sharedKeyManagement.ts @@ -79,25 +79,25 @@ export function useRoomEncryptionSystem(roomId: string): EncryptionSystem { // (and we still need to take the value it returns because // the effect won't run in time for it to save to localstorage in // time for us to read it out again). - const [urlRoomId, passwordFormUrl] = useKeyFromUrl(); + const [urlRoomId, passwordFromUrl] = useKeyFromUrl(); const storedPassword = useInternalRoomSharedKey(roomId); const room = client?.getRoom(roomId); - const e2eeSystem = useMemo(() => { - if (!room) return { kind: E2eeType.NONE } as Unencrypted; + const e2eeSystem = useMemo(() => { + if (!room) return { kind: E2eeType.NONE }; if (storedPassword) return { kind: E2eeType.SHARED_KEY, secret: storedPassword, - } as SharedSecret; + }; if (urlRoomId === roomId) return { kind: E2eeType.SHARED_KEY, - secret: passwordFormUrl, - } as SharedSecret; + secret: passwordFromUrl, + }; if (room.hasEncryptionStateEvent()) { - return { kind: E2eeType.PER_PARTICIPANT } as PerParticipantE2EE; + return { kind: E2eeType.PER_PARTICIPANT }; } - return { kind: E2eeType.NONE } as EncryptionSystem; - }, [passwordFormUrl, room, roomId, storedPassword, urlRoomId]); + return { kind: E2eeType.NONE }; + }, [passwordFromUrl, room, roomId, storedPassword, urlRoomId]); return e2eeSystem; } diff --git a/src/home/useGroupCallRooms.ts b/src/home/useGroupCallRooms.ts index d5a26012c..d2880795d 100644 --- a/src/home/useGroupCallRooms.ts +++ b/src/home/useGroupCallRooms.ts @@ -93,7 +93,7 @@ const roomIsJoinable = (room: Room): boolean => { return joinRule === JoinRule.Knock || joinRule === JoinRule.Public; }; -const roomIsJoinedWithCall = (room: Room): boolean => { +const roomHasCallMembershipEvents = (room: Room): boolean => { const roomStateEvents = room .getLiveTimeline() .getState(EventTimeline.FORWARDS)?.events; @@ -108,13 +108,13 @@ export function useGroupCallRooms(client: MatrixClient): GroupCallRoom[] { useEffect(() => { function updateRooms(): void { + // We want to show all rooms that historically had a call and which we are (can become) part of. const rooms = client .getRooms() - .filter(roomIsJoinedWithCall) + .filter(roomHasCallMembershipEvents) .filter(roomIsJoinable); const sortedRooms = sortRooms(client, rooms); const items = sortedRooms.map((room) => { - // const groupCall = client.getGroupCallForRoom(room.roomId)!; const session = client.matrixRTC.getRoomSession(room); session.memberships; return { diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 5540592ba..c93580b12 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -29,12 +29,7 @@ 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"; import IndexedDBWorker from "./IndexedDBWorker?worker"; -import { - getUrlParams, - PASSWORD_STRING, - PER_PARTICIPANT_STRING, - VIA_SERVERS_STRING, -} from "./UrlParams"; +import { generateUrlSearchParams, getUrlParams } from "./UrlParams"; import { loadOlm } from "./olm"; import { Config } from "./config/Config"; import { E2eeType } from "./e2ee/e2eeType"; @@ -339,8 +334,6 @@ export async function createRoom( const result = await createPromise; - logger.log(`Creating group call in ${result.room_id}`); - let password; if (e2ee == E2eeType.SHARED_KEY) { password = secureRandomBase64Url(16); @@ -383,33 +376,10 @@ export function getRelativeRoomUrl( roomName?: string, viaServers?: string[], ): string { - // The password shouldn't need URL encoding here (we generate URL-safe ones) but encode - // it in case it came from another client that generated a non url-safe one - const encryptionPart = ((): string => { - switch (encryptionSystem?.kind) { - case E2eeType.SHARED_KEY: { - const encodedPassword = encodeURIComponent(encryptionSystem.secret); - if (encodedPassword !== encryptionSystem.secret) { - logger.info( - "Encoded call password used non URL-safe chars: buggy client?", - ); - } - return "&" + PASSWORD_STRING + encodedPassword; - } - case E2eeType.PER_PARTICIPANT: - return "&" + PER_PARTICIPANT_STRING + "true"; - case E2eeType.NONE: - return ""; - } - })(); - - const roomIdPart = `roomId=${roomId}`; - const viaServersPart = viaServers - ? viaServers.map((s) => "&" + VIA_SERVERS_STRING + s).join("") + const roomPart = roomName + ? "/" + roomAliasLocalpartFromRoomName(roomName) : ""; - return `/room/#${ - roomName ? "/" + roomAliasLocalpartFromRoomName(roomName) : "" - }?${roomIdPart}${encryptionPart}${viaServersPart}`; + return `/room/#${roomPart}?${generateUrlSearchParams(roomId, encryptionSystem, viaServers).toString()}`; } export function getAvatarUrl( diff --git a/src/room/GroupCallLoader.tsx b/src/room/GroupCallLoader.tsx index 11a6b94bb..3ccc7b490 100644 --- a/src/room/GroupCallLoader.tsx +++ b/src/room/GroupCallLoader.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ReactNode, useCallback } from "react"; +import { useCallback } from "react"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { useTranslation } from "react-i18next"; import { MatrixError } from "matrix-js-sdk"; @@ -24,7 +24,7 @@ import { Heading, Link, Text } from "@vector-im/compound-web"; import { useLoadGroupCall, GroupCallStatus, - CustomMessage, + CallTerminatedMessage, } from "./useLoadGroupCall"; import { ErrorView, FullScreenView } from "../FullScreenView"; @@ -32,7 +32,7 @@ interface Props { client: MatrixClient; roomIdOrAlias: string; viaServers: string[]; - children: (groupCallState: GroupCallStatus) => ReactNode; + children: (groupCallState: GroupCallStatus) => JSX.Element; } export function GroupCallLoader({ @@ -57,7 +57,7 @@ export function GroupCallLoader({ case "loaded": case "waitForInvite": case "canKnock": - return <>{children(groupCallState)}; + return children(groupCallState); case "loading": return ( @@ -77,14 +77,14 @@ export function GroupCallLoader({ ); - } else if (groupCallState.error instanceof CustomMessage) { + } else if (groupCallState.error instanceof CallTerminatedMessage) { return ( {groupCallState.error.message} {groupCallState.error.messageBody} {groupCallState.error.reason && ( <> - Reason: + {t("group_call_loader.reason")}: "{groupCallState.error.reason}" )} diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index b959a0e2e..3a3c279fb 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -63,9 +63,21 @@ export type GroupCallStatus = | GroupCallWaitForInvite | GroupCallCanKnock; -export class CustomMessage extends Error { +export class CallTerminatedMessage extends Error { + /** + * @param messageBody The message explaining the kind of termination (kick, ban, knock reject, etc.) (translated) + */ public messageBody: string; + /** + * @param reason The user provided reason for the termination (kick/ban) + */ public reason?: string; + /** + * + * @param messageTitle The title of the call ended screen message (translated) + * @param messageBody The message explaining the kind of termination (kick, ban, knock reject, etc.) (translated) + * @param reason The user provided reason for the termination (kick/ban) + */ public constructor( messageTitle: string, messageBody: string, @@ -87,8 +99,8 @@ export const useLoadGroupCall = ( const { t } = useTranslation(); const bannedError = useCallback( - (): CustomMessage => - new CustomMessage( + (): CallTerminatedMessage => + new CallTerminatedMessage( t("group_call_loader.banned_heading"), t("group_call_loader.banned_body"), leaveReason(), @@ -96,8 +108,8 @@ export const useLoadGroupCall = ( [t], ); const knockRejectError = useCallback( - (): CustomMessage => - new CustomMessage( + (): CallTerminatedMessage => + new CallTerminatedMessage( t("group_call_loader.knock_reject_heading"), t("group_call_loader.knock_reject_body"), leaveReason(), @@ -105,8 +117,8 @@ export const useLoadGroupCall = ( [t], ); const removeNoticeError = useCallback( - (): CustomMessage => - new CustomMessage( + (): CallTerminatedMessage => + new CallTerminatedMessage( t("group_call_loader.call_ended_heading"), t("group_call_loader.call_ended_body"), leaveReason(), @@ -148,7 +160,7 @@ export const useLoadGroupCall = ( onKnockSent: () => void, ): Promise => { let joinedRoom: Room | null = null; - await client.knockRoom(roomId); + await client.knockRoom(roomId, { viaServers }); onKnockSent(); const invitePromise = new Promise((resolve, reject) => { client.on(