Skip to content

Commit

Permalink
Add labs option to exclude unverified devices (#92)
Browse files Browse the repository at this point in the history
Add a labs option which will, when set, switch into the "invisible crypto"
mode of refusing to send keys to, or decrypt messages from, devices that have
not been signed by their owner.
  • Loading branch information
richvdh authored Sep 30, 2024
1 parent 8962e8c commit be2c1fc
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/MatrixClientPeg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import PlatformPeg from "./PlatformPeg";
import { formatList } from "./utils/FormattingUtils";
import SdkConfig from "./SdkConfig";
import { Features } from "./settings/Settings";
import { setDeviceIsolationMode } from "./settings/controllers/DeviceIsolationModeController.ts";

export interface IMatrixClientCreds {
homeserverUrl: string;
Expand Down Expand Up @@ -343,6 +344,9 @@ class MatrixClientPegClass implements IMatrixClientPeg {
});

StorageManager.setCryptoInitialised(true);

setDeviceIsolationMode(this.matrixClient, SettingsStore.getValue("feature_exclude_insecure_devices"));

// TODO: device dehydration and whathaveyou
return;
}
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,8 @@
"dynamic_room_predecessors": "Dynamic room predecessors",
"dynamic_room_predecessors_description": "Enable MSC3946 (to support late-arriving room archives)",
"element_call_video_rooms": "Element Call video rooms",
"exclude_insecure_devices": "Exclude insecure devices when sending/receiving messages",
"exclude_insecure_devices_description": "When this mode is enabled, encrypted messages will not be shared with unverified devices, and messages from unverified devices will be shown as an error. Note that if you enable this mode, you may be unable to communicate with users who have not verified their devices.",
"experimental_description": "Feeling experimental? Try out our latest ideas in development. These features are not finalised; they may be unstable, may change, or may be dropped altogether. <a>Learn more</a>.",
"experimental_section": "Early previews",
"extended_profiles_msc_support": "Requires your server to support MSC4133",
Expand Down
11 changes: 11 additions & 0 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import React, { ReactNode } from "react";
import { UNSTABLE_MSC4133_EXTENDED_PROFILES } from "matrix-js-sdk/src/matrix";

import { _t, _td, TranslationKey } from "../languageHandler";
import DeviceIsolationModeController from "./controllers/DeviceIsolationModeController.ts";
import {
NotificationBodyEnabledController,
NotificationsEnabledController,
Expand Down Expand Up @@ -309,6 +310,16 @@ export const SETTINGS: { [setting: string]: ISetting } = {
supportedLevelsAreOrdered: true,
default: false,
},
"feature_exclude_insecure_devices": {
isFeature: true,
labsGroup: LabGroup.Encryption,
controller: new DeviceIsolationModeController(),
displayName: _td("labs|exclude_insecure_devices"),
description: _td("labs|exclude_insecure_devices_description"),
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
supportedLevelsAreOrdered: true,
default: false,
},
"useOnlyCurrentProfiles": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td("settings|disable_historical_profile"),
Expand Down
37 changes: 37 additions & 0 deletions src/settings/controllers/DeviceIsolationModeController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import { AllDevicesIsolationMode, OnlySignedDevicesIsolationMode } from "matrix-js-sdk/src/crypto-api";
import { MatrixClient } from "matrix-js-sdk/src/matrix";

import SettingController from "./SettingController";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { SettingLevel } from "../SettingLevel";

/**
* A controller for the "exclude_insecure_devices" setting, which will
* update the crypto stack's device isolation mode on change.
*/
export default class DeviceIsolationModeController extends SettingController {
public onChange(level: SettingLevel, roomId: string, newValue: any): void {
setDeviceIsolationMode(MatrixClientPeg.safeGet(), newValue);
}
}

/**
* Set the crypto stack's device isolation mode based on the current value of the
* "exclude_insecure_devices" setting.
*
* @param client - MatrixClient to update to the new setting.
* @param settingValue - value of the "exclude_insecure_devices" setting.
*/
export function setDeviceIsolationMode(client: MatrixClient, settingValue: boolean): void {
client
.getCrypto()
?.setDeviceIsolationMode(
settingValue ? new OnlySignedDevicesIsolationMode() : new AllDevicesIsolationMode(true),
);
}
1 change: 1 addition & 0 deletions test/components/structures/MatrixChat-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,7 @@ describe("<MatrixChat />", () => {
getUserVerificationStatus: jest
.fn()
.mockResolvedValue(new UserVerificationStatus(false, false, false)),
setDeviceIsolationMode: jest.fn(),
};
loginClient.isCryptoEnabled.mockReturnValue(true);
loginClient.getCrypto.mockReturnValue(mockCrypto as any);
Expand Down
33 changes: 33 additions & 0 deletions test/settings/controllers/DeviceIsolationModeController-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright 2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import { AllDevicesIsolationMode, OnlySignedDevicesIsolationMode } from "matrix-js-sdk/src/crypto-api";

import { stubClient } from "../../test-utils";
import DeviceIsolationModeController from "../../../src/settings/controllers/DeviceIsolationModeController.ts";
import { SettingLevel } from "../../../src/settings/SettingLevel";

describe("DeviceIsolationModeController", () => {
afterEach(() => {
jest.resetAllMocks();
});

describe("tracks enabling and disabling", () => {
it("on sets signed device isolation mode", () => {
const cli = stubClient();
const controller = new DeviceIsolationModeController();
controller.onChange(SettingLevel.DEVICE, "", true);
expect(cli.getCrypto()?.setDeviceIsolationMode).toHaveBeenCalledWith(new OnlySignedDevicesIsolationMode());
});

it("off sets all device isolation mode", () => {
const cli = stubClient();
const controller = new DeviceIsolationModeController();
controller.onChange(SettingLevel.DEVICE, "", false);
expect(cli.getCrypto()?.setDeviceIsolationMode).toHaveBeenCalledWith(new AllDevicesIsolationMode(true));
});
});
});
1 change: 1 addition & 0 deletions test/test-utils/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export function createTestClient(): MatrixClient {
resetKeyBackup: jest.fn(),
isEncryptionEnabledInRoom: jest.fn(),
getVerificationRequestsToDeviceInProgress: jest.fn().mockReturnValue([]),
setDeviceIsolationMode: jest.fn(),
}),

getPushActionsForEvent: jest.fn(),
Expand Down

0 comments on commit be2c1fc

Please sign in to comment.