feat: add encrypted online settings backup keys

Add immutable client-encrypted settings snapshots with independent MDD2 capability keys so fresh installs can restore configuration without transferring backup files. Keep credentials encrypted end to end, preserve queues and history during import, and avoid exposing identifiers in request URLs or errors. Include the persistent API with quota, rate limits, crash-safe storage locking, durability checks, and end-to-end race and recovery coverage.
This commit is contained in:
Sucukdeluxe
2026-08-07 18:29:06 +02:00
parent 5f19293ed2
commit 6e44e63167
22 changed files with 1832 additions and 44 deletions
+25
View File
@@ -166,6 +166,31 @@ afterEach(async () => {
});
describe("download manager", () => {
it("applies an imported settings snapshot without touching queued items or filesystem workflows", () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-settings-import-"));
tempDirs.push(root);
const settings = { ...defaultSettings(), outputDir: path.join(root, "downloads") };
const manager = new DownloadManager(settings, emptySession(), createStoragePaths(path.join(root, "state")));
manager.addPackages([{ name: "queue", links: ["https://example.com/file.bin"] }]);
const item = Object.values((manager as any).session.items)[0] as { provider: string | null };
item.provider = "realdebrid";
const resolveSpy = vi.spyOn(manager as any, "resolveExistingQueuedOpaqueFilenames");
const cleanupSpy = vi.spyOn(manager as any, "cleanupExistingExtractedArchives");
const retroactiveCleanupSpy = vi.spyOn(manager as any, "applyRetroactiveCleanupPolicy");
manager.setSettings({
...settings,
providerOrder: ["bestdebrid", "realdebrid"],
hosterRouting: { "example.com": "bestdebrid" },
completedCleanupPolicy: "immediate"
}, { settingsOnlyImport: true });
expect(item.provider).toBe("realdebrid");
expect(resolveSpy).not.toHaveBeenCalled();
expect(cleanupSpy).not.toHaveBeenCalled();
expect(retroactiveCleanupSpy).not.toHaveBeenCalled();
});
it("clears the BestDebrid circuit breaker when its token changes", () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "rd-best-token-"));
tempDirs.push(root);