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

@@ -1493,7 +1493,7 @@ describe("<MatrixChat />", () => {
};
const enabledMobileRegistration = (): void => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any => {
if (settingName === "Registration.mobileRegistrationHelper") return true;
if (settingName === UIFeature.Registration) return true;
});

View File

@@ -303,8 +303,8 @@ describe("TimelinePanel", () => {
client.isVersionSupported.mockResolvedValue(true);
client.doesServerSupportUnstableFeature.mockResolvedValue(true);
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string) => {
if (setting === "sendReadReceipt") return false;
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting: string): any => {
if (setting === "sendReadReceipts") return false;
return undefined;
});

View File

@@ -14,13 +14,14 @@ import { shouldShowFeedback } from "../../../../../src/utils/Feedback";
import BetaCard from "../../../../../src/components/views/beta/BetaCard";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { TranslationKey } from "../../../../../src/languageHandler";
import { FeatureSettingKey } from "../../../../../src/settings/Settings.tsx";
jest.mock("../../../../../src/utils/Feedback");
jest.mock("../../../../../src/settings/SettingsStore");
describe("<BetaCard />", () => {
describe("Feedback prompt", () => {
const featureId = "featureId";
const featureId = "featureId" as FeatureSettingKey;
beforeEach(() => {
mocked(SettingsStore).getBetaInfo.mockReturnValue({

View File

@@ -27,6 +27,7 @@ import {
import { UIFeature } from "../../../../../src/settings/UIFeature";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import { SdkContextClass } from "../../../../../src/contexts/SDKContext";
import { FeatureSettingKey } from "../../../../../src/settings/Settings.tsx";
mockPlatformPeg({
supportsSpellCheckSettings: jest.fn().mockReturnValue(false),
@@ -111,13 +112,13 @@ describe("<UserSettingsDialog />", () => {
});
it("renders ignored users tab when feature_mjolnir is enabled", () => {
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === "feature_mjolnir");
mockSettingsStore.getValue.mockImplementation((settingName) => settingName === "feature_mjolnir");
const { getByTestId } = render(getComponent());
expect(getByTestId(`settings-tab-${UserTab.Mjolnir}`)).toBeTruthy();
});
it("renders voip tab when voip is enabled", () => {
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.Voip);
mockSettingsStore.getValue.mockImplementation((settingName: any): any => settingName === UIFeature.Voip);
const { getByTestId } = render(getComponent());
expect(getByTestId(`settings-tab-${UserTab.Voice}`)).toBeTruthy();
});
@@ -165,7 +166,7 @@ describe("<UserSettingsDialog />", () => {
it("renders with voip tab selected", () => {
useMockMediaDevices();
mockSettingsStore.getValue.mockImplementation((settingName): any => settingName === UIFeature.Voip);
mockSettingsStore.getValue.mockImplementation((settingName: any): any => settingName === UIFeature.Voip);
const { container } = render(getComponent({ initialTabId: UserTab.Voice }));
expect(getActiveTabLabel(container)).toEqual("Voice & Video");
@@ -212,8 +213,11 @@ describe("<UserSettingsDialog />", () => {
});
it("renders labs tab when some feature is in beta", () => {
mockSettingsStore.getFeatureSettingNames.mockReturnValue(["feature_beta_setting", "feature_just_normal_labs"]);
mockSettingsStore.getBetaInfo.mockImplementation((settingName) =>
mockSettingsStore.getFeatureSettingNames.mockReturnValue([
"feature_beta_setting",
"feature_just_normal_labs",
] as unknown[] as FeatureSettingKey[]);
mockSettingsStore.getBetaInfo.mockImplementation((settingName: any) =>
settingName === "feature_beta_setting" ? ({} as any) : undefined,
);
const { getByTestId } = render(getComponent());

View File

@@ -66,11 +66,13 @@ describe("MessageComposer", () => {
// restore settings
act(() => {
[
"MessageComposerInput.showStickersButton",
"MessageComposerInput.showPollsButton",
"feature_wysiwyg_composer",
].forEach((setting: string): void => {
(
[
"MessageComposerInput.showStickersButton",
"MessageComposerInput.showPollsButton",
"feature_wysiwyg_composer",
] as const
).forEach((setting): void => {
SettingsStore.setValue(setting, null, SettingLevel.DEVICE, SettingsStore.getDefaultValue(setting));
});
});
@@ -188,11 +190,11 @@ describe("MessageComposer", () => {
// test button display depending on settings
[
{
setting: "MessageComposerInput.showStickersButton",
setting: "MessageComposerInput.showStickersButton" as const,
buttonLabel: "Sticker",
},
{
setting: "MessageComposerInput.showPollsButton",
setting: "MessageComposerInput.showPollsButton" as const,
buttonLabel: "Poll",
},
].forEach(({ setting, buttonLabel }) => {

View File

@@ -176,7 +176,7 @@ describe("RoomHeader", () => {
});
it("opens the notifications panel", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "feature_notifications") return true;
});

View File

@@ -44,7 +44,7 @@ describe("RoomPreviewCard", () => {
client.reEmitter.reEmit(room, [RoomStateEvent.Events]);
enabledFeatures = [];
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) =>
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName): any =>
enabledFeatures.includes(settingName) ? true : undefined,
);
});

View File

@@ -419,7 +419,7 @@ describe("WysiwygComposer", () => {
const onChange = jest.fn();
const onSend = jest.fn();
beforeEach(async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "MessageComposerInput.autoReplaceEmoji") return true;
});
customRender(onChange, onSend);
@@ -455,7 +455,7 @@ describe("WysiwygComposer", () => {
const onChange = jest.fn();
const onSend = jest.fn();
beforeEach(async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name): any => {
if (name === "MessageComposerInput.ctrlEnterToSend") return true;
});
customRender(onChange, onSend);

View File

@@ -57,7 +57,7 @@ describe("<LayoutSwitcher />", () => {
act(() => screen.getByRole("radio", { name: "Message bubbles" }).click());
expect(screen.getByRole("radio", { name: "Message bubbles" })).toBeChecked();
await waitFor(() => expect(SettingsStore.getValue<boolean>("layout")).toBe(Layout.Bubble));
await waitFor(() => expect(SettingsStore.getValue("layout")).toBe(Layout.Bubble));
});
});
@@ -77,7 +77,7 @@ describe("<LayoutSwitcher />", () => {
await renderLayoutSwitcher();
act(() => screen.getByRole("checkbox", { name: "Show compact text and messages" }).click());
await waitFor(() => expect(SettingsStore.getValue<boolean>("useCompactLayout")).toBe(true));
await waitFor(() => expect(SettingsStore.getValue("useCompactLayout")).toBe(true));
});
it("should be disabled when the modern layout is not enabled", async () => {

View File

@@ -40,7 +40,7 @@ describe("DiscoverySettings", () => {
const DiscoveryWrapper = (props = {}) => <MatrixClientContext.Provider value={client} {...props} />;
it("is empty if 3pid features are disabled", async () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((key) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((key: any): any => {
if (key === UIFeature.ThirdPartyID) return false;
});

View File

@@ -69,7 +69,7 @@ describe("RolesRoomSettingsTab", () => {
describe("Element Call", () => {
const setGroupCallsEnabled = (val: boolean): void => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string): any => {
if (name === "feature_group_calls") return val;
});
};

View File

@@ -17,6 +17,7 @@ import SettingsStore from "../../../../../../../src/settings/SettingsStore";
import { SettingLevel } from "../../../../../../../src/settings/SettingLevel";
import MatrixClientBackedController from "../../../../../../../src/settings/controllers/MatrixClientBackedController";
import PlatformPeg from "../../../../../../../src/PlatformPeg";
import { SettingKey } from "../../../../../../../src/settings/Settings.tsx";
describe("PreferencesUserSettingsTab", () => {
beforeEach(() => {
@@ -121,13 +122,13 @@ describe("PreferencesUserSettingsTab", () => {
const mockGetValue = (val: boolean) => {
const copyOfGetValueAt = SettingsStore.getValueAt;
SettingsStore.getValueAt = <T,>(
SettingsStore.getValueAt = (
level: SettingLevel,
name: string,
name: SettingKey,
roomId?: string,
isExplicit?: boolean,
): T => {
if (name === "sendReadReceipts") return val as T;
) => {
if (name === "sendReadReceipts") return val;
return copyOfGetValueAt(level, name, roomId, isExplicit);
};
};

View File

@@ -19,6 +19,7 @@ import { populateThread } from "../../../../test-utils/threads";
import DMRoomMap from "../../../../../src/utils/DMRoomMap";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import { Features } from "../../../../../src/settings/Settings.tsx";
describe("ThreadsActivityCentre", () => {
const getTACButton = () => {
@@ -92,7 +93,7 @@ describe("ThreadsActivityCentre", () => {
});
beforeEach(async () => {
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, false);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, false);
});
it("should render the threads activity centre button", async () => {
@@ -102,7 +103,7 @@ describe("ThreadsActivityCentre", () => {
it("should render the release announcement", async () => {
// Enable release announcement
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
renderTAC();
expect(document.body).toMatchSnapshot();
@@ -110,7 +111,7 @@ describe("ThreadsActivityCentre", () => {
it("should render not display the tooltip when the release announcement is displayed", async () => {
// Enable release announcement
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
renderTAC();
@@ -121,7 +122,7 @@ describe("ThreadsActivityCentre", () => {
it("should close the release announcement when the TAC button is clicked", async () => {
// Enable release announcement
await SettingsStore.setValue("feature_release_announcement", null, SettingLevel.DEVICE, true);
await SettingsStore.setValue(Features.ReleaseAnnouncement, null, SettingLevel.DEVICE, true);
renderTAC();
await userEvent.click(getTACButton());