From a701e3afd76a57bf858409683929d10b774e486f Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 11 Sep 2024 21:55:00 +0100 Subject: [PATCH] Add config option to force verification (#29) * Add config option to force verification If this is set, users will not have the option to skip verification on login (they will still be able to reload and continue unverified, currently). Default off. * Test for complete security dialog * I hadn't set up prettier --- src/IConfigOptions.ts | 2 + .../structures/auth/CompleteSecurity.tsx | 5 +- .../structures/auth/CompleteSecurity-test.tsx | 79 +++++++++++++++++++ test/test-utils/test-utils.ts | 2 + 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 test/components/structures/auth/CompleteSecurity-test.tsx diff --git a/src/IConfigOptions.ts b/src/IConfigOptions.ts index 97346641ec..72bee5d0ab 100644 --- a/src/IConfigOptions.ts +++ b/src/IConfigOptions.ts @@ -52,6 +52,8 @@ export interface IConfigOptions { auth_footer_links?: { text: string; url: string }[]; }; + force_verification?: boolean; // if true, users must verify new logins + map_style_url?: string; // for location-shared maps embedded_pages?: { diff --git a/src/components/structures/auth/CompleteSecurity.tsx b/src/components/structures/auth/CompleteSecurity.tsx index eb3ae3f592..568b7bffbd 100644 --- a/src/components/structures/auth/CompleteSecurity.tsx +++ b/src/components/structures/auth/CompleteSecurity.tsx @@ -14,6 +14,7 @@ import SetupEncryptionBody from "./SetupEncryptionBody"; import AccessibleButton from "../../views/elements/AccessibleButton"; import CompleteSecurityBody from "../../views/auth/CompleteSecurityBody"; import AuthPage from "../../views/auth/AuthPage"; +import SdkConfig from "../../../SdkConfig"; interface IProps { onFinished: () => void; @@ -82,8 +83,10 @@ export default class CompleteSecurity extends React.Component { throw new Error(`Unknown phase ${phase}`); } + const forceVerification = SdkConfig.get("force_verification") ?? false; + let skipButton; - if (phase === Phase.Intro || phase === Phase.ConfirmReset) { + if (!forceVerification && (phase === Phase.Intro || phase === Phase.ConfirmReset)) { skipButton = ( void = jest.fn(); + public stop: () => void = jest.fn(); +} + +describe("CompleteSecurity", () => { + beforeEach(() => { + const client = stubClient(); + const deviceIdToDevice = new Map(); + deviceIdToDevice.set("DEVICE_ID", { + deviceId: "DEVICE_ID", + userId: "USER_ID", + }); + const userIdToDevices = new Map(); + userIdToDevices.set("USER_ID", deviceIdToDevice); + mocked(client.getCrypto()!.getUserDeviceInfo).mockResolvedValue(userIdToDevices); + + const mockSetupEncryptionStore = new MockSetupEncryptionStore(); + jest.spyOn(SetupEncryptionStore, "sharedInstance").mockReturnValue( + mockSetupEncryptionStore as SetupEncryptionStore, + ); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it("Renders with a cancel button by default", () => { + render( {}} />); + + expect(screen.getByRole("button", { name: "Skip verification for now" })).toBeInTheDocument(); + }); + + it("Renders with a cancel button if forceVerification false", () => { + jest.spyOn(SdkConfig, "get").mockImplementation((key: string) => { + if (key === "forceVerification") { + return false; + } + }); + + render( {}} />); + + expect(screen.getByRole("button", { name: "Skip verification for now" })).toBeInTheDocument(); + }); + + it("Renders without a cancel button if forceVerification true", () => { + jest.spyOn(SdkConfig, "get").mockImplementation((key: string) => { + if (key === "force_verification") { + return true; + } + }); + + render( {}} />); + + expect(screen.queryByRole("button", { name: "Skip verification for now" })).not.toBeInTheDocument(); + }); +}); diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 8e82c298e4..092f30fb52 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -108,6 +108,7 @@ export function createTestClient(): MatrixClient { secretStorage: { get: jest.fn(), + isStored: jest.fn().mockReturnValue(false), }, store: { @@ -128,6 +129,7 @@ export function createTestClient(): MatrixClient { getDeviceVerificationStatus: jest.fn(), resetKeyBackup: jest.fn(), isEncryptionEnabledInRoom: jest.fn(), + getVerificationRequestsToDeviceInProgress: jest.fn().mockReturnValue([]), }), getPushActionsForEvent: jest.fn(),