fix: complete managed backup key remediation
Recover from structurally valid but undecryptable primary keyrings by selecting a fully cryptographically validated backup or recovery temp and reporting KEYRING_RECOVERED. Keep committed primary writes successful when best-effort post-publication cleanup fails, preventing ambiguous retries after durable local publication. Intercept clipboard writes inside the hidden Electron Main-process integration probe, remove the duplicate key-created toast, and make authoritative refresh coverage differ from optimistic state.
This commit is contained in:
@@ -216,24 +216,34 @@ function createOnlineBackupKeyring({
|
||||
async function readState() {
|
||||
const primary = await readCandidate(filePath);
|
||||
if (primary.status === 'valid') {
|
||||
const primaryState = inspectSource({ ...primary, recovered: false });
|
||||
let primaryModified = 0;
|
||||
try {
|
||||
primaryModified = (await fsImpl.stat(filePath)).mtimeMs;
|
||||
} catch {}
|
||||
const candidates = await recoveryCandidates();
|
||||
if (!firstBlockingIssue(primaryState)) {
|
||||
for (const candidatePath of candidates) {
|
||||
if (!isTemporaryFileName(path.basename(candidatePath))) continue;
|
||||
let candidateModified = 0;
|
||||
try {
|
||||
candidateModified = (await fsImpl.stat(candidatePath)).mtimeMs;
|
||||
} catch {}
|
||||
if (candidateModified <= primaryModified) continue;
|
||||
const candidate = await readCandidate(candidatePath);
|
||||
if (candidate.status !== 'valid') continue;
|
||||
const state = inspectSource({ ...candidate, recovered: true });
|
||||
if (!firstBlockingIssue(state)) return state;
|
||||
}
|
||||
return primaryState;
|
||||
}
|
||||
for (const candidatePath of candidates) {
|
||||
if (!isTemporaryFileName(path.basename(candidatePath))) continue;
|
||||
let candidateModified = 0;
|
||||
try {
|
||||
candidateModified = (await fsImpl.stat(candidatePath)).mtimeMs;
|
||||
} catch {}
|
||||
if (candidateModified <= primaryModified) continue;
|
||||
const candidate = await readCandidate(candidatePath);
|
||||
if (candidate.status !== 'valid') continue;
|
||||
const state = inspectSource({ ...candidate, recovered: true });
|
||||
if (!firstBlockingIssue(state)) return state;
|
||||
}
|
||||
return inspectSource({ ...primary, recovered: false });
|
||||
return primaryState;
|
||||
}
|
||||
const candidates = await recoveryCandidates();
|
||||
let fallback = null;
|
||||
@@ -363,7 +373,9 @@ function createOnlineBackupKeyring({
|
||||
} catch {
|
||||
if (!primaryPublished) throw issueError(KEYRING_ERROR_CODES.structure);
|
||||
}
|
||||
await cleanupTemporaryFiles(recoveryPath);
|
||||
try {
|
||||
await cleanupTemporaryFiles(recoveryPath);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function list() {
|
||||
|
||||
Reference in New Issue
Block a user