Redesign backup system: AES-256-GCM encrypted .mdd format

- Replace plaintext JSON export with encrypted binary format (JDownloader 2 style)
- Fixed app-internal key, works on any machine without password
- Export now includes ALL credentials (no more ***-masking), session AND history
- Add debridLinkApiKeys, linkSnappy credentials to sensitive keys list
- Backward-compatible import: auto-detects legacy JSON backups
- File extension changed from .json to .mdd
- MDD1 magic bytes + random IV + GCM auth tag for integrity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sucukdeluxe
2026-03-07 16:39:19 +01:00
co-authored by Claude Opus 4.6
parent ca534196b8
commit 0edd8f6be5
4 changed files with 177 additions and 83 deletions
+8 -7
View File
@@ -476,15 +476,15 @@ function registerIpcHandlers(): void {
ipcMain.handle(IPC_CHANNELS.EXPORT_BACKUP, async () => {
const options = {
defaultPath: `mdd-backup-${new Date().toISOString().slice(0, 10)}.json`,
filters: [{ name: "Backup", extensions: ["json"] }]
defaultPath: `mdd-backup-${new Date().toISOString().slice(0, 10)}.mdd`,
filters: [{ name: "MDD Backup", extensions: ["mdd"] }]
};
const result = mainWindow ? await dialog.showSaveDialog(mainWindow, options) : await dialog.showSaveDialog(options);
if (result.canceled || !result.filePath) {
return { saved: false };
}
const json = controller.exportBackup();
await fs.promises.writeFile(result.filePath, json, "utf8");
const encrypted = controller.exportBackup();
await fs.promises.writeFile(result.filePath, encrypted);
return { saved: true };
});
@@ -535,7 +535,8 @@ function registerIpcHandlers(): void {
const options = {
properties: ["openFile"] as Array<"openFile">,
filters: [
{ name: "Backup", extensions: ["json"] },
{ name: "MDD Backup", extensions: ["mdd"] },
{ name: "Legacy Backup (JSON)", extensions: ["json"] },
{ name: "Alle Dateien", extensions: ["*"] }
]
};
@@ -549,8 +550,8 @@ function registerIpcHandlers(): void {
if (stat.size > BACKUP_MAX_BYTES) {
return { restored: false, message: `Backup-Datei zu groß (max 50 MB, Datei hat ${(stat.size / 1024 / 1024).toFixed(1)} MB)` };
}
const json = await fs.promises.readFile(filePath, "utf8");
return controller.importBackup(json);
const data = await fs.promises.readFile(filePath);
return controller.importBackup(data);
});
controller.onState = (snapshot) => {