mirror of
https://github.com/element-hq/element-desktop
synced 2025-04-21 09:03:56 +02:00
Iterate
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
bec721cf57
commit
4889634f0b
@ -364,6 +364,8 @@ app.enableSandbox();
|
|||||||
// We disable media controls here. We do this because calls use audio and video elements and they sometimes capture the media keys. See https://github.com/vector-im/element-web/issues/15704
|
// We disable media controls here. We do this because calls use audio and video elements and they sometimes capture the media keys. See https://github.com/vector-im/element-web/issues/15704
|
||||||
app.commandLine.appendSwitch("disable-features", "HardwareMediaKeyHandling,MediaSessionService");
|
app.commandLine.appendSwitch("disable-features", "HardwareMediaKeyHandling,MediaSessionService");
|
||||||
|
|
||||||
|
store.prepare(); // must be called before any async actions
|
||||||
|
|
||||||
// Disable hardware acceleration if the setting has been set.
|
// Disable hardware acceleration if the setting has been set.
|
||||||
if (store.get("disableHardwareAcceleration") === true) {
|
if (store.get("disableHardwareAcceleration") === true) {
|
||||||
console.log("Disabling hardware acceleration.");
|
console.log("Disabling hardware acceleration.");
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
"zoom_out": "Zoom Out"
|
"zoom_out": "Zoom Out"
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"yes": "Yes",
|
||||||
|
"no": "No",
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"brand_help": "%(brand)s Help",
|
"brand_help": "%(brand)s Help",
|
||||||
"help": "Help",
|
"help": "Help",
|
||||||
@ -59,5 +61,12 @@
|
|||||||
"bring_all_to_front": "Bring All to Front",
|
"bring_all_to_front": "Bring All to Front",
|
||||||
"label": "Window",
|
"label": "Window",
|
||||||
"zoom": "Zoom"
|
"zoom": "Zoom"
|
||||||
|
},
|
||||||
|
"store": {
|
||||||
|
"error": {
|
||||||
|
"title": "Failed to load configuration",
|
||||||
|
"unsupported_backend_override": "TODO",
|
||||||
|
"unknown_backend_override": "TODO"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
164
src/store.ts
164
src/store.ts
@ -16,7 +16,9 @@ limitations under the License.
|
|||||||
|
|
||||||
import ElectronStore from "electron-store";
|
import ElectronStore from "electron-store";
|
||||||
import keytar from "keytar-forked";
|
import keytar from "keytar-forked";
|
||||||
import { app, safeStorage } from "electron";
|
import { app, safeStorage, dialog, type SafeStorage } from "electron";
|
||||||
|
|
||||||
|
import { _t } from "./language-helper.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legacy keytar service names for storing secrets.
|
* Legacy keytar service names for storing secrets.
|
||||||
@ -24,6 +26,20 @@ import { app, safeStorage } from "electron";
|
|||||||
const KEYTAR_SERVICE = "element.io";
|
const KEYTAR_SERVICE = "element.io";
|
||||||
const LEGACY_KEYTAR_SERVICE = "riot.im";
|
const LEGACY_KEYTAR_SERVICE = "riot.im";
|
||||||
|
|
||||||
|
type SafeStorageBackend = ReturnType<SafeStorage["getSelectedStorageBackend"]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of safeStorage backends to their command line arguments.
|
||||||
|
* kwallet6 cannot be specified via command line
|
||||||
|
* https://www.electronjs.org/docs/latest/api/safe-storage#safestoragegetselectedstoragebackend-linux
|
||||||
|
*/
|
||||||
|
const safeStorageBackendMap: Omit<Record<SafeStorageBackend, string>, "unknown" | "kwallet6"> = {
|
||||||
|
basic_text: "basic",
|
||||||
|
gnome_libsecret: "gnome-libsecret",
|
||||||
|
kwallet: "kwallet",
|
||||||
|
kwallet5: "kwallet5",
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSON-backed store for settings which need to be accessible by the main process.
|
* JSON-backed store for settings which need to be accessible by the main process.
|
||||||
* Secrets are stored within the `safeStorage` object, encrypted with safeStorage.
|
* Secrets are stored within the `safeStorage` object, encrypted with safeStorage.
|
||||||
@ -37,6 +53,10 @@ class Store extends ElectronStore<{
|
|||||||
locale?: string | string[];
|
locale?: string | string[];
|
||||||
disableHardwareAcceleration: boolean;
|
disableHardwareAcceleration: boolean;
|
||||||
safeStorage?: Record<string, string>;
|
safeStorage?: Record<string, string>;
|
||||||
|
// Only known for Linux - the safeStorage backend used for the safeStorage data as written
|
||||||
|
safeStorageBackend?: SafeStorageBackend;
|
||||||
|
// Only valid for Linux - whether to override the safeStorage backend via commandLine
|
||||||
|
safeStorageBackendOverride?: boolean;
|
||||||
}> {
|
}> {
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super({
|
super({
|
||||||
@ -69,37 +89,147 @@ class Store extends ElectronStore<{
|
|||||||
safeStorage: {
|
safeStorage: {
|
||||||
type: "object",
|
type: "object",
|
||||||
},
|
},
|
||||||
|
safeStorageBackend: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
safeStorageBackendOverride: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private whenSafeStorageReadyPromise?: Promise<unknown>;
|
/**
|
||||||
public async safeStorageReady(): Promise<void> {
|
* Prepare the store, does not prepare safeStorage, which needs to be done after the app is ready.
|
||||||
if (!this.whenSafeStorageReadyPromise) {
|
* Must be executed in the first tick of the event loop so that it can call Electron APIs before ready state.
|
||||||
this.whenSafeStorageReadyPromise = Promise.allSettled([app.whenReady().then(() => this.migrateSecrets())]);
|
*/
|
||||||
|
public prepare(): void {
|
||||||
|
if (process.platform === "linux") {
|
||||||
|
if (this.get("safeStorageBackendOverride")) {
|
||||||
|
const backend = this.get("safeStorageBackend")!;
|
||||||
|
if (backend in safeStorageBackendMap) {
|
||||||
|
app.commandLine.appendSwitch(
|
||||||
|
"password-store",
|
||||||
|
safeStorageBackendMap[backend as keyof typeof safeStorageBackendMap],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// This case should never happen, but could due to a downgrade or a modified store.
|
||||||
|
dialog.showErrorBox(_t("store|error|title"), _t("store|error|unsupported_backend_override"));
|
||||||
|
throw new Error("safeStorage backend override is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await this.whenSafeStorageReadyPromise;
|
}
|
||||||
|
|
||||||
|
private safeStorageReadyPromise?: Promise<unknown>;
|
||||||
|
public async safeStorageReady(): Promise<void> {
|
||||||
|
if (!this.safeStorageReadyPromise) {
|
||||||
|
this.safeStorageReadyPromise = this.prepareSafeStorage();
|
||||||
|
}
|
||||||
|
await this.safeStorageReadyPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSecretStorageKey = (key: string) => `safeStorage.${key}` as const;
|
private getSecretStorageKey = (key: string) => `safeStorage.${key}` as const;
|
||||||
|
|
||||||
|
private async prepareSafeStorage(): Promise<void> {
|
||||||
|
await app.whenReady();
|
||||||
|
|
||||||
|
if (process.platform === "linux") {
|
||||||
|
// 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
|
||||||
|
let safeStorageBackend = this.get("safeStorageBackend");
|
||||||
|
const selectedSafeStorageBackend = safeStorage.getSelectedStorageBackend();
|
||||||
|
|
||||||
|
if (selectedSafeStorageBackend === "unknown") {
|
||||||
|
// This should never happen but good to be safe
|
||||||
|
dialog.showErrorBox(_t("store|error|title"), _t("store|error|unknown_backend_override"));
|
||||||
|
throw new Error("safeStorage backend unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!safeStorageBackend) {
|
||||||
|
if (selectedSafeStorageBackend === "basic_text") {
|
||||||
|
// Ask the user if they want to use plain text encryption
|
||||||
|
// TODO should we only do this if they have existing data
|
||||||
|
const { response } = await dialog.showMessageBox({
|
||||||
|
// TODO
|
||||||
|
title: "Error 1",
|
||||||
|
message: "Message",
|
||||||
|
// detail: _t(""),
|
||||||
|
type: "question",
|
||||||
|
buttons: [_t("common|no"), _t("common|yes")],
|
||||||
|
defaultId: 0,
|
||||||
|
cancelId: 0,
|
||||||
|
});
|
||||||
|
if (response === 0) {
|
||||||
|
throw new Error("safeStorage backend basic_text and user rejected it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the backend used for the safeStorage data so we can detect if it changes
|
||||||
|
this.set("safeStorageBackend", selectedSafeStorageBackend);
|
||||||
|
safeStorageBackend = selectedSafeStorageBackend;
|
||||||
|
} else if (safeStorageBackend !== selectedSafeStorageBackend) {
|
||||||
|
console.warn(`safeStorage backend changed from ${safeStorageBackend} to ${selectedSafeStorageBackend}`);
|
||||||
|
|
||||||
|
if (safeStorageBackend === "basic_text") {
|
||||||
|
console.info(`Migrating safeStorage from basic_text to ${selectedSafeStorageBackend}`);
|
||||||
|
const data = this.get("safeStorage");
|
||||||
|
if (data) {
|
||||||
|
for (const key in data) {
|
||||||
|
const plaintext = data[key];
|
||||||
|
await this.setSecret(key, plaintext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (safeStorageBackend in safeStorageBackendMap) {
|
||||||
|
// Warn the user that the backend has changed and ask if they wish to use the old one
|
||||||
|
const { response } = await dialog.showMessageBox({
|
||||||
|
// TODO
|
||||||
|
title: "Error 2",
|
||||||
|
message: "Message",
|
||||||
|
// detail: _t(""),
|
||||||
|
type: "question",
|
||||||
|
buttons: [_t("common|no"), _t("common|yes")],
|
||||||
|
defaultId: 0,
|
||||||
|
cancelId: 0,
|
||||||
|
});
|
||||||
|
if (response === 0) {
|
||||||
|
throw new Error("safeStorage backend changed and user rejected mitigation");
|
||||||
|
}
|
||||||
|
this.set("safeStorageBackendOverride", true);
|
||||||
|
app.relaunch();
|
||||||
|
} else {
|
||||||
|
// Warn the user that the backend has changed and tell them that we cannot migrate
|
||||||
|
// dialog.showErrorBox(_t(""), _t("")); TODO
|
||||||
|
throw new Error("safeStorage backend changed and cannot migrate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (safeStorageBackend === "basic_text" && selectedSafeStorageBackend === safeStorageBackend) {
|
||||||
|
// TODO verify if this even works, the docstring makes it sound ephemeral!
|
||||||
|
safeStorage.setUsePlainTextEncryption(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!safeStorage.isEncryptionAvailable()) {
|
||||||
|
console.error("Store migration: safeStorage is not available");
|
||||||
|
throw new Error(`safeStorage is not available`);
|
||||||
|
// TODO fatal error
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.migrateSecrets();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrates keytar data to safeStorage,
|
* Migrates keytar data to safeStorage,
|
||||||
* deletes data from legacy keytar but keeps it in the new keytar for downgrade compatibility.
|
* deletes data from legacy keytar but keeps it in the new keytar for downgrade compatibility.
|
||||||
* @throws if safeStorage is not available.
|
* @throws if safeStorage is not available. TODO
|
||||||
*/
|
*/
|
||||||
private async migrateSecrets(): Promise<void> {
|
private async migrateSecrets(): Promise<void> {
|
||||||
if (this.has("safeStorage")) return;
|
if (this.has("safeStorage")) return; // already migrated
|
||||||
console.info("Store migration: started");
|
console.info("Store migration: started");
|
||||||
if (
|
|
||||||
!safeStorage.isEncryptionAvailable() &&
|
if (process.platform === "linux" && safeStorage.getSelectedStorageBackend() === "basic_text") {
|
||||||
!(process.platform === "linux" && safeStorage.getSelectedStorageBackend() === "basic_text")
|
console.warn("Store migration: safeStorage is using basic text encryption");
|
||||||
) {
|
|
||||||
console.error(
|
|
||||||
"Store migration: safeStorage is not available with backend",
|
|
||||||
safeStorage.getSelectedStorageBackend(),
|
|
||||||
);
|
|
||||||
throw new Error("safeStorage is not available");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user