Linux: Auto migrate safeStorage backend between kwallet5 and kwallet6

This commit is contained in:
ayumi-signal
2026-04-30 10:15:17 -07:00
committed by GitHub
parent 04d9a109b2
commit 2dea157233
2 changed files with 80 additions and 0 deletions
+12
View File
@@ -139,6 +139,7 @@ import { appRelaunch } from '../ts/util/relaunch.main.ts';
import { getAppRootDir } from '../ts/util/appRootDir.main.ts';
import { trackHeapSize } from '../ts/util/oomNotifier.node.ts';
import { sendDummyKeystroke } from './WindowsNotifications.main.ts';
import { maybeMigrateSafeStorageBackend } from '../ts/util/linuxPasswordStoreMigration.main.ts';
const { chmod, realpath, writeFile } = fsExtra;
const { get, pick, isNumber, isBoolean, some, debounce, noop } = lodash;
@@ -1892,6 +1893,17 @@ const onDatabaseInitializationError = async (error: Error) => {
defaultButtonId = copyErrorAndQuitButtonIndex;
} else if (error instanceof SafeStorageBackendChangeError) {
const { currentBackend, previousBackend } = error;
// Attempt automatic migration
if (await maybeMigrateSafeStorageBackend(previousBackend, currentBackend)) {
log.info(
`Performed auto migration of safeStorage backend from ${previousBackend} to ${currentBackend}. Restarting.`
);
app.relaunch();
app.exit(1);
return;
}
const previousBackendFlag = getOwn(
LINUX_PASSWORD_STORE_FLAGS,
previousBackend
@@ -0,0 +1,68 @@
// Copyright 2026 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* oxlint-disable no-console */
import { exec } from 'node:child_process';
import { userConfig } from '../../app/user_config.main.ts';
export async function maybeMigrateSafeStorageBackend(
previousBackend: string,
newBackend: string
): Promise<boolean> {
if (previousBackend === 'kwallet5' && newBackend === 'kwallet6') {
return upgradeKWallet5To6();
}
if (previousBackend === 'kwallet6' && newBackend === 'kwallet5') {
return downgradeKWallet6To5();
}
return false;
}
async function upgradeKWallet5To6(): Promise<boolean> {
if (await checkCommandSuccess('kwalletd5 --version')) {
console.log(
'kwalletd5 --version check did not fail, so it may still be installed. Aborting upgrade.'
);
return false;
}
if (!(await checkCommandSuccess('kwalletd6 --version'))) {
console.log(
'kwalletd6 --version check did not succeed, so it may not be installed. Aborting upgrade'
);
return false;
}
userConfig.set('safeStorageBackend', 'kwallet6');
return true;
}
async function downgradeKWallet6To5(): Promise<boolean> {
if (await checkCommandSuccess('kwalletd6 --version')) {
console.log(
'kwalletd6 --version check did not fail, so it may still be installed. Aborting upgrade.'
);
return false;
}
if (!(await checkCommandSuccess('kwalletd5 --version'))) {
console.log(
'kwalletd5 --version check did not succeed, so it may not be installed. Aborting upgrade'
);
return false;
}
userConfig.set('safeStorageBackend', 'kwallet5');
return true;
}
function checkCommandSuccess(command: string): Promise<boolean> {
return new Promise(resolve => {
exec(command).on('exit', code => {
resolve(code === 0);
});
});
}