Remove manual device verification which is not supported by the new cryptography stack (#28588)
* Remove call of `MatrixClient.setDeviceVerified` * Replace usage of deprecated crypto events * Replace deprecated imports * Remove legacy button in `UntrustedDeviceDialog` * Review fixes * Add tests * Fix doc
This commit is contained in:
parent
b72c053d1a
commit
d2acce1221
15 changed files with 237 additions and 527 deletions
|
@ -7,8 +7,8 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import { lazy } from "react";
|
||||
import { ICryptoCallbacks, SecretStorage } from "matrix-js-sdk/src/matrix";
|
||||
import { deriveRecoveryKeyFromPassphrase, decodeRecoveryKey } from "matrix-js-sdk/src/crypto-api";
|
||||
import { SecretStorage } from "matrix-js-sdk/src/matrix";
|
||||
import { deriveRecoveryKeyFromPassphrase, decodeRecoveryKey, CryptoCallbacks } from "matrix-js-sdk/src/crypto-api";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import Modal from "./Modal";
|
||||
|
@ -159,7 +159,7 @@ function cacheSecretStorageKey(
|
|||
}
|
||||
}
|
||||
|
||||
export const crossSigningCallbacks: ICryptoCallbacks = {
|
||||
export const crossSigningCallbacks: CryptoCallbacks = {
|
||||
getSecretStorageKey,
|
||||
cacheSecretStorageKey,
|
||||
};
|
||||
|
|
|
@ -49,7 +49,6 @@ import VoipUserMapper from "./VoipUserMapper";
|
|||
import { htmlSerializeFromMdIfNeeded } from "./editor/serialize";
|
||||
import { leaveRoomBehaviour } from "./utils/leave-behaviour";
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import { getDeviceCryptoInfo } from "./utils/crypto/deviceInfo";
|
||||
import { isCurrentLocalRoom, reject, singleMxcUpload, success, successSync } from "./slash-commands/utils";
|
||||
import { deop, op } from "./slash-commands/op";
|
||||
import { CommandCategories } from "./slash-commands/interface";
|
||||
|
@ -658,69 +657,6 @@ export const Commands = [
|
|||
category: CommandCategories.admin,
|
||||
renderingTypes: [TimelineRenderingType.Room],
|
||||
}),
|
||||
new Command({
|
||||
command: "verify",
|
||||
args: "<user-id> <device-id> <device-signing-key>",
|
||||
description: _td("slash_command|verify"),
|
||||
runFn: function (cli, roomId, threadId, args) {
|
||||
if (args) {
|
||||
const matches = args.match(/^(\S+) +(\S+) +(\S+)$/);
|
||||
if (matches) {
|
||||
const userId = matches[1];
|
||||
const deviceId = matches[2];
|
||||
const fingerprint = matches[3];
|
||||
|
||||
return success(
|
||||
(async (): Promise<void> => {
|
||||
const device = await getDeviceCryptoInfo(cli, userId, deviceId);
|
||||
if (!device) {
|
||||
throw new UserFriendlyError("slash_command|verify_unknown_pair", {
|
||||
userId,
|
||||
deviceId,
|
||||
cause: undefined,
|
||||
});
|
||||
}
|
||||
const deviceTrust = await cli.getCrypto()?.getDeviceVerificationStatus(userId, deviceId);
|
||||
|
||||
if (deviceTrust?.isVerified()) {
|
||||
if (device.getFingerprint() === fingerprint) {
|
||||
throw new UserFriendlyError("slash_command|verify_nop");
|
||||
} else {
|
||||
throw new UserFriendlyError("slash_command|verify_nop_warning_mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
if (device.getFingerprint() !== fingerprint) {
|
||||
const fprint = device.getFingerprint();
|
||||
throw new UserFriendlyError("slash_command|verify_mismatch", {
|
||||
fprint,
|
||||
userId,
|
||||
deviceId,
|
||||
fingerprint,
|
||||
cause: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
await cli.setDeviceVerified(userId, deviceId, true);
|
||||
|
||||
// Tell the user we verified everything
|
||||
Modal.createDialog(InfoDialog, {
|
||||
title: _t("slash_command|verify_success_title"),
|
||||
description: (
|
||||
<div>
|
||||
<p>{_t("slash_command|verify_success_description", { userId, deviceId })}</p>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
})(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return reject(this.getUsage());
|
||||
},
|
||||
category: CommandCategories.advanced,
|
||||
renderingTypes: [TimelineRenderingType.Room],
|
||||
}),
|
||||
new Command({
|
||||
command: "discardsession",
|
||||
description: _td("slash_command|discardsession"),
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2019 New Vector Ltd
|
||||
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
Copyright 2016 OpenMarket 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 React, { useCallback } from "react";
|
||||
import { Device } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import * as FormattingUtils from "../../../utils/FormattingUtils";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import QuestionDialog from "./QuestionDialog";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
|
||||
interface IManualDeviceKeyVerificationDialogProps {
|
||||
userId: string;
|
||||
device: Device;
|
||||
onFinished(confirm?: boolean): void;
|
||||
}
|
||||
|
||||
export function ManualDeviceKeyVerificationDialog({
|
||||
userId,
|
||||
device,
|
||||
onFinished,
|
||||
}: IManualDeviceKeyVerificationDialogProps): JSX.Element {
|
||||
const mxClient = MatrixClientPeg.safeGet();
|
||||
|
||||
const onLegacyFinished = useCallback(
|
||||
(confirm: boolean) => {
|
||||
if (confirm) {
|
||||
mxClient.setDeviceVerified(userId, device.deviceId, true);
|
||||
}
|
||||
onFinished(confirm);
|
||||
},
|
||||
[mxClient, userId, device, onFinished],
|
||||
);
|
||||
|
||||
let text;
|
||||
if (mxClient?.getUserId() === userId) {
|
||||
text = _t("encryption|verification|manual_device_verification_self_text");
|
||||
} else {
|
||||
text = _t("encryption|verification|manual_device_verification_user_text");
|
||||
}
|
||||
|
||||
const fingerprint = device.getFingerprint();
|
||||
const key = fingerprint && FormattingUtils.formatCryptoKey(fingerprint);
|
||||
const body = (
|
||||
<div>
|
||||
<p>{text}</p>
|
||||
<div className="mx_DeviceVerifyDialog_cryptoSection">
|
||||
<ul>
|
||||
<li>
|
||||
<label>{_t("encryption|verification|manual_device_verification_device_name_label")}:</label>{" "}
|
||||
<span>{device.displayName}</span>
|
||||
</li>
|
||||
<li>
|
||||
<label>{_t("encryption|verification|manual_device_verification_device_id_label")}:</label>{" "}
|
||||
<span>
|
||||
<code>{device.deviceId}</code>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<label>{_t("encryption|verification|manual_device_verification_device_key_label")}:</label>{" "}
|
||||
<span>
|
||||
<code>
|
||||
<strong>{key}</strong>
|
||||
</code>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>{_t("encryption|verification|manual_device_verification_footer")}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<QuestionDialog
|
||||
title={_t("settings|sessions|verify_session")}
|
||||
description={body}
|
||||
button={_t("settings|sessions|verify_session")}
|
||||
onFinished={onLegacyFinished}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -17,9 +17,20 @@ import BaseDialog from "./BaseDialog";
|
|||
import { IDevice } from "../right_panel/UserInfo";
|
||||
|
||||
interface IProps {
|
||||
/**
|
||||
* The user whose device is untrusted.
|
||||
*/
|
||||
user: User;
|
||||
/**
|
||||
* The device that is untrusted.
|
||||
*/
|
||||
device: IDevice;
|
||||
onFinished(mode?: "legacy" | "sas" | false): void;
|
||||
/**
|
||||
* Callback for when the dialog is dismissed.
|
||||
* If mode is "sas", the user wants to verify the device with SAS. Otherwise, the dialog was dismissed normally.
|
||||
* @param mode The mode of dismissal.
|
||||
*/
|
||||
onFinished(mode?: "sas"): void;
|
||||
}
|
||||
|
||||
const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) => {
|
||||
|
@ -56,13 +67,10 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
|
|||
<p>{askToVerifyText}</p>
|
||||
</div>
|
||||
<div className="mx_Dialog_buttons">
|
||||
<AccessibleButton kind="primary_outline" onClick={() => onFinished("legacy")}>
|
||||
{_t("encryption|udd|manual_verification_button")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton kind="primary_outline" onClick={() => onFinished("sas")}>
|
||||
{_t("encryption|udd|interactive_verification_button")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton kind="primary" onClick={() => onFinished(false)}>
|
||||
<AccessibleButton kind="primary" onClick={() => onFinished()}>
|
||||
{_t("action|done")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
|
|
@ -6,9 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { CryptoEvent, MatrixClient, Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixClient, Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { throttle } from "lodash";
|
||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto-api";
|
||||
|
||||
import { E2EStatus, shieldStatusForRoom } from "../utils/ShieldUtils";
|
||||
import { useTypedEventEmitter } from "./useEventEmitter";
|
||||
|
|
|
@ -922,7 +922,6 @@
|
|||
},
|
||||
"udd": {
|
||||
"interactive_verification_button": "Interactively verify by emoji",
|
||||
"manual_verification_button": "Manually verify by text",
|
||||
"other_ask_verify_text": "Ask this user to verify their session, or manually verify it below.",
|
||||
"other_new_session_text": "%(name)s (%(userId)s) signed in to a new session without verifying it:",
|
||||
"own_ask_verify_text": "Verify your other session using one of the options below.",
|
||||
|
@ -957,12 +956,6 @@
|
|||
"incoming_sas_dialog_waiting": "Waiting for partner to confirm…",
|
||||
"incoming_sas_user_dialog_text_1": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.",
|
||||
"incoming_sas_user_dialog_text_2": "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.",
|
||||
"manual_device_verification_device_id_label": "Session ID",
|
||||
"manual_device_verification_device_key_label": "Session key",
|
||||
"manual_device_verification_device_name_label": "Session name",
|
||||
"manual_device_verification_footer": "If they don't match, the security of your communication may be compromised.",
|
||||
"manual_device_verification_self_text": "Confirm by comparing the following with the User Settings in your other session:",
|
||||
"manual_device_verification_user_text": "Confirm this user's session by comparing the following with their User Settings:",
|
||||
"no_key_or_device": "It looks like you don't have a Security Key or any other devices you can verify against. This device will not be able to access old encrypted messages. In order to verify your identity on this device, you'll need to reset your verification keys.",
|
||||
"no_support_qr_emoji": "The device you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.",
|
||||
"other_party_cancelled": "The other party cancelled the verification.",
|
||||
|
@ -3036,13 +3029,6 @@
|
|||
"upgraderoom": "Upgrades a room to a new version",
|
||||
"upgraderoom_permission_error": "You do not have the required permissions to use this command.",
|
||||
"usage": "Usage",
|
||||
"verify": "Verifies a user, session, and pubkey tuple",
|
||||
"verify_mismatch": "WARNING: KEY VERIFICATION FAILED! The signing key for %(userId)s and session %(deviceId)s is \"%(fprint)s\" which does not match the provided key \"%(fingerprint)s\". This could mean your communications are being intercepted!",
|
||||
"verify_nop": "Session already verified!",
|
||||
"verify_nop_warning_mismatch": "WARNING: session already verified, but keys do NOT MATCH!",
|
||||
"verify_success_description": "The signing key you provided matches the signing key you received from %(userId)s's session %(deviceId)s. Session marked as verified.",
|
||||
"verify_success_title": "Verified key",
|
||||
"verify_unknown_pair": "Unknown (user, session) pair: (%(userId)s, %(deviceId)s)",
|
||||
"view": "Views room with given address",
|
||||
"whois": "Displays information about a user"
|
||||
},
|
||||
|
|
|
@ -9,7 +9,8 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { Method, MatrixClient, Crypto } from "matrix-js-sdk/src/matrix";
|
||||
import { Method, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoApi } from "matrix-js-sdk/src/crypto-api";
|
||||
|
||||
import type * as Pako from "pako";
|
||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
|
@ -169,7 +170,7 @@ async function collectSynapseSpecific(client: MatrixClient, body: FormData): Pro
|
|||
/**
|
||||
* Collects crypto related information.
|
||||
*/
|
||||
async function collectCryptoInfo(cryptoApi: Crypto.CryptoApi, body: FormData): Promise<void> {
|
||||
async function collectCryptoInfo(cryptoApi: CryptoApi, body: FormData): Promise<void> {
|
||||
body.append("crypto_version", cryptoApi.getVersion());
|
||||
|
||||
const ownDeviceKeys = await cryptoApi.getOwnDeviceKeys();
|
||||
|
@ -198,7 +199,7 @@ async function collectCryptoInfo(cryptoApi: Crypto.CryptoApi, body: FormData): P
|
|||
/**
|
||||
* Collects information about secret storage and backup.
|
||||
*/
|
||||
async function collectRecoveryInfo(client: MatrixClient, cryptoApi: Crypto.CryptoApi, body: FormData): Promise<void> {
|
||||
async function collectRecoveryInfo(client: MatrixClient, cryptoApi: CryptoApi, body: FormData): Promise<void> {
|
||||
const secretStorage = client.secretStorage;
|
||||
body.append("secret_storage_ready", String(await cryptoApi.isSecretStorageReady()));
|
||||
body.append("secret_storage_key_in_account", String(await secretStorage.hasKey()));
|
||||
|
|
|
@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { Crypto } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoApi } from "matrix-js-sdk/src/crypto-api";
|
||||
|
||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
|
||||
|
@ -21,7 +21,7 @@ import { MatrixClientPeg } from "../../MatrixClientPeg";
|
|||
*
|
||||
* Dehydration can currently only be enabled by setting a flag in the .well-known file.
|
||||
*/
|
||||
async function deviceDehydrationEnabled(crypto: Crypto.CryptoApi | undefined): Promise<boolean> {
|
||||
async function deviceDehydrationEnabled(crypto: CryptoApi | undefined): Promise<boolean> {
|
||||
if (!crypto) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import { RightPanelPhases } from "./stores/right-panel/RightPanelStorePhases";
|
|||
import { accessSecretStorage } from "./SecurityManager";
|
||||
import UntrustedDeviceDialog from "./components/views/dialogs/UntrustedDeviceDialog";
|
||||
import { IDevice } from "./components/views/right_panel/UserInfo";
|
||||
import { ManualDeviceKeyVerificationDialog } from "./components/views/dialogs/ManualDeviceKeyVerificationDialog";
|
||||
import RightPanelStore from "./stores/right-panel/RightPanelStore";
|
||||
import { IRightPanelCardState } from "./stores/right-panel/RightPanelStoreIPanelState";
|
||||
import { findDMForUser } from "./utils/dm/findDMForUser";
|
||||
|
@ -53,11 +52,6 @@ export async function verifyDevice(matrixClient: MatrixClient, user: User, devic
|
|||
.getCrypto()
|
||||
?.requestDeviceVerification(user.userId, device.deviceId);
|
||||
setRightPanel({ member: user, verificationRequestPromise });
|
||||
} else if (action === "legacy") {
|
||||
Modal.createDialog(ManualDeviceKeyVerificationDialog, {
|
||||
userId: user.userId,
|
||||
device,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue