Skip to content
This repository was archived by the owner on Oct 22, 2024. It is now read-only.

Commit be2c1fc

Browse files
authored
Add labs option to exclude unverified devices (#92)
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.
1 parent 8962e8c commit be2c1fc

File tree

7 files changed

+89
-0
lines changed

7 files changed

+89
-0
lines changed

src/MatrixClientPeg.ts

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import PlatformPeg from "./PlatformPeg";
4242
import { formatList } from "./utils/FormattingUtils";
4343
import SdkConfig from "./SdkConfig";
4444
import { Features } from "./settings/Settings";
45+
import { setDeviceIsolationMode } from "./settings/controllers/DeviceIsolationModeController.ts";
4546

4647
export interface IMatrixClientCreds {
4748
homeserverUrl: string;
@@ -343,6 +344,9 @@ class MatrixClientPegClass implements IMatrixClientPeg {
343344
});
344345

345346
StorageManager.setCryptoInitialised(true);
347+
348+
setDeviceIsolationMode(this.matrixClient, SettingsStore.getValue("feature_exclude_insecure_devices"));
349+
346350
// TODO: device dehydration and whathaveyou
347351
return;
348352
}

src/i18n/strings/en_EN.json

+2
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,8 @@
14271427
"dynamic_room_predecessors": "Dynamic room predecessors",
14281428
"dynamic_room_predecessors_description": "Enable MSC3946 (to support late-arriving room archives)",
14291429
"element_call_video_rooms": "Element Call video rooms",
1430+
"exclude_insecure_devices": "Exclude insecure devices when sending/receiving messages",
1431+
"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.",
14301432
"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>.",
14311433
"experimental_section": "Early previews",
14321434
"extended_profiles_msc_support": "Requires your server to support MSC4133",

src/settings/Settings.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import React, { ReactNode } from "react";
1111
import { UNSTABLE_MSC4133_EXTENDED_PROFILES } from "matrix-js-sdk/src/matrix";
1212

1313
import { _t, _td, TranslationKey } from "../languageHandler";
14+
import DeviceIsolationModeController from "./controllers/DeviceIsolationModeController.ts";
1415
import {
1516
NotificationBodyEnabledController,
1617
NotificationsEnabledController,
@@ -309,6 +310,16 @@ export const SETTINGS: { [setting: string]: ISetting } = {
309310
supportedLevelsAreOrdered: true,
310311
default: false,
311312
},
313+
"feature_exclude_insecure_devices": {
314+
isFeature: true,
315+
labsGroup: LabGroup.Encryption,
316+
controller: new DeviceIsolationModeController(),
317+
displayName: _td("labs|exclude_insecure_devices"),
318+
description: _td("labs|exclude_insecure_devices_description"),
319+
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED,
320+
supportedLevelsAreOrdered: true,
321+
default: false,
322+
},
312323
"useOnlyCurrentProfiles": {
313324
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
314325
displayName: _td("settings|disable_historical_profile"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright 2024 New Vector Ltd.
3+
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
4+
Please see LICENSE files in the repository root for full details.
5+
*/
6+
7+
import { AllDevicesIsolationMode, OnlySignedDevicesIsolationMode } from "matrix-js-sdk/src/crypto-api";
8+
import { MatrixClient } from "matrix-js-sdk/src/matrix";
9+
10+
import SettingController from "./SettingController";
11+
import { MatrixClientPeg } from "../../MatrixClientPeg";
12+
import { SettingLevel } from "../SettingLevel";
13+
14+
/**
15+
* A controller for the "exclude_insecure_devices" setting, which will
16+
* update the crypto stack's device isolation mode on change.
17+
*/
18+
export default class DeviceIsolationModeController extends SettingController {
19+
public onChange(level: SettingLevel, roomId: string, newValue: any): void {
20+
setDeviceIsolationMode(MatrixClientPeg.safeGet(), newValue);
21+
}
22+
}
23+
24+
/**
25+
* Set the crypto stack's device isolation mode based on the current value of the
26+
* "exclude_insecure_devices" setting.
27+
*
28+
* @param client - MatrixClient to update to the new setting.
29+
* @param settingValue - value of the "exclude_insecure_devices" setting.
30+
*/
31+
export function setDeviceIsolationMode(client: MatrixClient, settingValue: boolean): void {
32+
client
33+
.getCrypto()
34+
?.setDeviceIsolationMode(
35+
settingValue ? new OnlySignedDevicesIsolationMode() : new AllDevicesIsolationMode(true),
36+
);
37+
}

test/components/structures/MatrixChat-test.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ describe("<MatrixChat />", () => {
10021002
getUserVerificationStatus: jest
10031003
.fn()
10041004
.mockResolvedValue(new UserVerificationStatus(false, false, false)),
1005+
setDeviceIsolationMode: jest.fn(),
10051006
};
10061007
loginClient.isCryptoEnabled.mockReturnValue(true);
10071008
loginClient.getCrypto.mockReturnValue(mockCrypto as any);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
Copyright 2024 New Vector Ltd.
3+
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
4+
Please see LICENSE files in the repository root for full details.
5+
*/
6+
7+
import { AllDevicesIsolationMode, OnlySignedDevicesIsolationMode } from "matrix-js-sdk/src/crypto-api";
8+
9+
import { stubClient } from "../../test-utils";
10+
import DeviceIsolationModeController from "../../../src/settings/controllers/DeviceIsolationModeController.ts";
11+
import { SettingLevel } from "../../../src/settings/SettingLevel";
12+
13+
describe("DeviceIsolationModeController", () => {
14+
afterEach(() => {
15+
jest.resetAllMocks();
16+
});
17+
18+
describe("tracks enabling and disabling", () => {
19+
it("on sets signed device isolation mode", () => {
20+
const cli = stubClient();
21+
const controller = new DeviceIsolationModeController();
22+
controller.onChange(SettingLevel.DEVICE, "", true);
23+
expect(cli.getCrypto()?.setDeviceIsolationMode).toHaveBeenCalledWith(new OnlySignedDevicesIsolationMode());
24+
});
25+
26+
it("off sets all device isolation mode", () => {
27+
const cli = stubClient();
28+
const controller = new DeviceIsolationModeController();
29+
controller.onChange(SettingLevel.DEVICE, "", false);
30+
expect(cli.getCrypto()?.setDeviceIsolationMode).toHaveBeenCalledWith(new AllDevicesIsolationMode(true));
31+
});
32+
});
33+
});

test/test-utils/test-utils.ts

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export function createTestClient(): MatrixClient {
131131
resetKeyBackup: jest.fn(),
132132
isEncryptionEnabledInRoom: jest.fn(),
133133
getVerificationRequestsToDeviceInProgress: jest.fn().mockReturnValue([]),
134+
setDeviceIsolationMode: jest.fn(),
134135
}),
135136

136137
getPushActionsForEvent: jest.fn(),

0 commit comments

Comments
 (0)