diff --git a/res/css/_components.pcss b/res/css/_components.pcss index 88e4617b132..efa7f6b98b2 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -134,6 +134,7 @@ @import "./views/dialogs/_ConfirmUserActionDialog.pcss"; @import "./views/dialogs/_CreateRoomDialog.pcss"; @import "./views/dialogs/_CreateSubspaceDialog.pcss"; +@import "./views/dialogs/_Crypto.pcss"; @import "./views/dialogs/_DeactivateAccountDialog.pcss"; @import "./views/dialogs/_DevtoolsDialog.pcss"; @import "./views/dialogs/_ExportDialog.pcss"; diff --git a/res/css/views/dialogs/_Crypto.pcss b/res/css/views/dialogs/_Crypto.pcss new file mode 100644 index 00000000000..ad1179ff5c2 --- /dev/null +++ b/res/css/views/dialogs/_Crypto.pcss @@ -0,0 +1,21 @@ +/* + * 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. + */ + +.mx_Crypto { + .mx_KeyStorage { + margin: var(--cpd-space-4x) 0; + text-align: left; + + thead { + font: var(--cpd-font-heading-sm-semibold); + } + + th { + padding-right: var(--cpd-space-2x); + } + } +} diff --git a/src/components/views/dialogs/DevtoolsDialog.tsx b/src/components/views/dialogs/DevtoolsDialog.tsx index e9e2c9a3344..440e37393ff 100644 --- a/src/components/views/dialogs/DevtoolsDialog.tsx +++ b/src/components/views/dialogs/DevtoolsDialog.tsx @@ -24,6 +24,7 @@ import { SettingLevel } from "../../../settings/SettingLevel"; import ServerInfo from "./devtools/ServerInfo"; import CopyableText from "../elements/CopyableText"; import RoomNotifications from "./devtools/RoomNotifications"; +import { Crypto } from "./devtools/Crypto"; enum Category { Room, @@ -49,6 +50,7 @@ const Tools: Record = { [_td("devtools|explore_account_data"), AccountDataExplorer], [_td("devtools|settings_explorer"), SettingExplorer], [_td("devtools|server_info"), ServerInfo], + [_td("devtools|crypto|title"), Crypto], ], }; diff --git a/src/components/views/dialogs/devtools/Crypto.tsx b/src/components/views/dialogs/devtools/Crypto.tsx new file mode 100644 index 00000000000..f0f21539f42 --- /dev/null +++ b/src/components/views/dialogs/devtools/Crypto.tsx @@ -0,0 +1,132 @@ +/* + * 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, { 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"; + +interface KeyBackupProps { + onBack(): void; +} + +export function Crypto({ onBack }: KeyBackupProps): JSX.Element { + return ( + + + + ); +} + +/** + * A component that displays information about the key storage. + */ +function KeyStorage(): JSX.Element { + const matrixClient = useMatrixClientContext(); + const keyStorageData = useAsyncMemo(async () => { + const crypto = matrixClient.getCrypto(); + if (!crypto) return null; + + 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]); + + if (keyStorageData === undefined) return ; + if (keyStorageData === null) return {_t("devtools|crypto|crypto_not_available")}; + + 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|backup_key_not_cached") + }, + ${ + 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")} +
+ ); +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 875da43f14e..84167d560dc 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -734,6 +734,29 @@ "category_room": "Room", "caution_colon": "Caution:", "client_versions": "Client Versions", + "crypto": { + "4s_public_key_in_account_data": "in account data", + "4s_public_key_not_in_account_data": "not found", + "4s_public_key_status": "Secret storage public key:", + "backup_key_cached": "cached locally", + "backup_key_cached_status": "Backup key cached:", + "backup_key_not_cached": "not found locally", + "backup_key_not_stored": "not stored", + "backup_key_stored": "in secret storage", + "backup_key_stored_status": "Backup key stored:", + "backup_key_unexpected_type": "unexpected type", + "backup_key_well_formed": "well formed", + "crypto_not_available": "Cryptographic module is not available", + "key_backup_active_version": "Active backup version:", + "key_backup_active_version_none": "None", + "key_backup_inactive_warning": "Your keys are not being backed up from this session.", + "key_backup_latest_version": "Latest backup version on server:", + "key_storage": "Key Storage", + "secret_storage_not_ready": "not ready", + "secret_storage_ready": "ready", + "secret_storage_status": "Secret storage:", + "title": "Crypto" + }, "developer_mode": "Developer mode", "developer_tools": "Developer Tools", "edit_setting": "Edit setting",