fix(import): strip machine-specific paths when importing backup

A backup made on 'Server A' carries absolute paths (logFilePath,
folderMonitor.folderPath, pendingQueue file paths) that do not exist
on 'Server B' — leading to silent log-write failures, folder-monitor
start errors on missing directories, and queue jobs pointing at
non-existent files.

On import, now:
  - clear logFilePath if its parent directory doesn't exist here
  - clear folderMonitor.folderPath + disable it if the directory is missing
  - clear pendingQueue (queue state is inherently per-machine)

Also harden startup: folder-monitor auto-start now verifies the path
exists and persists enabled=false if not, so one missing-path launch
doesn't keep retrying forever.
This commit is contained in:
Administrator 2026-04-19 11:42:33 +02:00
parent 62a459353a
commit 3472f4e1ed

27
main.js
View File

@ -625,7 +625,14 @@ app.whenReady().then(() => {
const launchConfig = configStore.load(); const launchConfig = configStore.load();
const fm = launchConfig.globalSettings && launchConfig.globalSettings.folderMonitor; const fm = launchConfig.globalSettings && launchConfig.globalSettings.folderMonitor;
if (fm && fm.enabled && fm.folderPath) { if (fm && fm.enabled && fm.folderPath) {
startFolderMonitor(fm); if (fs.existsSync(fm.folderPath)) {
startFolderMonitor(fm);
} else {
debugLog(`folder-monitor auto-start skipped: path not found (${fm.folderPath})`);
// Persist the disable so the user gets a clean state on next launch
const gs = { ...launchConfig.globalSettings, folderMonitor: { ...fm, enabled: false } };
configStore.save({ globalSettings: gs }).catch(() => {});
}
} }
} catch (err) { } catch (err) {
debugLog(`folder-monitor auto-start failed: ${err.message}`); debugLog(`folder-monitor auto-start failed: ${err.message}`);
@ -1051,11 +1058,27 @@ ipcMain.handle('import-backup', async (_event, legacyPassword) => {
const ts = new Date().toISOString().replace(/[:.]/g, '-'); const ts = new Date().toISOString().replace(/[:.]/g, '-');
const preImportPath = configStore.filePath.replace('.json', `.pre-import-${ts}.json`); const preImportPath = configStore.filePath.replace('.json', `.pre-import-${ts}.json`);
try { fs.copyFileSync(configStore.filePath, preImportPath); } catch {} try { fs.copyFileSync(configStore.filePath, preImportPath); } catch {}
// Strip machine-specific state: absolute paths from the source machine will
// not exist on this one (e.g. C:\Users\Administrator\... vs \bakeredwin318\...).
// Any path that does not resolve locally is cleared so the user can re-set it
// instead of hitting silent failures later.
const importedGlobal = imported.globalSettings || {};
if (importedGlobal.logFilePath && !fs.existsSync(path.dirname(importedGlobal.logFilePath))) {
importedGlobal.logFilePath = '';
}
if (importedGlobal.folderMonitor && typeof importedGlobal.folderMonitor === 'object') {
const fm = importedGlobal.folderMonitor;
if (fm.folderPath && !fs.existsSync(fm.folderPath)) {
fm.folderPath = '';
fm.enabled = false;
}
}
importedGlobal.pendingQueue = null;
// Single atomic write — no split state, no TOCTOU race // Single atomic write — no split state, no TOCTOU race
const merged = { const merged = {
hosters: imported.hosters, hosters: imported.hosters,
hosterSettings: imported.hosterSettings, hosterSettings: imported.hosterSettings,
globalSettings: imported.globalSettings, globalSettings: importedGlobal,
history: imported.history || [] history: imported.history || []
}; };
await configStore._atomicWrite(JSON.stringify(merged, null, 2)); await configStore._atomicWrite(JSON.stringify(merged, null, 2));