/* Copyright 2024 New Vector Ltd. Copyright 2021 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE files in the repository root for full details. */ import React, { lazy } from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { EmptyObject } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; import AccessibleButton from "../elements/AccessibleButton"; import * as FormattingUtils from "../../../utils/FormattingUtils"; import SettingsStore from "../../../settings/SettingsStore"; import SettingsFlag from "../elements/SettingsFlag"; import { SettingLevel } from "../../../settings/SettingLevel"; import { SettingsSubsection, SettingsSubsectionText } from "./shared/SettingsSubsection"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; interface IState { /** The device's base64-encoded Ed25519 identity key, or: * * * `undefined`: not yet loaded * * `null`: encryption is not supported (or the crypto stack was not correctly initialized) */ deviceIdentityKey: string | undefined | null; } export default class CryptographyPanel extends React.Component { public static contextType = MatrixClientContext; declare public context: React.ContextType; public constructor(props: EmptyObject, context: React.ContextType) { super(props); if (!context.getCrypto()) { this.state = { deviceIdentityKey: null }; } else { this.state = { deviceIdentityKey: undefined }; } } public componentDidMount(): void { if (this.state.deviceIdentityKey === undefined) { this.context .getCrypto() ?.getOwnDeviceKeys() .then((keys) => { this.setState({ deviceIdentityKey: keys.ed25519 }); }) .catch((e) => { logger.error(`CryptographyPanel: Error fetching own device keys: ${e}`); this.setState({ deviceIdentityKey: null }); }); } } public render(): React.ReactNode { const client = this.context; const deviceId = client.deviceId; let identityKey = this.state.deviceIdentityKey; if (identityKey === undefined) { // Should show a spinner here really, but since this will be very transitional, I can't be doing with the // necessary styling. identityKey = "..."; } else if (identityKey === null) { identityKey = _t("encryption|not_supported"); } else { identityKey = FormattingUtils.formatCryptoKey(identityKey); } let importExportButtons: JSX.Element | undefined; if (client.getCrypto()) { importExportButtons = (
{_t("settings|security|export_megolm_keys")} {_t("settings|security|import_megolm_keys")}
); } let noSendUnverifiedSetting: JSX.Element | undefined; if (SettingsStore.canSetValue("blacklistUnverifiedDevices", null, SettingLevel.DEVICE)) { noSendUnverifiedSetting = ( ); } return (
{_t("settings|security|session_id")} {deviceId}
{_t("settings|security|session_key")} {identityKey}
{importExportButtons} {noSendUnverifiedSetting}
); } private onExportE2eKeysClicked = (): void => { Modal.createDialog( lazy(() => import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog")), { matrixClient: this.context }, ); }; private onImportE2eKeysClicked = (): void => { Modal.createDialog( lazy(() => import("../../../async-components/views/dialogs/security/ImportE2eKeysDialog")), { matrixClient: this.context }, ); }; private updateBlacklistDevicesFlag = (checked: boolean): void => { const crypto = this.context.getCrypto(); if (crypto) crypto.globalBlacklistUnverifiedDevices = checked; }; }