From e32624666987e75fa9db772a913433c98f0f371e Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Thu, 22 May 2025 11:57:51 +0530 Subject: [PATCH 1/2] Use `basic_text` as fallback when encryption not available Show the user a dialog and fallback to using basic_text temporarily when a valid backend is available but encryption support is not. --- src/i18n/strings/en_EN.json | 3 +++ src/store.ts | 38 +++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 28a81bd..60ec188 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -56,6 +56,9 @@ "backend_changed": "Clear data and reload?", "backend_changed_detail": "Unable to access secret from system keyring, it appears to have changed.", "backend_changed_title": "Failed to load database", + "backend_no_encryption": "Your system has a supported keyring but encryption is not available.", + "backend_no_encryption_detail": "Electron has detected that encryption is not available on your keyring %(backend)s. Please ensure that you have the keyring installed. If you do have the keyring installed, please reboot and try again. Optionally, you can allow %(brand)s to use a weaker form of encryption.", + "backend_no_encryption_title": "No encryption support", "unknown_backend_override": "Your system has an unsupported keyring meaning the database cannot be opened.", "unknown_backend_override_details": "Please check the logs for more details.", "unknown_backend_override_title": "Failed to load database", diff --git a/src/store.ts b/src/store.ts index d78c615..c7cc9bf 100644 --- a/src/store.ts +++ b/src/store.ts @@ -241,8 +241,9 @@ class Store extends ElectronStore { // Linux safeStorage support is hellish, the support varies on the Desktop Environment used rather than the store itself. // https://github.com/electron/electron/issues/39789 https://github.com/microsoft/vscode/issues/185212 const selectedSafeStorageBackend = safeStorage.getSelectedStorageBackend(); + const isEncryptionAvailable = safeStorage.isEncryptionAvailable(); console.info( - `safeStorage backend '${selectedSafeStorageBackend}' selected, '${safeStorageBackend}' in config.`, + `safeStorage backend '${selectedSafeStorageBackend}' selected, '${safeStorageBackend}' in config, isEncryptionAvailable = ${isEncryptionAvailable}.`, ); if (selectedSafeStorageBackend === "unknown") { @@ -257,10 +258,42 @@ class Store extends ElectronStore { } if (this.get("safeStorageBackendMigrate")) { + this.secrets = new PlaintextStorageWriter(this); return this.upgradeLinuxBackend2(); } - if (!safeStorageBackend) { + // Whether we were using basic_text as a fallback before + const usingFallback = this.get("safeStorageBackendOverride") && safeStorageBackend === "basic_text"; + + if (this.mode === Mode.Encrypted && !isEncryptionAvailable && !usingFallback) { + // Sometimes we may have a working backend that for some reason does not support encryption at the moment. + // This may be because electron reported an incorrect backend or because of some known issues with the keyring itself. + // In any case, when this happens, we give the user an option to use a weaker form of encryption. + const { response } = await dialog.showMessageBox({ + title: _t("store|error|backend_no_encryption_title"), + message: _t("store|error|backend_no_encryption"), + detail: _t("store|error|backend_no_encryption_detail", { + backend: safeStorageBackend, + brand: global.vectorConfig.brand || "Element", + }), + type: "error", + buttons: [_t("action|cancel"), _t("store|error|unsupported_keyring_cta")], + defaultId: 0, + cancelId: 0, + }); + if (response === 0) { + throw new Error( + `Encryption support not available on backend ${safeStorageBackend} and user prohibits using weaker encryption.`, + ); + } + this.recordSafeStorageBackend("basic_text"); + this.set("safeStorageBackendOverride", true); + relaunchApp(); + } else if (usingFallback) { + // On the next run, don't use the fallback. + // This is so that we can check if the problems with the keyring fixed itself. + this.set("safeStorageBackendOverride", false); + } else if (!safeStorageBackend) { if (selectedSafeStorageBackend === "basic_text" && this.mode === Mode.Encrypted) { const { response } = await dialog.showMessageBox({ title: _t("store|error|unsupported_keyring_title"), @@ -289,6 +322,7 @@ class Store extends ElectronStore { if (safeStorageBackend === "basic_text") { return this.upgradeLinuxBackend1(); } else if (safeStorageBackend === "plaintext") { + this.secrets = new PlaintextStorageWriter(this); this.upgradeLinuxBackend3(); } else if (safeStorageBackend in safeStorageBackendMap) { this.set("safeStorageBackendOverride", true); From 63e1e0d894ddb19bf48c444ebfd7f0e9abbd3c06 Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Thu, 22 May 2025 14:33:48 +0530 Subject: [PATCH 2/2] Move store creation into migration methods --- src/store.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/store.ts b/src/store.ts index c7cc9bf..c061298 100644 --- a/src/store.ts +++ b/src/store.ts @@ -258,7 +258,6 @@ class Store extends ElectronStore { } if (this.get("safeStorageBackendMigrate")) { - this.secrets = new PlaintextStorageWriter(this); return this.upgradeLinuxBackend2(); } @@ -322,7 +321,6 @@ class Store extends ElectronStore { if (safeStorageBackend === "basic_text") { return this.upgradeLinuxBackend1(); } else if (safeStorageBackend === "plaintext") { - this.secrets = new PlaintextStorageWriter(this); this.upgradeLinuxBackend3(); } else if (safeStorageBackend in safeStorageBackendMap) { this.set("safeStorageBackendOverride", true); @@ -383,7 +381,7 @@ class Store extends ElectronStore { relaunchApp(); } private upgradeLinuxBackend2(): void { - if (!this.secrets) throw new Error("safeStorage not ready"); + this.secrets = new PlaintextStorageWriter(this); console.info("Performing safeStorage migration"); const data = this.get("safeStorage"); if (data) { @@ -396,7 +394,7 @@ class Store extends ElectronStore { relaunchApp(); } private upgradeLinuxBackend3(): void { - if (!this.secrets) throw new Error("safeStorage not ready"); + this.secrets = new PlaintextStorageWriter(this); const selectedSafeStorageBackend = safeStorage.getSelectedStorageBackend(); console.info(`Finishing safeStorage migration to ${selectedSafeStorageBackend}`); const data = this.get("safeStorage");