/* * Copyright 2025 New Vector Ltd. * * 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, { type JSX } from "react"; import { InlineSpinner } from "@vector-im/compound-web"; import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext"; import BaseTool from "./BaseTool"; import { useAsyncMemo } from "../../../../hooks/useAsyncMemo"; import { _t } from "../../../../languageHandler"; import Modal from "../../../../Modal"; import { ManualDeviceKeyVerificationDialog } from "../ManualDeviceKeyVerificationDialog"; interface KeyBackupProps { /** * Callback to invoke when the back button is clicked. */ onBack(): void; } /** * A component that displays information about the key storage and cross-signing. */ export function Crypto({ onBack }: KeyBackupProps): JSX.Element { const matrixClient = useMatrixClientContext(); return ( {matrixClient.getCrypto() ? ( <> ) : ( {_t("devtools|crypto|crypto_not_available")} )} ); } /** * A component that displays information about the key storage. */ function KeyStorage(): JSX.Element { const matrixClient = useMatrixClientContext(); const keyStorageData = useAsyncMemo(async () => { const crypto = matrixClient.getCrypto()!; // Get all the key storage data that we will display const backupInfo = await crypto.getKeyBackupInfo(); const backupKeyStored = Boolean(await matrixClient.isKeyBackupKeyStored()); const backupKeyFromCache = await crypto.getSessionBackupPrivateKey(); const backupKeyCached = Boolean(backupKeyFromCache); const backupKeyWellFormed = backupKeyFromCache instanceof Uint8Array; const activeBackupVersion = await crypto.getActiveSessionBackupVersion(); const secretStorageKeyInAccount = await matrixClient.secretStorage.hasKey(); const secretStorageReady = await crypto.isSecretStorageReady(); return { backupInfo, backupKeyStored, backupKeyCached, backupKeyWellFormed, activeBackupVersion, secretStorageKeyInAccount, secretStorageReady, }; }, [matrixClient]); // Show a spinner while loading if (keyStorageData === undefined) return ; const { backupInfo, backupKeyStored, backupKeyCached, backupKeyWellFormed, activeBackupVersion, secretStorageKeyInAccount, secretStorageReady, } = keyStorageData; return ( {_t("devtools|crypto|key_storage")}
{_t("devtools|crypto|key_backup_latest_version")} {backupInfo ? `${backupInfo.version} (${_t("settings|security|key_backup_algorithm")} ${backupInfo.algorithm})` : _t("devtools|crypto|key_backup_inactive_warning")}
{_t("devtools|crypto|backup_key_stored_status")} {backupKeyStored ? _t("devtools|crypto|backup_key_stored") : _t("devtools|crypto|backup_key_not_stored")}
{_t("devtools|crypto|key_backup_active_version")} {activeBackupVersion === null ? _t("devtools|crypto|key_backup_active_version_none") : activeBackupVersion}
{_t("devtools|crypto|backup_key_cached_status")} {`${ backupKeyCached ? _t("devtools|crypto|backup_key_cached") : _t("devtools|crypto|not_found_locally") }, ${ backupKeyWellFormed ? _t("devtools|crypto|backup_key_well_formed") : _t("devtools|crypto|backup_key_unexpected_type") }`}
{_t("devtools|crypto|4s_public_key_status")} {secretStorageKeyInAccount ? _t("devtools|crypto|4s_public_key_in_account_data") : _t("devtools|crypto|4s_public_key_not_in_account_data")}
{_t("devtools|crypto|secret_storage_status")} {secretStorageReady ? _t("devtools|crypto|secret_storage_ready") : _t("devtools|crypto|secret_storage_not_ready")}
); } /** * A component that displays information about cross-signing. */ function CrossSigning(): JSX.Element { const matrixClient = useMatrixClientContext(); const crossSigningData = useAsyncMemo(async () => { const crypto = matrixClient.getCrypto()!; // Get all the cross-signing data that we will display const crossSigningStatus = await crypto.getCrossSigningStatus(); const crossSigningPublicKeysOnDevice = crossSigningStatus.publicKeysOnDevice; const crossSigningPrivateKeysInStorage = crossSigningStatus.privateKeysInSecretStorage; const masterPrivateKeyCached = crossSigningStatus.privateKeysCachedLocally.masterKey; const selfSigningPrivateKeyCached = crossSigningStatus.privateKeysCachedLocally.selfSigningKey; const userSigningPrivateKeyCached = crossSigningStatus.privateKeysCachedLocally.userSigningKey; const crossSigningReady = await crypto.isCrossSigningReady(); return { crossSigningPublicKeysOnDevice, crossSigningPrivateKeysInStorage, masterPrivateKeyCached, selfSigningPrivateKeyCached, userSigningPrivateKeyCached, crossSigningReady, }; }, [matrixClient]); // Show a spinner while loading if (crossSigningData === undefined) return ; const { crossSigningPublicKeysOnDevice, crossSigningPrivateKeysInStorage, masterPrivateKeyCached, selfSigningPrivateKeyCached, userSigningPrivateKeyCached, crossSigningReady, } = crossSigningData; return ( {_t("devtools|crypto|cross_signing")}
{_t("devtools|crypto|cross_signing_status")} {getCrossSigningStatus(crossSigningReady, crossSigningPrivateKeysInStorage)}
{_t("devtools|crypto|cross_signing_public_keys_on_device_status")} {crossSigningPublicKeysOnDevice ? _t("devtools|crypto|cross_signing_public_keys_on_device") : _t("devtools|crypto|not_found")}
{_t("devtools|crypto|cross_signing_private_keys_in_storage_status")} {crossSigningPrivateKeysInStorage ? _t("devtools|crypto|cross_signing_private_keys_in_storage") : _t("devtools|crypto|cross_signing_private_keys_not_in_storage")}
{_t("devtools|crypto|master_private_key_cached_status")} {masterPrivateKeyCached ? _t("devtools|crypto|cross_signing_cached") : _t("devtools|crypto|not_found_locally")}
{_t("devtools|crypto|self_signing_private_key_cached_status")} {selfSigningPrivateKeyCached ? _t("devtools|crypto|cross_signing_cached") : _t("devtools|crypto|not_found_locally")}
{_t("devtools|crypto|user_signing_private_key_cached_status")} {userSigningPrivateKeyCached ? _t("devtools|crypto|cross_signing_cached") : _t("devtools|crypto|not_found_locally")}
); } /** * Get the cross-signing status. * @param crossSigningReady Whether cross-signing is ready. * @param crossSigningPrivateKeysInStorage Whether cross-signing private keys are in secret storage. */ function getCrossSigningStatus(crossSigningReady: boolean, crossSigningPrivateKeysInStorage: boolean): string { if (crossSigningReady) { return crossSigningPrivateKeysInStorage ? _t("devtools|crypto|cross_signing_ready") : _t("devtools|crypto|cross_signing_untrusted"); } if (crossSigningPrivateKeysInStorage) { return _t("devtools|crypto|cross_signing_not_ready"); } return _t("devtools|crypto|cross_signing_not_ready"); } /** * A component that displays information about the current session. */ function Session(): JSX.Element { const matrixClient = useMatrixClientContext(); const sessionData = useAsyncMemo(async () => { const crypto = matrixClient.getCrypto()!; const keys = await crypto.getOwnDeviceKeys(); return { fingerprint: keys.ed25519, deviceId: matrixClient.deviceId, }; }, [matrixClient]); // Show a spinner while loading if (sessionData === undefined) { return ; } return ( {_t("devtools|crypto|session")}
{_t("devtools|crypto|device_id")} {sessionData.deviceId}
{_t("devtools|crypto|session_fingerprint")} {sessionData.fingerprint}
); }