Save room shared keys to local storage
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
@@ -20,7 +20,7 @@ import { MatrixClient } from "matrix-js-sdk";
|
||||
import { Buffer } from "buffer";
|
||||
|
||||
import { widget } from "../widget";
|
||||
import { getSetting, setSetting, settingsBus } from "../settings/useSetting";
|
||||
import { getSetting, setSetting, getSettingKey } from "../settings/useSetting";
|
||||
import {
|
||||
CallEndedTracker,
|
||||
CallStartedTracker,
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
} from "./PosthogEvents";
|
||||
import { Config } from "../config/Config";
|
||||
import { getUrlParams } from "../UrlParams";
|
||||
import { localStorageBus } from "../useLocalStorage";
|
||||
|
||||
/* Posthog analytics tracking.
|
||||
*
|
||||
@@ -413,7 +414,7 @@ export class PosthogAnalytics {
|
||||
// * When the user changes their preferences on this device
|
||||
// Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings
|
||||
// won't be called (i.e. this.anonymity will be left as the default, until the setting changes)
|
||||
settingsBus.on("opt-in-analytics", (optInAnalytics) => {
|
||||
localStorageBus.on(getSettingKey("opt-in-analytics"), (optInAnalytics) => {
|
||||
this.updateAnonymityAndIdentifyUser(optInAnalytics);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,7 +14,27 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { useSetting } from "../settings/useSetting";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { randomString } from "matrix-js-sdk/src/randomstring";
|
||||
|
||||
export const useRoomSharedKey = (roomId: string, initialValue?: string) =>
|
||||
useSetting(`room-shared-key-${roomId}`, initialValue);
|
||||
import { useEnableE2EE } from "../settings/useSetting";
|
||||
import { useLocalStorage } from "../useLocalStorage";
|
||||
|
||||
const getRoomSharedKeyLocalStorageKey = (roomId: string): string =>
|
||||
`room-shared-key-${roomId}`;
|
||||
|
||||
export const useRoomSharedKey = (
|
||||
roomId: string
|
||||
): [string | null, ((value: string) => void) | null] => {
|
||||
const key = useMemo(() => getRoomSharedKeyLocalStorageKey(roomId), [roomId]);
|
||||
const [e2eeEnabled] = useEnableE2EE();
|
||||
const [roomSharedKey, setRoomSharedKey] = useLocalStorage(key);
|
||||
|
||||
useEffect(() => {
|
||||
if ((roomSharedKey && roomSharedKey !== "") || !e2eeEnabled) return;
|
||||
|
||||
setRoomSharedKey(randomString(32));
|
||||
}, [roomSharedKey, e2eeEnabled, setRoomSharedKey]);
|
||||
|
||||
return e2eeEnabled ? [roomSharedKey, setRoomSharedKey] : [null, null];
|
||||
};
|
||||
|
||||
@@ -109,7 +109,7 @@ function CallTile({
|
||||
<CopyButton
|
||||
className={styles.copyButton}
|
||||
variant="icon"
|
||||
value={getRoomUrl(roomAlias, roomSharedKey)}
|
||||
value={getRoomUrl(roomAlias, roomSharedKey ?? undefined)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -245,14 +245,13 @@ export function GroupCallView({
|
||||
}, [groupCall, state, leave]);
|
||||
|
||||
const [e2eeSharedKey, setE2EESharedKey] = useRoomSharedKey(
|
||||
groupCall.room.roomId,
|
||||
password ?? undefined
|
||||
groupCall.room.roomId
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!password || password === e2eeSharedKey) return;
|
||||
if (!password || password === "" || password === e2eeSharedKey) return;
|
||||
|
||||
setE2EESharedKey(password);
|
||||
setE2EESharedKey?.(password);
|
||||
}, [password, e2eeSharedKey, setE2EESharedKey]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
Copyright 2022 - 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.
|
||||
@@ -14,59 +14,49 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from "events";
|
||||
import { useMemo, useState, useEffect, useCallback } from "react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { isE2EESupported } from "livekit-client";
|
||||
|
||||
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
||||
import {
|
||||
getLocalStorageItem,
|
||||
setLocalStorageItem,
|
||||
useLocalStorage,
|
||||
} from "../useLocalStorage";
|
||||
|
||||
type Setting<T> = [T, (value: T) => void];
|
||||
type DisableableSetting<T> = [T, ((value: T) => void) | null];
|
||||
|
||||
// Bus to notify other useSetting consumers when a setting is changed
|
||||
export const settingsBus = new EventEmitter();
|
||||
|
||||
const getSettingKey = (name: string): string => {
|
||||
export const getSettingKey = (name: string): string => {
|
||||
return `matrix-setting-${name}`;
|
||||
};
|
||||
// Like useState, but reads from and persists the value to localStorage
|
||||
export const useSetting = <T>(name: string, defaultValue: T): Setting<T> => {
|
||||
const key = useMemo(() => getSettingKey(name), [name]);
|
||||
|
||||
const [value, setValue] = useState<T>(() => {
|
||||
const item = localStorage.getItem(key);
|
||||
return item == null ? defaultValue : JSON.parse(item);
|
||||
});
|
||||
const [item, setItem] = useLocalStorage(key);
|
||||
|
||||
useEffect(() => {
|
||||
settingsBus.on(name, setValue);
|
||||
return () => {
|
||||
settingsBus.off(name, setValue);
|
||||
};
|
||||
}, [name, setValue]);
|
||||
const value = useMemo(
|
||||
() => (item == null ? defaultValue : JSON.parse(item)),
|
||||
[item, defaultValue]
|
||||
);
|
||||
const setValue = useCallback(
|
||||
(value: T) => {
|
||||
setItem(JSON.stringify(value));
|
||||
},
|
||||
[setItem]
|
||||
);
|
||||
|
||||
return [
|
||||
value,
|
||||
useCallback(
|
||||
(newValue: T) => {
|
||||
setValue(newValue);
|
||||
localStorage.setItem(key, JSON.stringify(newValue));
|
||||
settingsBus.emit(name, newValue);
|
||||
},
|
||||
[name, key, setValue]
|
||||
),
|
||||
];
|
||||
return [value, setValue];
|
||||
};
|
||||
|
||||
export const getSetting = <T>(name: string, defaultValue: T): T => {
|
||||
const item = localStorage.getItem(getSettingKey(name));
|
||||
const item = getLocalStorageItem(getSettingKey(name));
|
||||
return item === null ? defaultValue : JSON.parse(item);
|
||||
};
|
||||
|
||||
export const setSetting = <T>(name: string, newValue: T) => {
|
||||
localStorage.setItem(getSettingKey(name), JSON.stringify(newValue));
|
||||
settingsBus.emit(name, newValue);
|
||||
};
|
||||
export const setSetting = <T>(name: string, newValue: T) =>
|
||||
setLocalStorageItem(getSettingKey(name), JSON.stringify(newValue));
|
||||
|
||||
const canEnableSpatialAudio = () => {
|
||||
const { userAgent } = navigator;
|
||||
|
||||
59
src/useLocalStorage.ts
Normal file
59
src/useLocalStorage.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
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 EventEmitter from "events";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
type LocalStorageItem = ReturnType<typeof localStorage.getItem>;
|
||||
|
||||
// Bus to notify other useLocalStorage consumers when an item is changed
|
||||
export const localStorageBus = new EventEmitter();
|
||||
|
||||
// Like useState, but reads from and persists the value to localStorage
|
||||
export const useLocalStorage = (
|
||||
key: string
|
||||
): [LocalStorageItem, (value: string) => void] => {
|
||||
const [value, setValue] = useState<LocalStorageItem>(() =>
|
||||
localStorage.getItem(key)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
localStorageBus.on(key, setValue);
|
||||
return () => {
|
||||
localStorageBus.off(key, setValue);
|
||||
};
|
||||
}, [key, setValue]);
|
||||
|
||||
return [
|
||||
value,
|
||||
useCallback(
|
||||
(newValue: string) => {
|
||||
setValue(newValue);
|
||||
localStorage.setItem(key, newValue);
|
||||
localStorageBus.emit(key, newValue);
|
||||
},
|
||||
[key, setValue]
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
export const getLocalStorageItem = (key: string): LocalStorageItem =>
|
||||
localStorage.getItem(key);
|
||||
|
||||
export const setLocalStorageItem = (key: string, value: string): void => {
|
||||
localStorage.setItem(key, value);
|
||||
localStorageBus.emit(key, value);
|
||||
};
|
||||
Reference in New Issue
Block a user