Compare commits

...

4 Commits

Author SHA1 Message Date
Timo K
de1c6ddb9a add skipLobby to params
Signed-off-by: Timo K <toger5@hotmail.de>
2023-09-24 22:51:20 +02:00
Timo K
275f843afc dont encrypt rooms with token login
Signed-off-by: Timo K <toger5@hotmail.de>
2023-09-24 20:25:29 +02:00
Timo K
560f0221fb Add homeserver to token login
Signed-off-by: Timo K <toger5@hotmail.de>
2023-09-24 19:42:42 +02:00
Timo K
48bbe613fe add url param token and skip login if provided
Signed-off-by: Timo K <toger5@hotmail.de>
2023-09-24 19:25:05 +02:00
5 changed files with 91 additions and 38 deletions

View File

@@ -44,6 +44,7 @@ import {
import { translatedError } from "./TranslatedError";
import { useEventTarget } from "./useEvents";
import { Config } from "./config/Config";
import { useUrlParams } from "./UrlParams";
declare global {
interface Window {
@@ -152,7 +153,7 @@ interface Props {
export const ClientProvider: FC<Props> = ({ children }) => {
const history = useHistory();
const { token, userId, deviceId, baseUrl } = useUrlParams();
// null = signed out, undefined = loading
const [initClientState, setInitClientState] = useState<
InitResult | null | undefined
@@ -165,12 +166,26 @@ export const ClientProvider: FC<Props> = ({ children }) => {
// the client.
if (initializing.current) return;
initializing.current = true;
const tokenLogin =
!token && !userId
? undefined
: ({
token,
userId,
deviceId,
homeserver: baseUrl,
} as {
token: string;
userId: string;
deviceId: string;
homeserver: string;
});
loadClient()
loadClient(tokenLogin)
.then(setInitClientState)
.catch((err) => logger.error(err))
.finally(() => (initializing.current = false));
}, []);
}, [token, userId, deviceId, baseUrl]);
const changePassword = useCallback(
async (password: string) => {
@@ -339,7 +354,12 @@ type InitResult = {
passwordlessUser: boolean;
};
async function loadClient(): Promise<InitResult | null> {
async function loadClient(tokenLogin?: {
token: string;
userId: string;
deviceId: string;
homeserver: string;
}): Promise<InitResult | null> {
if (widget) {
// We're inside a widget, so let's engage *matryoshka mode*
logger.log("Using a matryoshka client");
@@ -351,7 +371,15 @@ async function loadClient(): Promise<InitResult | null> {
} else {
// We're running as a standalone application
try {
const session = loadSession();
let session = loadSession();
if (tokenLogin) {
session = {
user_id: tokenLogin.userId,
device_id: tokenLogin.deviceId, //"TOKEN_DEVICE",
access_token: tokenLogin.token,
passwordlessUser: false,
};
}
if (!session) {
logger.log("No session stored; continuing without a client");
return null;
@@ -362,7 +390,7 @@ async function loadClient(): Promise<InitResult | null> {
/* eslint-disable camelcase */
const { user_id, device_id, access_token, passwordlessUser } = session;
const initClientParams = {
baseUrl: Config.defaultHomeserverUrl()!,
baseUrl: tokenLogin?.homeserver ?? Config.defaultHomeserverUrl()!,
accessToken: access_token,
userId: user_id,
deviceId: device_id,
@@ -371,7 +399,7 @@ async function loadClient(): Promise<InitResult | null> {
};
try {
const client = await initClient(initClientParams, true);
const client = await initClient(initClientParams, !tokenLogin);
return {
client,
passwordlessUser,

View File

@@ -108,6 +108,16 @@ interface UrlParams {
* E2EE password
*/
password: string | null;
/**
* Token for a user for instance login. This is used for bridge gosts.
*/
token: string | null;
/**
* Setting this flag skips the lobby and brings you in the call directly.
* In the widget this can be combined with preload to pass the device settings
* with the join widget action.
*/
skipLobby: boolean;
}
// This is here as a stopgap, but what would be far nicer is a function that
@@ -200,6 +210,8 @@ export const getUrlParams = (
fontScale: Number.isNaN(fontScale) ? null : fontScale,
analyticsID: parser.getParam("analyticsID"),
allowIceFallback: parser.getFlagParam("allowIceFallback"),
token: parser.getParam("token"),
skipLobby: parser.getFlagParam("skipLobby"),
};
};

View File

@@ -85,12 +85,17 @@ export const useManageRoomSharedKey = (roomId: string): string | null => {
export const useIsRoomE2EE = (roomId: string): boolean | null => {
const { client } = useClient();
const { token } = useUrlParams();
const isRoomForBridgedCall = !!token;
const room = useMemo(() => client?.getRoom(roomId) ?? null, [roomId, client]);
// 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]
() =>
!isRoomForBridgedCall &&
widget === null &&
(room === null || !room.getCanonicalAlias()),
[room, isRoomForBridgedCall]
);
};

View File

@@ -60,6 +60,7 @@ interface Props {
isPasswordlessUser: boolean;
confineToRoom: boolean;
preload: boolean;
skipLobby: boolean;
hideHeader: boolean;
rtcSession: MatrixRTCSession;
}
@@ -69,6 +70,7 @@ export function GroupCallView({
isPasswordlessUser,
confineToRoom,
preload,
skipLobby,
hideHeader,
rtcSession,
}: Props) {
@@ -133,18 +135,17 @@ export function GroupCallView({
latestMuteStates.current = muteStates;
useEffect(() => {
if (widget && preload) {
// In preload mode, wait for a join action before entering
const onJoin = async (ev: CustomEvent<IWidgetApiRequest>) => {
if (skipLobby) {
// widget && preload
const defaultDeviceSetup = async (
requestedDeviceData: JoinCallData
): Promise<void> => {
// XXX: I think this is broken currently - LiveKit *won't* request
// permissions and give you device names unless you specify a kind, but
// here we want all kinds of devices. This needs a fix in livekit-client
// for the following name-matching logic to do anything useful.
const devices = await Room.getLocalDevices(undefined, true);
const { audioInput, videoInput } = ev.detail
.data as unknown as JoinCallData;
const { audioInput, videoInput } = requestedDeviceData;
if (audioInput === null) {
latestMuteStates.current!.audio.setEnabled?.(false);
} else {
@@ -184,27 +185,27 @@ export function GroupCallView({
latestMuteStates.current!.video.setEnabled?.(true);
}
}
};
// In preload mode, wait for a join action before entering
if (widget && preload) {
const onJoin = async (ev: CustomEvent<IWidgetApiRequest>) => {
defaultDeviceSetup(ev.detail.data as unknown as JoinCallData);
enterRTCSession(rtcSession);
await Promise.all([
widget!.api.setAlwaysOnScreen(true),
widget!.api.transport.reply(ev.detail, {}),
]);
};
widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin);
return () => {
widget!.lazyActions.off(ElementWidgetActions.JoinCall, onJoin);
};
} else {
defaultDeviceSetup({ audioInput: null, videoInput: null });
enterRTCSession(rtcSession);
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
PosthogAnalytics.instance.eventCallStarted.track(
rtcSession.room.roomId
);
await Promise.all([
widget!.api.setAlwaysOnScreen(true),
widget!.api.transport.reply(ev.detail, {}),
]);
};
widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin);
return () => {
widget!.lazyActions.off(ElementWidgetActions.JoinCall, onJoin);
};
}
}
}, [rtcSession, preload]);
}, [rtcSession, preload, skipLobby]);
const [left, setLeft] = useState(false);
const [leaveError, setLeaveError] = useState<Error | undefined>(undefined);

View File

@@ -30,8 +30,14 @@ import { platform } from "../Platform";
import { AppSelectionModal } from "./AppSelectionModal";
export const RoomPage: FC = () => {
const { confineToRoom, appPrompt, preload, hideHeader, displayName } =
useUrlParams();
const {
confineToRoom,
appPrompt,
preload,
hideHeader,
displayName,
skipLobby,
} = useUrlParams();
const { roomAlias, roomId, viaServers } = useRoomIdentifier();
@@ -77,10 +83,11 @@ export const RoomPage: FC = () => {
isPasswordlessUser={passwordlessUser}
confineToRoom={confineToRoom}
preload={preload}
skipLobby={skipLobby}
hideHeader={hideHeader}
/>
),
[client, passwordlessUser, confineToRoom, preload, hideHeader]
[client, passwordlessUser, confineToRoom, preload, hideHeader, skipLobby]
);
let content: ReactNode;