Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Enable the rust-crypto labs button (#12114)
Browse files Browse the repository at this point in the history
* `LabsUserSettingsTab-test.tsx`: use a real `SdkConfig`

... instead of mocking it out. Doing so allows us more flexibility, and gives a
more realistic test.

* Enable the rust-crypto labs button

* fix up a test
  • Loading branch information
richvdh committed Jan 18, 2024
1 parent b64d2e7 commit b6364a4
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 20 deletions.
3 changes: 2 additions & 1 deletion src/MatrixClientPeg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import PlatformPeg from "./PlatformPeg";
import { formatList } from "./utils/FormattingUtils";
import SdkConfig from "./SdkConfig";
import { Features } from "./settings/Settings";

export interface IMatrixClientCreds {
homeserverUrl: string;
Expand Down Expand Up @@ -301,7 +302,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
throw new Error("createClient must be called first");
}

const useRustCrypto = SettingsStore.getValue("feature_rust_crypto");
const useRustCrypto = SettingsStore.getValue(Features.RustCrypto);

// we want to make sure that the same crypto implementation is used throughout the lifetime of a device,
// so persist the setting at the device layer
Expand Down
5 changes: 4 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,10 @@
"report_to_moderators": "Report to moderators",
"report_to_moderators_description": "In rooms that support moderation, the “Report” button will let you report abuse to room moderators.",
"rust_crypto": "Rust cryptography implementation",
"rust_crypto_disabled_notice": "Can currently only be enabled via config.json",
"rust_crypto_in_config": "Rust cryptography cannot be disabled on this deployment of %(brand)s",
"rust_crypto_in_config_description": "Switching to the Rust cryptography requires a migration process that may take several minutes. It cannot be disabled; use with caution!",
"rust_crypto_optin_warning": "Switching to the Rust cryptography requires a migration process that may take several minutes. To disable you will need to log out and back in; use with caution!",
"rust_crypto_requires_logout": "Once enabled, Rust cryptography can only be disabled by logging out and in again",
"sliding_sync": "Sliding Sync mode",
"sliding_sync_checking": "Checking…",
"sliding_sync_configuration": "Sliding Sync configuration",
Expand Down
19 changes: 14 additions & 5 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import RustCryptoSdkController from "./controllers/RustCryptoSdkController";
import ServerSupportUnstableFeatureController from "./controllers/ServerSupportUnstableFeatureController";
import { WatchManager } from "./WatchManager";
import { CustomTheme } from "../theme";
import SettingsStore from "./SettingsStore";

export const defaultWatchManager = new WatchManager();

Expand Down Expand Up @@ -94,6 +95,7 @@ export enum Features {
VoiceBroadcastForceSmallChunks = "feature_voice_broadcast_force_small_chunks",
NotificationSettings2 = "feature_notification_settings2",
OidcNativeFlow = "feature_oidc_native_flow",
RustCrypto = "feature_rust_crypto",
}

export const labGroupNames: Record<LabGroup, TranslationKey> = {
Expand Down Expand Up @@ -480,15 +482,22 @@ export const SETTINGS: { [setting: string]: ISetting } = {
description: _td("labs|oidc_native_flow_description"),
default: false,
},
"feature_rust_crypto": {
// use the rust matrix-sdk-crypto-js for crypto.
[Features.RustCrypto]: {
// use the rust matrix-sdk-crypto-wasm for crypto.
isFeature: true,
labsGroup: LabGroup.Developer,
configDisablesSetting: true,
// unlike most features, `configDisablesSetting` is false here.
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("labs|rust_crypto"),
description: _td("labs|under_active_development"),
// shouldWarn: true,
description: () => {
if (SettingsStore.getValueAt(SettingLevel.CONFIG, Features.RustCrypto)) {
// It's enabled in the config, so you can't get rid of it even by logging out.
return _t("labs|rust_crypto_in_config_description");
} else {
return _t("labs|rust_crypto_optin_warning");
}
},
shouldWarn: true,
default: false,
controller: new RustCryptoSdkController(),
},
Expand Down
29 changes: 26 additions & 3 deletions src/settings/controllers/RustCryptoSdkController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,35 @@ limitations under the License.
*/

import { _t } from "../../languageHandler";
import SettingsStore from "../SettingsStore";
import { SettingLevel } from "../SettingLevel";
import PlatformPeg from "../../PlatformPeg";
import SettingController from "./SettingController";
import { Features } from "../Settings";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import SdkConfig from "../../SdkConfig";

export default class RustCryptoSdkController extends SettingController {
public onChange(level: SettingLevel, roomId: string | null, newValue: any): void {
// If the crypto stack has already been initialized, we'll need to reload the app to make it take effect.
if (MatrixClientPeg.get()?.getCrypto()) {
PlatformPeg.get()?.reload();
}
}

public get settingDisabled(): boolean | string {
// Currently this can only be changed via config.json. In future, we'll allow the user to *enable* this setting
// via labs, which will migrate their existing device to the rust-sdk implementation.
return _t("labs|rust_crypto_disabled_notice");
if (!SettingsStore.getValueAt(SettingLevel.DEVICE, Features.RustCrypto)) {
// If rust crypto has not yet been enabled for this device, you can turn it on, IF YOU DARE
return false;
}

if (SettingsStore.getValueAt(SettingLevel.CONFIG, Features.RustCrypto)) {
// It's enabled in the config, so you can't get rid of it even by logging out.
return _t("labs|rust_crypto_in_config", { brand: SdkConfig.get().brand });
}

// The setting is enabled at the device level, but not mandated at the config level.
// You can only turn it off by logging out and in again.
return _t("labs|rust_crypto_requires_logout");
}
}
3 changes: 3 additions & 0 deletions test/MatrixClientPeg-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ describe("MatrixClientPeg", () => {
afterEach(() => {
localStorage.clear();
jest.restoreAllMocks();

// some of the tests assign `MatrixClientPeg.matrixClient`: clear it, to prevent leakage between tests
peg.unset();
});

it("setJustRegisteredUserId", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ limitations under the License.
*/

import React from "react";
import { render, screen } from "@testing-library/react";
import { fireEvent, render, screen } from "@testing-library/react";

import LabsUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/LabsUserSettingsTab";
import SettingsStore from "../../../../../../src/settings/SettingsStore";
import SdkConfig from "../../../../../../src/SdkConfig";
import { SettingLevel } from "../../../../../../src/settings/SettingLevel";

describe("<LabsUserSettingsTab />", () => {
const sdkConfigSpy = jest.spyOn(SdkConfig, "get");

const defaultProps = {
closeSettingsFn: jest.fn(),
};
Expand All @@ -34,7 +33,9 @@ describe("<LabsUserSettingsTab />", () => {
beforeEach(() => {
jest.clearAllMocks();
settingsValueSpy.mockReturnValue(false);
sdkConfigSpy.mockReturnValue(false);
SdkConfig.reset();
SdkConfig.add({ brand: "BrandedClient" });
localStorage.clear();
});

it("renders settings marked as beta as beta cards", () => {
Expand All @@ -43,6 +44,7 @@ describe("<LabsUserSettingsTab />", () => {
});

it("does not render non-beta labs settings when disabled in config", () => {
const sdkConfigSpy = jest.spyOn(SdkConfig, "get");
render(getComponent());
expect(sdkConfigSpy).toHaveBeenCalledWith("show_labs_settings");

Expand All @@ -52,12 +54,90 @@ describe("<LabsUserSettingsTab />", () => {

it("renders non-beta labs settings when enabled in config", () => {
// enable labs
sdkConfigSpy.mockImplementation((configName) => configName === "show_labs_settings");
SdkConfig.add({ show_labs_settings: true });
const { container } = render(getComponent());

// non-beta labs section
expect(screen.getByText("Early previews")).toBeInTheDocument();
const labsSections = container.getElementsByClassName("mx_SettingsSubsection");
expect(labsSections).toHaveLength(9);
});

describe("Rust crypto setting", () => {
const SETTING_NAME = "Rust cryptography implementation";

beforeEach(() => {
SdkConfig.add({ show_labs_settings: true });
});

describe("Not enabled in config", () => {
it("can be turned on if not already", async () => {
// By the time the settings panel is shown, `MatrixClientPeg.initClientCrypto` has saved the current
// value to the settings store.
await SettingsStore.setValue("feature_rust_crypto", null, SettingLevel.DEVICE, false);

const rendered = render(getComponent());
const toggle = rendered.getByRole("switch", { name: SETTING_NAME });
expect(toggle.getAttribute("aria-disabled")).toEqual("false");
expect(toggle.getAttribute("aria-checked")).toEqual("false");

const description = toggle.closest(".mx_SettingsFlag")?.querySelector(".mx_SettingsFlag_microcopy");
expect(description).toHaveTextContent(/To disable you will need to log out and back in/);
});

it("cannot be turned off once enabled", async () => {
await SettingsStore.setValue("feature_rust_crypto", null, SettingLevel.DEVICE, true);

const rendered = render(getComponent());
const toggle = rendered.getByRole("switch", { name: SETTING_NAME });
expect(toggle.getAttribute("aria-disabled")).toEqual("true");
expect(toggle.getAttribute("aria-checked")).toEqual("true");

// Hover over the toggle to make it show the tooltip
fireEvent.mouseOver(toggle);

const tooltip = rendered.getByRole("tooltip");
expect(tooltip).toHaveTextContent(
"Once enabled, Rust cryptography can only be disabled by logging out and in again",
);
});
});

describe("Enabled in config", () => {
beforeEach(() => {
SdkConfig.add({ features: { feature_rust_crypto: true } });
});

it("can be turned on if not already", async () => {
// By the time the settings panel is shown, `MatrixClientPeg.initClientCrypto` has saved the current
// value to the settings store.
await SettingsStore.setValue("feature_rust_crypto", null, SettingLevel.DEVICE, false);

const rendered = render(getComponent());
const toggle = rendered.getByRole("switch", { name: SETTING_NAME });
expect(toggle.getAttribute("aria-disabled")).toEqual("false");
expect(toggle.getAttribute("aria-checked")).toEqual("false");

const description = toggle.closest(".mx_SettingsFlag")?.querySelector(".mx_SettingsFlag_microcopy");
expect(description).toHaveTextContent(/It cannot be disabled/);
});

it("cannot be turned off once enabled", async () => {
await SettingsStore.setValue("feature_rust_crypto", null, SettingLevel.DEVICE, true);

const rendered = render(getComponent());
const toggle = rendered.getByRole("switch", { name: SETTING_NAME });
expect(toggle.getAttribute("aria-disabled")).toEqual("true");
expect(toggle.getAttribute("aria-checked")).toEqual("true");

// Hover over the toggle to make it show the tooltip
fireEvent.mouseOver(toggle);

const tooltip = rendered.getByRole("tooltip");
expect(tooltip).toHaveTextContent(
"Rust cryptography cannot be disabled on this deployment of BrandedClient",
);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exports[`<LabsUserSettingsTab /> renders settings marked as beta as beta cards 1
<div
class="mx_SettingsSubsection_text"
>
What's next for false? Labs are the best way to get things early, test out new features and help shape them before they actually launch.
What's next for BrandedClient? Labs are the best way to get things early, test out new features and help shape them before they actually launch.
</div>
<div
class="mx_BetaCard"
Expand All @@ -42,10 +42,10 @@ exports[`<LabsUserSettingsTab /> renders settings marked as beta as beta cards 1
class="mx_BetaCard_caption"
>
<p>
A new way to chat over voice and video in .
A new way to chat over voice and video in BrandedClient.
</p>
<p>
Video rooms are always-on VoIP channels embedded within a room in .
Video rooms are always-on VoIP channels embedded within a room in BrandedClient.
</p>
</div>
<div
Expand All @@ -62,7 +62,7 @@ exports[`<LabsUserSettingsTab /> renders settings marked as beta as beta cards 1
<div
class="mx_BetaCard_refreshWarning"
>
Joining the beta will reload .
Joining the beta will reload BrandedClient.
</div>
<div
class="mx_BetaCard_faq"
Expand Down Expand Up @@ -104,7 +104,7 @@ exports[`<LabsUserSettingsTab /> renders settings marked as beta as beta cards 1
class="mx_BetaCard_caption"
>
<p>
Introducing a simpler way to change your notification settings. Customize your , just the way you like.
Introducing a simpler way to change your notification settings. Customize your BrandedClient, just the way you like.
</p>
</div>
<div
Expand Down

0 comments on commit b6364a4

Please sign in to comment.