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 { Buffer } from "buffer";
|
||||||
|
|
||||||
import { widget } from "../widget";
|
import { widget } from "../widget";
|
||||||
import { getSetting, setSetting, settingsBus } from "../settings/useSetting";
|
import { getSetting, setSetting, getSettingKey } from "../settings/useSetting";
|
||||||
import {
|
import {
|
||||||
CallEndedTracker,
|
CallEndedTracker,
|
||||||
CallStartedTracker,
|
CallStartedTracker,
|
||||||
@@ -34,6 +34,7 @@ import {
|
|||||||
} from "./PosthogEvents";
|
} from "./PosthogEvents";
|
||||||
import { Config } from "../config/Config";
|
import { Config } from "../config/Config";
|
||||||
import { getUrlParams } from "../UrlParams";
|
import { getUrlParams } from "../UrlParams";
|
||||||
|
import { localStorageBus } from "../useLocalStorage";
|
||||||
|
|
||||||
/* Posthog analytics tracking.
|
/* Posthog analytics tracking.
|
||||||
*
|
*
|
||||||
@@ -413,7 +414,7 @@ export class PosthogAnalytics {
|
|||||||
// * When the user changes their preferences on this device
|
// * When the user changes their preferences on this device
|
||||||
// Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings
|
// 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)
|
// 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);
|
this.updateAnonymityAndIdentifyUser(optInAnalytics);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,27 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
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) =>
|
import { useEnableE2EE } from "../settings/useSetting";
|
||||||
useSetting(`room-shared-key-${roomId}`, initialValue);
|
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
|
<CopyButton
|
||||||
className={styles.copyButton}
|
className={styles.copyButton}
|
||||||
variant="icon"
|
variant="icon"
|
||||||
value={getRoomUrl(roomAlias, roomSharedKey)}
|
value={getRoomUrl(roomAlias, roomSharedKey ?? undefined)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -245,14 +245,13 @@ export function GroupCallView({
|
|||||||
}, [groupCall, state, leave]);
|
}, [groupCall, state, leave]);
|
||||||
|
|
||||||
const [e2eeSharedKey, setE2EESharedKey] = useRoomSharedKey(
|
const [e2eeSharedKey, setE2EESharedKey] = useRoomSharedKey(
|
||||||
groupCall.room.roomId,
|
groupCall.room.roomId
|
||||||
password ?? undefined
|
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!password || password === e2eeSharedKey) return;
|
if (!password || password === "" || password === e2eeSharedKey) return;
|
||||||
|
|
||||||
setE2EESharedKey(password);
|
setE2EESharedKey?.(password);
|
||||||
}, [password, e2eeSharedKey, setE2EESharedKey]);
|
}, [password, e2eeSharedKey, setE2EESharedKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with 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.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EventEmitter } from "events";
|
import { useCallback, useMemo } from "react";
|
||||||
import { useMemo, useState, useEffect, useCallback } from "react";
|
|
||||||
import { isE2EESupported } from "livekit-client";
|
import { isE2EESupported } from "livekit-client";
|
||||||
|
|
||||||
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
||||||
|
import {
|
||||||
|
getLocalStorageItem,
|
||||||
|
setLocalStorageItem,
|
||||||
|
useLocalStorage,
|
||||||
|
} from "../useLocalStorage";
|
||||||
|
|
||||||
type Setting<T> = [T, (value: T) => void];
|
type Setting<T> = [T, (value: T) => void];
|
||||||
type DisableableSetting<T> = [T, ((value: T) => void) | null];
|
type DisableableSetting<T> = [T, ((value: T) => void) | null];
|
||||||
|
|
||||||
// Bus to notify other useSetting consumers when a setting is changed
|
export const getSettingKey = (name: string): string => {
|
||||||
export const settingsBus = new EventEmitter();
|
|
||||||
|
|
||||||
const getSettingKey = (name: string): string => {
|
|
||||||
return `matrix-setting-${name}`;
|
return `matrix-setting-${name}`;
|
||||||
};
|
};
|
||||||
// Like useState, but reads from and persists the value to localStorage
|
// Like useState, but reads from and persists the value to localStorage
|
||||||
export const useSetting = <T>(name: string, defaultValue: T): Setting<T> => {
|
export const useSetting = <T>(name: string, defaultValue: T): Setting<T> => {
|
||||||
const key = useMemo(() => getSettingKey(name), [name]);
|
const key = useMemo(() => getSettingKey(name), [name]);
|
||||||
|
|
||||||
const [value, setValue] = useState<T>(() => {
|
const [item, setItem] = useLocalStorage(key);
|
||||||
const item = localStorage.getItem(key);
|
|
||||||
return item == null ? defaultValue : JSON.parse(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
const value = useMemo(
|
||||||
settingsBus.on(name, setValue);
|
() => (item == null ? defaultValue : JSON.parse(item)),
|
||||||
return () => {
|
[item, defaultValue]
|
||||||
settingsBus.off(name, setValue);
|
);
|
||||||
};
|
const setValue = useCallback(
|
||||||
}, [name, setValue]);
|
(value: T) => {
|
||||||
|
setItem(JSON.stringify(value));
|
||||||
return [
|
|
||||||
value,
|
|
||||||
useCallback(
|
|
||||||
(newValue: T) => {
|
|
||||||
setValue(newValue);
|
|
||||||
localStorage.setItem(key, JSON.stringify(newValue));
|
|
||||||
settingsBus.emit(name, newValue);
|
|
||||||
},
|
},
|
||||||
[name, key, setValue]
|
[setItem]
|
||||||
),
|
);
|
||||||
];
|
|
||||||
|
return [value, setValue];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSetting = <T>(name: string, defaultValue: T): T => {
|
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);
|
return item === null ? defaultValue : JSON.parse(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setSetting = <T>(name: string, newValue: T) => {
|
export const setSetting = <T>(name: string, newValue: T) =>
|
||||||
localStorage.setItem(getSettingKey(name), JSON.stringify(newValue));
|
setLocalStorageItem(getSettingKey(name), JSON.stringify(newValue));
|
||||||
settingsBus.emit(name, newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const canEnableSpatialAudio = () => {
|
const canEnableSpatialAudio = () => {
|
||||||
const { userAgent } = navigator;
|
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