mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-12 18:39:19 +00:00
Refactor encryption information.
We had lots of enums and booleans to describe the encryption situation. Now we only use the `EncryptionSystem` "enum" which contains the additional information like sharedKey. (and we don't use the isRoomE2EE function that is somewhat confusing since it checks `return widget === null && !room.getCanonicalAlias();` which is only indirectly related to e2ee) Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
committed by
Andrew Ferrazzutti
parent
620c3f5d34
commit
69deece0a3
@@ -15,12 +15,11 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useMemo } from "react";
|
import { useEffect, useMemo } from "react";
|
||||||
import { Room } from "matrix-js-sdk";
|
|
||||||
|
|
||||||
import { setLocalStorageItem, useLocalStorage } from "../useLocalStorage";
|
import { setLocalStorageItem, useLocalStorage } from "../useLocalStorage";
|
||||||
import { useClient } from "../ClientContext";
|
|
||||||
import { UrlParams, getUrlParams, useUrlParams } from "../UrlParams";
|
import { UrlParams, getUrlParams, useUrlParams } from "../UrlParams";
|
||||||
import { widget } from "../widget";
|
import { E2eeType } from "./e2eeType";
|
||||||
|
import { useClient } from "../ClientContext";
|
||||||
|
|
||||||
export function saveKeyForRoom(roomId: string, password: string): void {
|
export function saveKeyForRoom(roomId: string, password: string): void {
|
||||||
setLocalStorageItem(getRoomSharedKeyLocalStorageKey(roomId), password);
|
setLocalStorageItem(getRoomSharedKeyLocalStorageKey(roomId), password);
|
||||||
@@ -68,30 +67,37 @@ const useKeyFromUrl = (): [string, string] | [undefined, undefined] => {
|
|||||||
: [undefined, undefined];
|
: [undefined, undefined];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useRoomSharedKey = (roomId: string): string | undefined => {
|
export type Unencrypted = { kind: E2eeType.NONE };
|
||||||
|
export type SharedSecret = { kind: E2eeType.SHARED_KEY; secret: string };
|
||||||
|
export type PerParticipantE2EE = { kind: E2eeType.PER_PARTICIPANT };
|
||||||
|
export type EncryptionSystem = Unencrypted | SharedSecret | PerParticipantE2EE;
|
||||||
|
|
||||||
|
export function useRoomEncryptionSystem(roomId: string): EncryptionSystem {
|
||||||
|
const { client } = useClient();
|
||||||
|
|
||||||
// make sure we've extracted the key from the URL first
|
// make sure we've extracted the key from the URL first
|
||||||
// (and we still need to take the value it returns because
|
// (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
|
// the effect won't run in time for it to save to localstorage in
|
||||||
// time for us to read it out again).
|
// time for us to read it out again).
|
||||||
const [urlRoomId, passwordFormUrl] = useKeyFromUrl();
|
const [urlRoomId, passwordFormUrl] = useKeyFromUrl();
|
||||||
|
|
||||||
const storedPassword = useInternalRoomSharedKey(roomId);
|
const storedPassword = useInternalRoomSharedKey(roomId);
|
||||||
|
const room = client?.getRoom(roomId);
|
||||||
if (storedPassword) return storedPassword;
|
const e2eeSystem = useMemo(() => {
|
||||||
if (urlRoomId === roomId) return passwordFormUrl;
|
if (!room) return { kind: E2eeType.NONE } as Unencrypted;
|
||||||
return undefined;
|
if (storedPassword)
|
||||||
};
|
return {
|
||||||
|
kind: E2eeType.SHARED_KEY,
|
||||||
export const useIsRoomE2EE = (roomId: string): boolean | null => {
|
secret: storedPassword,
|
||||||
const { client } = useClient();
|
} as SharedSecret;
|
||||||
const room = useMemo(() => client?.getRoom(roomId), [roomId, client]);
|
if (urlRoomId === roomId)
|
||||||
|
return {
|
||||||
return useMemo(() => !room || isRoomE2EE(room), [room]);
|
kind: E2eeType.SHARED_KEY,
|
||||||
};
|
secret: passwordFormUrl,
|
||||||
|
} as SharedSecret;
|
||||||
export function isRoomE2EE(room: Room): boolean {
|
if (room.hasEncryptionStateEvent()) {
|
||||||
// For now, rooms in widget mode are never considered encrypted.
|
return { kind: E2eeType.PER_PARTICIPANT } as PerParticipantE2EE;
|
||||||
// In the future, when widget mode gains encryption support, then perhaps we
|
}
|
||||||
// should inspect the e2eEnabled URL parameter here?
|
return { kind: E2eeType.NONE } as EncryptionSystem;
|
||||||
return widget === null && !room.getCanonicalAlias();
|
}, [passwordFormUrl, room, roomId, storedPassword, urlRoomId]);
|
||||||
|
return e2eeSystem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,12 +78,14 @@ export const RegisteredView: FC<Props> = ({ client }) => {
|
|||||||
roomName,
|
roomName,
|
||||||
E2eeType.SHARED_KEY,
|
E2eeType.SHARED_KEY,
|
||||||
);
|
);
|
||||||
|
if (!createRoomResult.password)
|
||||||
|
throw new Error("Failed to create room with shared secret");
|
||||||
|
|
||||||
history.push(
|
history.push(
|
||||||
getRelativeRoomUrl(
|
getRelativeRoomUrl(
|
||||||
createRoomResult.roomId,
|
createRoomResult.roomId,
|
||||||
|
{ kind: E2eeType.SHARED_KEY, secret: createRoomResult.password },
|
||||||
roomName,
|
roomName,
|
||||||
createRoomResult.password,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,13 +116,15 @@ export const UnauthenticatedView: FC = () => {
|
|||||||
if (!setClient) {
|
if (!setClient) {
|
||||||
throw new Error("setClient is undefined");
|
throw new Error("setClient is undefined");
|
||||||
}
|
}
|
||||||
|
if (!createRoomResult.password)
|
||||||
|
throw new Error("Failed to create room with shared secret");
|
||||||
|
|
||||||
setClient({ client, session });
|
setClient({ client, session });
|
||||||
history.push(
|
history.push(
|
||||||
getRelativeRoomUrl(
|
getRelativeRoomUrl(
|
||||||
createRoomResult.roomId,
|
createRoomResult.roomId,
|
||||||
|
{ kind: E2eeType.SHARED_KEY, secret: createRoomResult.password },
|
||||||
roomName,
|
roomName,
|
||||||
createRoomResult.password,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,7 @@ import {
|
|||||||
} from "./useECConnectionState";
|
} from "./useECConnectionState";
|
||||||
import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider";
|
import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider";
|
||||||
import { E2eeType } from "../e2ee/e2eeType";
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
|
import { EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
export type E2EEConfig = {
|
|
||||||
mode: E2eeType;
|
|
||||||
sharedKey?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface UseLivekitResult {
|
interface UseLivekitResult {
|
||||||
livekitRoom?: Room;
|
livekitRoom?: Room;
|
||||||
@@ -56,41 +52,35 @@ export function useLiveKit(
|
|||||||
rtcSession: MatrixRTCSession,
|
rtcSession: MatrixRTCSession,
|
||||||
muteStates: MuteStates,
|
muteStates: MuteStates,
|
||||||
sfuConfig: SFUConfig | undefined,
|
sfuConfig: SFUConfig | undefined,
|
||||||
e2eeConfig: E2EEConfig,
|
e2eeSystem: EncryptionSystem,
|
||||||
): UseLivekitResult {
|
): UseLivekitResult {
|
||||||
const e2eeOptions = useMemo((): E2EEOptions | undefined => {
|
const e2eeOptions = useMemo((): E2EEOptions | undefined => {
|
||||||
if (e2eeConfig.mode === E2eeType.NONE) return undefined;
|
if (e2eeSystem.kind === E2eeType.NONE) return undefined;
|
||||||
|
|
||||||
if (e2eeConfig.mode === E2eeType.PER_PARTICIPANT) {
|
if (e2eeSystem.kind === E2eeType.PER_PARTICIPANT) {
|
||||||
return {
|
return {
|
||||||
keyProvider: new MatrixKeyProvider(),
|
keyProvider: new MatrixKeyProvider(),
|
||||||
worker: new E2EEWorker(),
|
worker: new E2EEWorker(),
|
||||||
};
|
};
|
||||||
} else if (
|
} else if (e2eeSystem.kind === E2eeType.SHARED_KEY && e2eeSystem.secret) {
|
||||||
e2eeConfig.mode === E2eeType.SHARED_KEY &&
|
|
||||||
e2eeConfig.sharedKey
|
|
||||||
) {
|
|
||||||
return {
|
return {
|
||||||
keyProvider: new ExternalE2EEKeyProvider(),
|
keyProvider: new ExternalE2EEKeyProvider(),
|
||||||
worker: new E2EEWorker(),
|
worker: new E2EEWorker(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [e2eeConfig]);
|
}, [e2eeSystem]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (e2eeConfig.mode === E2eeType.NONE || !e2eeOptions) return;
|
if (e2eeSystem.kind === E2eeType.NONE || !e2eeOptions) return;
|
||||||
|
|
||||||
if (e2eeConfig.mode === E2eeType.PER_PARTICIPANT) {
|
if (e2eeSystem.kind === E2eeType.PER_PARTICIPANT) {
|
||||||
(e2eeOptions.keyProvider as MatrixKeyProvider).setRTCSession(rtcSession);
|
(e2eeOptions.keyProvider as MatrixKeyProvider).setRTCSession(rtcSession);
|
||||||
} else if (
|
} else if (e2eeSystem.kind === E2eeType.SHARED_KEY && e2eeSystem.secret) {
|
||||||
e2eeConfig.mode === E2eeType.SHARED_KEY &&
|
|
||||||
e2eeConfig.sharedKey
|
|
||||||
) {
|
|
||||||
(e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey(
|
(e2eeOptions.keyProvider as ExternalE2EEKeyProvider).setKey(
|
||||||
e2eeConfig.sharedKey,
|
e2eeSystem.secret,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [e2eeOptions, e2eeConfig, rtcSession]);
|
}, [e2eeOptions, e2eeSystem, rtcSession]);
|
||||||
|
|
||||||
const initialMuteStates = useRef<MuteStates>(muteStates);
|
const initialMuteStates = useRef<MuteStates>(muteStates);
|
||||||
const devices = useMediaDevices();
|
const devices = useMediaDevices();
|
||||||
@@ -131,9 +121,9 @@ export function useLiveKit(
|
|||||||
// useEffect() with an argument that references itself, if E2EE is enabled
|
// useEffect() with an argument that references itself, if E2EE is enabled
|
||||||
const room = useMemo(() => {
|
const room = useMemo(() => {
|
||||||
const r = new Room(roomOptions);
|
const r = new Room(roomOptions);
|
||||||
r.setE2EEEnabled(e2eeConfig.mode !== E2eeType.NONE);
|
r.setE2EEEnabled(e2eeSystem.kind !== E2eeType.NONE);
|
||||||
return r;
|
return r;
|
||||||
}, [roomOptions, e2eeConfig]);
|
}, [roomOptions, e2eeSystem]);
|
||||||
|
|
||||||
const connectionState = useECConnectionState(
|
const connectionState = useECConnectionState(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ import PopOutIcon from "@vector-im/compound-design-tokens/icons/pop-out.svg?reac
|
|||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import { Modal } from "../Modal";
|
import { Modal } from "../Modal";
|
||||||
import { useIsRoomE2EE, useRoomSharedKey } from "../e2ee/sharedKeyManagement";
|
import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
import { getAbsoluteRoomUrl } from "../matrix-utils";
|
import { getAbsoluteRoomUrl } from "../matrix-utils";
|
||||||
import styles from "./AppSelectionModal.module.css";
|
import styles from "./AppSelectionModal.module.css";
|
||||||
import { editFragmentQuery } from "../UrlParams";
|
import { editFragmentQuery } from "../UrlParams";
|
||||||
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
roomId: string | null;
|
roomId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppSelectionModal: FC<Props> = ({ roomId }) => {
|
export const AppSelectionModal: FC<Props> = ({ roomId }) => {
|
||||||
@@ -42,10 +43,9 @@ export const AppSelectionModal: FC<Props> = ({ roomId }) => {
|
|||||||
},
|
},
|
||||||
[setOpen],
|
[setOpen],
|
||||||
);
|
);
|
||||||
|
const e2eeSystem = useRoomEncryptionSystem(roomId);
|
||||||
|
|
||||||
const roomSharedKey = useRoomSharedKey(roomId ?? "");
|
if (e2eeSystem.kind === E2eeType.NONE) {
|
||||||
const roomIsEncrypted = useIsRoomE2EE(roomId ?? "");
|
|
||||||
if (roomIsEncrypted && roomSharedKey === undefined) {
|
|
||||||
logger.error(
|
logger.error(
|
||||||
"Generating app redirect URL for encrypted room but don't have key available!",
|
"Generating app redirect URL for encrypted room but don't have key available!",
|
||||||
);
|
);
|
||||||
@@ -60,7 +60,7 @@ export const AppSelectionModal: FC<Props> = ({ roomId }) => {
|
|||||||
const url = new URL(
|
const url = new URL(
|
||||||
roomId === null
|
roomId === null
|
||||||
? window.location.href
|
? window.location.href
|
||||||
: getAbsoluteRoomUrl(roomId, undefined, roomSharedKey ?? undefined),
|
: getAbsoluteRoomUrl(roomId, e2eeSystem),
|
||||||
);
|
);
|
||||||
// Edit the URL to prevent the app selection prompt from appearing a second
|
// Edit the URL to prevent the app selection prompt from appearing a second
|
||||||
// time within the app, and to keep the user confined to the current room
|
// time within the app, and to keep the user confined to the current room
|
||||||
@@ -73,7 +73,7 @@ export const AppSelectionModal: FC<Props> = ({ roomId }) => {
|
|||||||
const result = new URL("io.element.call:/");
|
const result = new URL("io.element.call:/");
|
||||||
result.searchParams.set("url", url.toString());
|
result.searchParams.set("url", url.toString());
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}, [roomId, roomSharedKey]);
|
}, [e2eeSystem, roomId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -17,7 +17,10 @@ limitations under the License.
|
|||||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { FC, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { Room, isE2EESupported } from "livekit-client";
|
import {
|
||||||
|
Room,
|
||||||
|
isE2EESupported as isE2EESupportedBrowser,
|
||||||
|
} from "livekit-client";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
import { JoinRule } from "matrix-js-sdk/src/matrix";
|
import { JoinRule } from "matrix-js-sdk/src/matrix";
|
||||||
@@ -39,12 +42,11 @@ import { useMediaDevices, MediaDevices } from "../livekit/MediaDevicesContext";
|
|||||||
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
||||||
import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers";
|
import { enterRTCSession, leaveRTCSession } from "../rtcSessionHelpers";
|
||||||
import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState";
|
import { useMatrixRTCSessionJoinState } from "../useMatrixRTCSessionJoinState";
|
||||||
import { useIsRoomE2EE, useRoomSharedKey } from "../e2ee/sharedKeyManagement";
|
import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
import { useRoomAvatar } from "./useRoomAvatar";
|
import { useRoomAvatar } from "./useRoomAvatar";
|
||||||
import { useRoomName } from "./useRoomName";
|
import { useRoomName } from "./useRoomName";
|
||||||
import { useJoinRule } from "./useJoinRule";
|
import { useJoinRule } from "./useJoinRule";
|
||||||
import { InviteModal } from "./InviteModal";
|
import { InviteModal } from "./InviteModal";
|
||||||
import { E2EEConfig } from "../livekit/useLiveKit";
|
|
||||||
import { useUrlParams } from "../UrlParams";
|
import { useUrlParams } from "../UrlParams";
|
||||||
import { E2eeType } from "../e2ee/e2eeType";
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
|
|
||||||
@@ -86,10 +88,8 @@ export const GroupCallView: FC<Props> = ({
|
|||||||
const { displayName, avatarUrl } = useProfile(client);
|
const { displayName, avatarUrl } = useProfile(client);
|
||||||
const roomName = useRoomName(rtcSession.room);
|
const roomName = useRoomName(rtcSession.room);
|
||||||
const roomAvatar = useRoomAvatar(rtcSession.room);
|
const roomAvatar = useRoomAvatar(rtcSession.room);
|
||||||
const e2eeSharedKey = useRoomSharedKey(rtcSession.room.roomId);
|
|
||||||
const { perParticipantE2EE, returnToLobby } = useUrlParams();
|
const { perParticipantE2EE, returnToLobby } = useUrlParams();
|
||||||
const roomEncrypted =
|
const e2eeSystem = useRoomEncryptionSystem(rtcSession.room.roomId);
|
||||||
useIsRoomE2EE(rtcSession.room.roomId) || perParticipantE2EE;
|
|
||||||
|
|
||||||
const matrixInfo = useMemo((): MatrixInfo => {
|
const matrixInfo = useMemo((): MatrixInfo => {
|
||||||
return {
|
return {
|
||||||
@@ -100,16 +100,16 @@ export const GroupCallView: FC<Props> = ({
|
|||||||
roomName,
|
roomName,
|
||||||
roomAlias: rtcSession.room.getCanonicalAlias(),
|
roomAlias: rtcSession.room.getCanonicalAlias(),
|
||||||
roomAvatar,
|
roomAvatar,
|
||||||
roomEncrypted,
|
e2eeSystem,
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
|
client,
|
||||||
displayName,
|
displayName,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
rtcSession,
|
rtcSession.room,
|
||||||
roomName,
|
roomName,
|
||||||
roomAvatar,
|
roomAvatar,
|
||||||
roomEncrypted,
|
e2eeSystem,
|
||||||
client,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Count each member only once, regardless of how many devices they use
|
// Count each member only once, regardless of how many devices they use
|
||||||
@@ -126,16 +126,6 @@ export const GroupCallView: FC<Props> = ({
|
|||||||
const latestMuteStates = useRef<MuteStates>();
|
const latestMuteStates = useRef<MuteStates>();
|
||||||
latestMuteStates.current = muteStates;
|
latestMuteStates.current = muteStates;
|
||||||
|
|
||||||
const e2eeConfig = useMemo((): E2EEConfig => {
|
|
||||||
if (perParticipantE2EE) {
|
|
||||||
return { mode: E2eeType.PER_PARTICIPANT };
|
|
||||||
} else if (e2eeSharedKey) {
|
|
||||||
return { mode: E2eeType.SHARED_KEY, sharedKey: e2eeSharedKey };
|
|
||||||
} else {
|
|
||||||
return { mode: E2eeType.NONE };
|
|
||||||
}
|
|
||||||
}, [perParticipantE2EE, e2eeSharedKey]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const defaultDeviceSetup = async (
|
const defaultDeviceSetup = async (
|
||||||
requestedDeviceData: JoinCallData,
|
requestedDeviceData: JoinCallData,
|
||||||
@@ -288,17 +278,18 @@ export const GroupCallView: FC<Props> = ({
|
|||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (roomEncrypted && !perParticipantE2EE && !e2eeSharedKey) {
|
if (e2eeSystem.kind === E2eeType.NONE) {
|
||||||
return (
|
return (
|
||||||
<ErrorView
|
<ErrorView
|
||||||
error={
|
error={
|
||||||
new Error(
|
new Error(
|
||||||
"No E2EE key provided: please make sure the URL you're using to join this call has been retrieved using the in-app button.",
|
"No E2EE key or other encryption system provided: Element call calls are always encrypted, please make sure the URL you're using to join this call has been retrieved using the in-app button.",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (!isE2EESupported() && roomEncrypted) {
|
} else if (!isE2EESupportedBrowser()) {
|
||||||
|
// and we have a encryption system.
|
||||||
return (
|
return (
|
||||||
<FullScreenView>
|
<FullScreenView>
|
||||||
<Heading>{t("browser_media_e2ee_unsupported_heading")}</Heading>
|
<Heading>{t("browser_media_e2ee_unsupported_heading")}</Heading>
|
||||||
@@ -345,7 +336,7 @@ export const GroupCallView: FC<Props> = ({
|
|||||||
onLeave={onLeave}
|
onLeave={onLeave}
|
||||||
hideHeader={hideHeader}
|
hideHeader={hideHeader}
|
||||||
muteStates={muteStates}
|
muteStates={muteStates}
|
||||||
e2eeConfig={e2eeConfig}
|
e2eeSystem={e2eeSystem}
|
||||||
//otelGroupCallMembership={otelGroupCallMembership}
|
//otelGroupCallMembership={otelGroupCallMembership}
|
||||||
onShareClick={onShareClick}
|
onShareClick={onShareClick}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ import { OTelGroupCallMembership } from "../otel/OTelGroupCallMembership";
|
|||||||
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
|
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
|
||||||
import { useRageshakeRequestModal } from "../settings/submit-rageshake";
|
import { useRageshakeRequestModal } from "../settings/submit-rageshake";
|
||||||
import { RageshakeRequestModal } from "./RageshakeRequestModal";
|
import { RageshakeRequestModal } from "./RageshakeRequestModal";
|
||||||
import { E2EEConfig, useLiveKit } from "../livekit/useLiveKit";
|
import { useLiveKit } from "../livekit/useLiveKit";
|
||||||
import { useFullscreen } from "./useFullscreen";
|
import { useFullscreen } from "./useFullscreen";
|
||||||
import { useLayoutStates } from "../video-grid/Layout";
|
import { useLayoutStates } from "../video-grid/Layout";
|
||||||
import { useWakeLock } from "../useWakeLock";
|
import { useWakeLock } from "../useWakeLock";
|
||||||
@@ -76,13 +76,15 @@ import { ECConnectionState } from "../livekit/useECConnectionState";
|
|||||||
import { useOpenIDSFU } from "../livekit/openIDSFU";
|
import { useOpenIDSFU } from "../livekit/openIDSFU";
|
||||||
import { useCallViewModel } from "../state/CallViewModel";
|
import { useCallViewModel } from "../state/CallViewModel";
|
||||||
import { subscribe } from "../state/subscribe";
|
import { subscribe } from "../state/subscribe";
|
||||||
|
import { EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
|
|
||||||
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
|
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
|
||||||
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||||
|
|
||||||
export interface ActiveCallProps
|
export interface ActiveCallProps
|
||||||
extends Omit<InCallViewProps, "livekitRoom" | "connState"> {
|
extends Omit<InCallViewProps, "livekitRoom" | "connState"> {
|
||||||
e2eeConfig: E2EEConfig;
|
e2eeSystem: EncryptionSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActiveCall: FC<ActiveCallProps> = (props) => {
|
export const ActiveCall: FC<ActiveCallProps> = (props) => {
|
||||||
@@ -91,7 +93,7 @@ export const ActiveCall: FC<ActiveCallProps> = (props) => {
|
|||||||
props.rtcSession,
|
props.rtcSession,
|
||||||
props.muteStates,
|
props.muteStates,
|
||||||
sfuConfig,
|
sfuConfig,
|
||||||
props.e2eeConfig,
|
props.e2eeSystem,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -238,7 +240,7 @@ export const InCallView: FC<InCallViewProps> = subscribe(
|
|||||||
const vm = useCallViewModel(
|
const vm = useCallViewModel(
|
||||||
rtcSession.room,
|
rtcSession.room,
|
||||||
livekitRoom,
|
livekitRoom,
|
||||||
matrixInfo.roomEncrypted,
|
matrixInfo.e2eeSystem.kind !== E2eeType.NONE,
|
||||||
connState,
|
connState,
|
||||||
);
|
);
|
||||||
const items = useStateObservable(vm.tiles);
|
const items = useStateObservable(vm.tiles);
|
||||||
@@ -432,7 +434,7 @@ export const InCallView: FC<InCallViewProps> = subscribe(
|
|||||||
id={matrixInfo.roomId}
|
id={matrixInfo.roomId}
|
||||||
name={matrixInfo.roomName}
|
name={matrixInfo.roomName}
|
||||||
avatarUrl={matrixInfo.roomAvatar}
|
avatarUrl={matrixInfo.roomAvatar}
|
||||||
encrypted={matrixInfo.roomEncrypted}
|
encrypted={matrixInfo.e2eeSystem.kind !== E2eeType.NONE}
|
||||||
participantCount={participantCount}
|
participantCount={participantCount}
|
||||||
/>
|
/>
|
||||||
</LeftNav>
|
</LeftNav>
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import useClipboard from "react-use-clipboard";
|
|||||||
import { Modal } from "../Modal";
|
import { Modal } from "../Modal";
|
||||||
import { getAbsoluteRoomUrl } from "../matrix-utils";
|
import { getAbsoluteRoomUrl } from "../matrix-utils";
|
||||||
import styles from "./InviteModal.module.css";
|
import styles from "./InviteModal.module.css";
|
||||||
import { useRoomSharedKey } from "../e2ee/sharedKeyManagement";
|
|
||||||
import { Toast } from "../Toast";
|
import { Toast } from "../Toast";
|
||||||
|
import { useRoomEncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
room: Room;
|
room: Room;
|
||||||
@@ -36,11 +36,11 @@ interface Props {
|
|||||||
|
|
||||||
export const InviteModal: FC<Props> = ({ room, open, onDismiss }) => {
|
export const InviteModal: FC<Props> = ({ room, open, onDismiss }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const roomSharedKey = useRoomSharedKey(room.roomId);
|
const e2eeSystem = useRoomEncryptionSystem(room.roomId);
|
||||||
|
|
||||||
const url = useMemo(
|
const url = useMemo(
|
||||||
() =>
|
() => getAbsoluteRoomUrl(room.roomId, e2eeSystem, room.name),
|
||||||
getAbsoluteRoomUrl(room.roomId, room.name, roomSharedKey ?? undefined),
|
[e2eeSystem, room.name, room.roomId],
|
||||||
[room, roomSharedKey],
|
|
||||||
);
|
);
|
||||||
const [, setCopied] = useClipboard(url);
|
const [, setCopied] = useClipboard(url);
|
||||||
const [toastOpen, setToastOpen] = useState(false);
|
const [toastOpen, setToastOpen] = useState(false);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
} from "../button/Button";
|
} from "../button/Button";
|
||||||
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
|
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
|
||||||
import { useMediaQuery } from "../useMediaQuery";
|
import { useMediaQuery } from "../useMediaQuery";
|
||||||
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
client: MatrixClient;
|
client: MatrixClient;
|
||||||
@@ -104,7 +105,7 @@ export const LobbyView: FC<Props> = ({
|
|||||||
id={matrixInfo.roomId}
|
id={matrixInfo.roomId}
|
||||||
name={matrixInfo.roomName}
|
name={matrixInfo.roomName}
|
||||||
avatarUrl={matrixInfo.roomAvatar}
|
avatarUrl={matrixInfo.roomAvatar}
|
||||||
encrypted={matrixInfo.roomEncrypted}
|
encrypted={matrixInfo.e2eeSystem.kind !== E2eeType.NONE}
|
||||||
participantCount={participantCount}
|
participantCount={participantCount}
|
||||||
/>
|
/>
|
||||||
</LeftNav>
|
</LeftNav>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import styles from "./VideoPreview.module.css";
|
|||||||
import { useMediaDevices } from "../livekit/MediaDevicesContext";
|
import { useMediaDevices } from "../livekit/MediaDevicesContext";
|
||||||
import { MuteStates } from "./MuteStates";
|
import { MuteStates } from "./MuteStates";
|
||||||
import { useMediaQuery } from "../useMediaQuery";
|
import { useMediaQuery } from "../useMediaQuery";
|
||||||
|
import { EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
|
|
||||||
export type MatrixInfo = {
|
export type MatrixInfo = {
|
||||||
userId: string;
|
userId: string;
|
||||||
@@ -41,7 +42,7 @@ export type MatrixInfo = {
|
|||||||
roomName: string;
|
roomName: string;
|
||||||
roomAlias: string | null;
|
roomAlias: string | null;
|
||||||
roomAvatar: string | null;
|
roomAvatar: string | null;
|
||||||
roomEncrypted: boolean;
|
e2eeSystem: EncryptionSystem;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ export const WaitForInviteView: FC<Props> = ({
|
|||||||
[setSettingsModalOpen],
|
[setSettingsModalOpen],
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Unify this component with InCallView, so we can get slick joining
|
|
||||||
// animations and don't have to feel bad about reusing its CSS
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classNames(styles.room, inCallStyles.inRoom)}>
|
<div className={classNames(styles.room, inCallStyles.inRoom)}>
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ export const widget = ((): WidgetHelpers | null => {
|
|||||||
];
|
];
|
||||||
const receiveState = [
|
const receiveState = [
|
||||||
{ eventType: EventType.RoomMember },
|
{ eventType: EventType.RoomMember },
|
||||||
|
{ eventType: EventType.RoomEncryption },
|
||||||
{ eventType: EventType.GroupCallPrefix },
|
{ eventType: EventType.GroupCallPrefix },
|
||||||
{ eventType: EventType.GroupCallMemberPrefix },
|
{ eventType: EventType.GroupCallMemberPrefix },
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user