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
+1 -1
View File
@@ -127,7 +127,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
};
private async updateRooms(): Promise<void> {
let roomIds = SettingsStore.getValue<string[]>("breadcrumb_rooms");
let roomIds = SettingsStore.getValue("breadcrumb_rooms");
if (!roomIds || roomIds.length === 0) roomIds = [];
const rooms = filterBoolean(roomIds.map((r) => this.matrixClient?.getRoom(r)));
+1 -1
View File
@@ -61,7 +61,7 @@ export class CallStore extends AsyncStoreWithClient<{}> {
// If the room ID of a previously connected call is still in settings at
// this time, that's a sign that we failed to disconnect from it
// properly, and need to clean up after ourselves
const uncleanlyDisconnectedRoomIds = SettingsStore.getValue<string[]>("activeCallRoomIds");
const uncleanlyDisconnectedRoomIds = SettingsStore.getValue("activeCallRoomIds");
if (uncleanlyDisconnectedRoomIds.length) {
await Promise.all([
...uncleanlyDisconnectedRoomIds.map(async (uncleanlyDisconnectedRoomId): Promise<void> => {
+5 -3
View File
@@ -26,7 +26,9 @@ export type Feature = (typeof FEATURES)[number];
* The stored settings for the release announcements.
* The boolean is at true when the user has viewed the feature
*/
type StoredSettings = Record<Feature, boolean>;
type StoredSettings = Partial<Record<Feature, boolean>>;
export type ReleaseAnnouncementData = StoredSettings;
/**
* The events emitted by the ReleaseAnnouncementStore.
@@ -82,7 +84,7 @@ export class ReleaseAnnouncementStore extends TypedEventEmitter<ReleaseAnnouncem
*/
private getViewedReleaseAnnouncements(): StoredSettings {
// Clone the settings to avoid to mutate the internal stored value in the SettingsStore
return cloneDeep(SettingsStore.getValue<StoredSettings>("releaseAnnouncementData"));
return cloneDeep(SettingsStore.getValue("releaseAnnouncementData"));
}
/**
@@ -90,7 +92,7 @@ export class ReleaseAnnouncementStore extends TypedEventEmitter<ReleaseAnnouncem
* @private
*/
private isReleaseAnnouncementEnabled(): boolean {
return SettingsStore.getValue<boolean>(Features.ReleaseAnnouncement);
return SettingsStore.getValue(Features.ReleaseAnnouncement);
}
/**
+5 -2
View File
@@ -252,10 +252,13 @@ export default class RightPanelStore extends ReadyWatchingStore {
const room = this.mxClient?.getRoom(this.viewedRoomId);
if (!!room) {
this.global =
this.global ?? convertToStatePanel(SettingsStore.getValue("RightPanel.phasesGlobal"), room);
this.global ??
convertToStatePanel(SettingsStore.getValue("RightPanel.phasesGlobal"), room) ??
undefined;
this.byRoom[this.viewedRoomId] =
this.byRoom[this.viewedRoomId] ??
convertToStatePanel(SettingsStore.getValue("RightPanel.phases", this.viewedRoomId), room);
convertToStatePanel(SettingsStore.getValue("RightPanel.phases", this.viewedRoomId), room) ??
undefined;
} else {
logger.warn(
"Could not restore the right panel after load because there was no associated room object.",
@@ -57,10 +57,10 @@ export interface IRightPanelForRoom {
history: Array<IRightPanelCard>;
}
interface IRightPanelForRoomStored {
export type IRightPanelForRoomStored = {
isOpen: boolean;
history: Array<IRightPanelCardStored>;
}
};
export function convertToStorePanel(cacheRoom?: IRightPanelForRoom): IRightPanelForRoomStored | undefined {
if (!cacheRoom) return undefined;
@@ -68,7 +68,7 @@ export function convertToStorePanel(cacheRoom?: IRightPanelForRoom): IRightPanel
return { isOpen: cacheRoom.isOpen, history: storeHistory };
}
export function convertToStatePanel(storeRoom: IRightPanelForRoomStored, room: Room): IRightPanelForRoom {
export function convertToStatePanel(storeRoom: IRightPanelForRoomStored | null, room: Room): IRightPanelForRoom | null {
if (!storeRoom) return storeRoom;
const stateHistory = [...storeRoom.history].map((panelStateStore) => convertStoreToCard(panelStateStore, room));
return { history: stateHistory, isOpen: storeRoom.isOpen };
+2 -2
View File
@@ -239,7 +239,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
if (!isMetaSpace(space)) {
cliSpace = this.matrixClient.getRoom(space);
if (!cliSpace?.isSpaceRoom()) return;
} else if (!this.enabledMetaSpaces.includes(space as MetaSpace)) {
} else if (!this.enabledMetaSpaces.includes(space)) {
return;
}
@@ -1178,7 +1178,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
}
// restore selected state from last session if any and still valid
const lastSpaceId = window.localStorage.getItem(ACTIVE_SPACE_LS_KEY);
const lastSpaceId = window.localStorage.getItem(ACTIVE_SPACE_LS_KEY) as MetaSpace;
const valid =
lastSpaceId &&
(!isMetaSpace(lastSpaceId) ? this.matrixClient.getRoom(lastSpaceId) : enabledMetaSpaces[lastSpaceId]);
+1 -1
View File
@@ -48,7 +48,7 @@ export interface ISuggestedRoom extends HierarchyRoom {
viaServers: string[];
}
export function isMetaSpace(spaceKey?: SpaceKey): boolean {
export function isMetaSpace(spaceKey?: SpaceKey): spaceKey is MetaSpace {
return (
spaceKey === MetaSpace.Home ||
spaceKey === MetaSpace.Favourites ||
+3 -3
View File
@@ -25,9 +25,9 @@ import { Container, IStoredLayout, ILayoutStateEvent, WIDGET_LAYOUT_EVENT_TYPE,
export type { IStoredLayout, ILayoutStateEvent };
export { Container, WIDGET_LAYOUT_EVENT_TYPE };
interface ILayoutSettings extends ILayoutStateEvent {
export type ILayoutSettings = Partial<ILayoutStateEvent> & {
overrides?: string; // event ID for layout state event, if present
}
};
// Dev note: "Pinned" widgets are ones in the top container.
export const MAX_PINNED = 3;
@@ -149,7 +149,7 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
const layoutEv = room.currentState.getStateEvents(WIDGET_LAYOUT_EVENT_TYPE, "");
const legacyPinned = SettingsStore.getValue("Widgets.pinned", room.roomId);
let userLayout = SettingsStore.getValue<ILayoutSettings | null>("Widgets.layout", room.roomId);
let userLayout = SettingsStore.getValue("Widgets.layout", room.roomId);
if (layoutEv && userLayout && userLayout.overrides !== layoutEv.getId()) {
// For some other layout that we don't really care about. The user can reset this
+1 -4
View File
@@ -53,10 +53,7 @@ export class WidgetPermissionStore {
public setOIDCState(widget: Widget, kind: WidgetKind, roomId: string | undefined, newState: OIDCState): void {
const settingsKey = this.packSettingKey(widget, kind, roomId);
let currentValues = SettingsStore.getValue<{
allow?: string[];
deny?: string[];
}>("widgetOpenIDPermissions");
let currentValues = SettingsStore.getValue("widgetOpenIDPermissions");
if (!currentValues) {
currentValues = {};
}