fix: harden managed online backup key handling
Require canonical encrypted envelopes and surface typed sanitized keyring corruption states. Persist crash-durable primary and recovery files, prevalidate removal plans, isolate renderer refresh authority, and cover the real hidden Windows DPAPI and IPC composition.
This commit is contained in:
@@ -3,6 +3,7 @@ const {
|
||||
deleteOnlineBackup,
|
||||
uploadOnlineBackup
|
||||
} = require('./online-backup');
|
||||
const { KEYRING_ERROR_CODES } = require('./online-backup-keyring');
|
||||
|
||||
const ERRORS = Object.freeze({
|
||||
list: 'Online-Sicherungen konnten nicht geladen werden',
|
||||
@@ -11,6 +12,16 @@ const ERRORS = Object.freeze({
|
||||
delete: 'Online-Sicherung konnte nicht gelöscht werden',
|
||||
notFound: 'Online-Sicherungsschlüssel wurde nicht gefunden'
|
||||
});
|
||||
const KEYRING_MESSAGES = Object.freeze({
|
||||
[KEYRING_ERROR_CODES.structure]: 'Gespeicherter Online-Schlüsselbund ist beschädigt',
|
||||
[KEYRING_ERROR_CODES.unavailable]: 'Sichere Schlüsselspeicherung ist nicht verfügbar',
|
||||
[KEYRING_ERROR_CODES.decrypt]: 'Gespeicherter Online-Sicherungsschlüssel konnte nicht entschlüsselt werden',
|
||||
[KEYRING_ERROR_CODES.mismatch]: 'Gespeicherte Online-Sicherungskennung stimmt nicht mit dem Schlüssel überein',
|
||||
[KEYRING_ERROR_CODES.duplicate]: 'Gespeicherte Online-Sicherungskennung ist mehrdeutig',
|
||||
[KEYRING_ERROR_CODES.recovered]: 'Online-Schlüsselbund wurde aus einer Wiederherstellungsdatei geladen',
|
||||
[KEYRING_ERROR_CODES.encrypt]: 'Online-Sicherungsschlüssel konnte nicht sicher vorbereitet werden',
|
||||
[KEYRING_ERROR_CODES.plan]: 'Online-Sicherung konnte lokal nicht eindeutig entfernt werden'
|
||||
});
|
||||
|
||||
function sanitizeEntry(entry) {
|
||||
return {
|
||||
@@ -28,6 +39,12 @@ function sanitizeCreatedEntry(entry, key) {
|
||||
};
|
||||
}
|
||||
|
||||
function keyringFailure(error, fallback) {
|
||||
const message = KEYRING_MESSAGES[error?.code];
|
||||
if (!message) return { ok: false, error: fallback };
|
||||
return { ok: false, code: error.code, error: message };
|
||||
}
|
||||
|
||||
function createOnlineBackupManager({
|
||||
keyring,
|
||||
loadSettings,
|
||||
@@ -46,8 +63,12 @@ function createOnlineBackupManager({
|
||||
}
|
||||
|
||||
async function listEntries() {
|
||||
const entries = await keyring.list();
|
||||
return entries.map(sanitizeEntry);
|
||||
const snapshot = await keyring.list();
|
||||
if (!snapshot || !Array.isArray(snapshot.entries) || !Array.isArray(snapshot.issues)) throw new Error(ERRORS.list);
|
||||
return {
|
||||
entries: snapshot.entries.map(sanitizeEntry),
|
||||
issues: snapshot.issues
|
||||
};
|
||||
}
|
||||
|
||||
async function createTransaction() {
|
||||
@@ -68,27 +89,39 @@ function createOnlineBackupManager({
|
||||
}
|
||||
|
||||
async function deleteTransaction(id) {
|
||||
const key = await keyring.getKey(id);
|
||||
if (!key) return { ok: false, notFound: true, error: ERRORS.notFound };
|
||||
const outcome = await deleteBackup(key);
|
||||
const plan = await keyring.prepareRemove(id);
|
||||
if (!plan) return { ok: false, notFound: true, error: ERRORS.notFound };
|
||||
const outcome = await deleteBackup(plan.key);
|
||||
if (!outcome?.deleted && !outcome?.notFound) throw new Error(ERRORS.delete);
|
||||
await keyring.remove(id);
|
||||
await keyring.commitRemove(plan);
|
||||
return { ok: true, removedId: id, notFound: outcome.notFound };
|
||||
}
|
||||
|
||||
async function listManaged() {
|
||||
try {
|
||||
return { ok: true, entries: await listEntries() };
|
||||
} catch {
|
||||
return { ok: false, error: ERRORS.list };
|
||||
const snapshot = await listEntries();
|
||||
const issue = snapshot.issues[0];
|
||||
if (!issue) return { ok: true, entries: snapshot.entries };
|
||||
const message = KEYRING_MESSAGES[issue] || ERRORS.list;
|
||||
if (snapshot.entries.length || issue === KEYRING_ERROR_CODES.recovered) {
|
||||
return {
|
||||
ok: true,
|
||||
entries: snapshot.entries,
|
||||
warningCode: issue,
|
||||
warning: message
|
||||
};
|
||||
}
|
||||
return { ok: false, entries: [], code: issue, error: message };
|
||||
} catch (error) {
|
||||
return keyringFailure(error, ERRORS.list);
|
||||
}
|
||||
}
|
||||
|
||||
async function createManaged() {
|
||||
try {
|
||||
return await serialize(createTransaction);
|
||||
} catch {
|
||||
return { ok: false, error: ERRORS.create };
|
||||
} catch (error) {
|
||||
return keyringFailure(error, ERRORS.create);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,16 +131,16 @@ function createOnlineBackupManager({
|
||||
if (!key) return { ok: false, notFound: true, error: ERRORS.notFound };
|
||||
await copyText(key);
|
||||
return { ok: true };
|
||||
} catch {
|
||||
return { ok: false, error: ERRORS.copy };
|
||||
} catch (error) {
|
||||
return keyringFailure(error, ERRORS.copy);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteManaged(id) {
|
||||
try {
|
||||
return await serialize(() => deleteTransaction(id));
|
||||
} catch {
|
||||
return { ok: false, error: ERRORS.delete };
|
||||
} catch (error) {
|
||||
return keyringFailure(error, ERRORS.delete);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user