Harden Settings using mapped types (#28775)

* Harden Settings using mapped types

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix issues found during hardening

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove oidc native flow stale key

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski
2024-12-23 20:25:15 +00:00
committed by GitHub
parent 4e1bd69e4d
commit 1e42f28a69
90 changed files with 576 additions and 274 deletions

View File

@@ -17,7 +17,7 @@ import { filterBoolean } from "../../utils/arrays";
export const useRecentSearches = (): [Room[], () => void] => {
const [rooms, setRooms] = useState(() => {
const cli = MatrixClientPeg.safeGet();
const recents = SettingsStore.getValue<string[]>("SpotlightSearch.recentSearches", null);
const recents = SettingsStore.getValue("SpotlightSearch.recentSearches", null);
return filterBoolean(recents.map((r) => cli.getRoom(r)));
});

View File

@@ -55,7 +55,7 @@ export const usePublicRoomDirectory = (): {
const [updateQuery, updateResult] = useLatestResult<IRoomDirectoryOptions, IPublicRoomsChunkRoom[]>(setPublicRooms);
const showNsfwPublicRooms = useSettingValue<boolean>("SpotlightSearch.showNsfwPublicRooms");
const showNsfwPublicRooms = useSettingValue("SpotlightSearch.showNsfwPublicRooms");
async function initProtocols(): Promise<void> {
if (!MatrixClientPeg.get()) {

View File

@@ -10,14 +10,39 @@ import { useEffect, useState } from "react";
import SettingsStore from "../settings/SettingsStore";
import { SettingLevel } from "../settings/SettingLevel";
import { FeatureSettingKey, SettingKey, Settings } from "../settings/Settings.tsx";
// Hook to fetch the value of a setting and dynamically update when it changes
export const useSettingValue = <T>(settingName: string, roomId: string | null = null, excludeDefault = false): T => {
const [value, setValue] = useState(SettingsStore.getValue<T>(settingName, roomId, excludeDefault));
export function useSettingValue<S extends SettingKey>(
settingName: S,
roomId: string | null,
excludeDefault: true,
): Settings[S]["default"] | undefined;
export function useSettingValue<S extends SettingKey>(
settingName: S,
roomId?: string | null,
excludeDefault?: false,
): Settings[S]["default"];
export function useSettingValue<S extends SettingKey>(
settingName: S,
roomId: string | null = null,
excludeDefault = false,
): Settings[S]["default"] | undefined {
const [value, setValue] = useState(
// XXX: This seems naff but is needed to convince TypeScript that the overload is fine
excludeDefault
? SettingsStore.getValue(settingName, roomId, excludeDefault)
: SettingsStore.getValue(settingName, roomId, excludeDefault),
);
useEffect(() => {
const ref = SettingsStore.watchSetting(settingName, roomId, () => {
setValue(SettingsStore.getValue<T>(settingName, roomId, excludeDefault));
setValue(
// XXX: This seems naff but is needed to convince TypeScript that the overload is fine
excludeDefault
? SettingsStore.getValue(settingName, roomId, excludeDefault)
: SettingsStore.getValue(settingName, roomId, excludeDefault),
);
});
// clean-up
return () => {
@@ -26,7 +51,7 @@ export const useSettingValue = <T>(settingName: string, roomId: string | null =
}, [settingName, roomId, excludeDefault]);
return value;
};
}
/**
* Hook to fetch the value of a setting at a specific level and dynamically update when it changes
@@ -37,20 +62,18 @@ export const useSettingValue = <T>(settingName: string, roomId: string | null =
* @param explicit
* @param excludeDefault
*/
export const useSettingValueAt = <T>(
export const useSettingValueAt = <S extends SettingKey>(
level: SettingLevel,
settingName: string,
settingName: S,
roomId: string | null = null,
explicit = false,
excludeDefault = false,
): T => {
const [value, setValue] = useState(
SettingsStore.getValueAt<T>(level, settingName, roomId, explicit, excludeDefault),
);
): Settings[S]["default"] => {
const [value, setValue] = useState(SettingsStore.getValueAt(level, settingName, roomId, explicit, excludeDefault));
useEffect(() => {
const ref = SettingsStore.watchSetting(settingName, roomId, () => {
setValue(SettingsStore.getValueAt<T>(level, settingName, roomId, explicit, excludeDefault));
setValue(SettingsStore.getValueAt(level, settingName, roomId, explicit, excludeDefault));
});
// clean-up
return () => {
@@ -62,8 +85,8 @@ export const useSettingValueAt = <T>(
};
// Hook to fetch whether a feature is enabled and dynamically update when that changes
export const useFeatureEnabled = (featureName: string, roomId: string | null = null): boolean => {
const [enabled, setEnabled] = useState(SettingsStore.getValue<boolean>(featureName, roomId));
export const useFeatureEnabled = (featureName: FeatureSettingKey, roomId: string | null = null): boolean => {
const [enabled, setEnabled] = useState(SettingsStore.getValue(featureName, roomId));
useEffect(() => {
const ref = SettingsStore.watchSetting(featureName, roomId, () => {

View File

@@ -16,10 +16,10 @@ export function useTheme(): { theme: string; systemThemeActivated: boolean } {
// We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
// show the right values for things.
const themeChoice = useSettingValue<string>("theme");
const systemThemeExplicit = useSettingValueAt<string>(SettingLevel.DEVICE, "use_system_theme", null, false, true);
const themeExplicit = useSettingValueAt<string>(SettingLevel.DEVICE, "theme", null, false, true);
const systemThemeActivated = useSettingValue<boolean>("use_system_theme");
const themeChoice = useSettingValue("theme");
const systemThemeExplicit = useSettingValueAt(SettingLevel.DEVICE, "use_system_theme", null, false, true);
const themeExplicit = useSettingValueAt(SettingLevel.DEVICE, "theme", null, false, true);
const systemThemeActivated = useSettingValue("use_system_theme");
// If the user has enabled system theme matching, use that.
if (systemThemeExplicit) {

View File

@@ -145,7 +145,7 @@ const tasks: UserOnboardingTask[] = [
];
export function useUserOnboardingTasks(context: UserOnboardingContext): UserOnboardingTaskWithResolvedCompletion[] {
const useCase = useSettingValue<UseCase | null>("FTUE.useCaseSelection") ?? UseCase.Skip;
const useCase = useSettingValue("FTUE.useCaseSelection") ?? UseCase.Skip;
return useMemo<UserOnboardingTaskWithResolvedCompletion[]>(() => {
return tasks