From 6e786d6cd54f3654ad5460d8a5d5f743e7652795 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Mon, 13 Jun 2022 08:03:16 +0200 Subject: [PATCH] Prevent level order to be modified (#8821) (cherry picked from commit b87c53788501eb84b913caf61fa04ce1645c9e70) --- src/settings/SettingsStore.ts | 5 ++- test/settings/SettingsStore-test.ts | 61 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 test/settings/SettingsStore-test.ts diff --git a/src/settings/SettingsStore.ts b/src/settings/SettingsStore.ts index 4f81ad3be6..b0d2bb75f3 100644 --- a/src/settings/SettingsStore.ts +++ b/src/settings/SettingsStore.ts @@ -80,7 +80,8 @@ export const LEVEL_ORDER = [ function getLevelOrder(setting: ISetting): SettingLevel[] { // Settings which support only a single setting level are inherently ordered if (setting.supportedLevelsAreOrdered || setting.supportedLevels.length === 1) { - return setting.supportedLevels; + // return a copy to prevent callers from modifying the array + return [...setting.supportedLevels]; } return LEVEL_ORDER; } @@ -359,7 +360,7 @@ export default class SettingsStore { if (!levelOrder.includes(SettingLevel.DEFAULT)) levelOrder.push(SettingLevel.DEFAULT); // always include default const minIndex = levelOrder.indexOf(level); - if (minIndex === -1) throw new Error("Level " + level + " is not prioritized"); + if (minIndex === -1) throw new Error(`Level "${level}" for setting "${settingName}" is not prioritized`); const handlers = SettingsStore.getHandlers(settingName); diff --git a/test/settings/SettingsStore-test.ts b/test/settings/SettingsStore-test.ts new file mode 100644 index 0000000000..e35f2a25b1 --- /dev/null +++ b/test/settings/SettingsStore-test.ts @@ -0,0 +1,61 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +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 BasePlatform from "../../src/BasePlatform"; +import { SettingLevel } from "../../src/settings/SettingLevel"; +import SettingsStore from "../../src/settings/SettingsStore"; +import { mockPlatformPeg } from "../test-utils"; + +const TEST_DATA = [ + { + name: "Electron.showTrayIcon", + level: SettingLevel.PLATFORM, + value: true, + }, +]; + +describe("SettingsStore", () => { + let platformSettings: object; + + beforeAll(() => { + jest.clearAllMocks(); + platformSettings = {}; + mockPlatformPeg({ + isLevelSupported: jest.fn().mockReturnValue(true), + supportsSetting: jest.fn().mockReturnValue(true), + setSettingValue: jest.fn().mockImplementation((settingName: string, value: any) => { + platformSettings[settingName] = value; + }), + getSettingValue: jest.fn().mockImplementation((settingName: string) => { + return platformSettings[settingName]; + }), + } as unknown as BasePlatform); + + TEST_DATA.forEach(d => { + SettingsStore.setValue(d.name, null, d.level, d.value); + }); + }); + + describe("getValueAt", () => { + TEST_DATA.forEach(d => { + it(`should return the value "${d.level}"."${d.name}"`, () => { + expect(SettingsStore.getValueAt(d.level, d.name)).toBe(d.value); + // regression test #22545 + expect(SettingsStore.getValueAt(d.level, d.name)).toBe(d.value); + }); + }); + }); +});