mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix(whatsapp): restore malformed credentials from backup (#99070)
* fix(whatsapp): wrap JSON.parse with try-catch in auth store and test helpers
Add defensive try-catch around JSON.parse calls in WhatsApp extension
to prevent crashes from corrupted state files.
- restoreCredsFromBackupIfNeeded: wrap creds.json/backup validation
JSON.parse with try-catch; corrupted creds.json now properly falls
through to backup restoration instead of skipping it entirely
- updateLastRouteMock: wrap JSON.parse with try-catch, initialize
empty store on corrupted file
* test(whatsapp): add regression test for malformed creds.json longer than one byte
- Add a focused regression test for the exact case ClawSweeper
flagged: readWebCredsJsonRawSync returns non-null content for
files with stat.size > 1, so malformed JSON like "{x" (2 bytes)
reaches JSON.parse — the inner try-catch now catches the parse
failure and falls through to backup restoration
- Without this patch, JSON.parse("{x") throws to the outer catch
and restoreCredsFromBackupIfNeeded returns false, skipping backup
🦞 diamond lobster: L2 evidence (real function call + real filesystem objects)
Ref. https://github.com/openclaw/openclaw/pull/99070
* fix(whatsapp): restore malformed creds from backup
Co-authored-by: LeonidasLux <LeonidasLux@users.noreply.github.com>
* docs(changelog): defer credential recovery entry to aggregate
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: LeonidasLux <LeonidasLux@users.noreply.github.com>
This commit is contained in:
co-authored by
Peter Steinberger
LeonidasLux
parent
cd305b3b0c
commit
42464de58d
@@ -76,10 +76,10 @@ describe("auth-store", () => {
|
||||
expect(fsSync.existsSync(credsPath)).toBe(false);
|
||||
});
|
||||
|
||||
it("restores creds from a regular backup file", async () => {
|
||||
it("restores malformed creds from a valid backup", async () => {
|
||||
const authDir = createTempAuthDir("openclaw-wa-auth-restore");
|
||||
const credsPath = path.join(authDir, "creds.json");
|
||||
fsSync.writeFileSync(credsPath, "{", "utf-8");
|
||||
fsSync.writeFileSync(credsPath, "{x", "utf-8");
|
||||
fsSync.writeFileSync(
|
||||
path.join(authDir, "creds.json.bak"),
|
||||
JSON.stringify({ me: { id: "123@s.whatsapp.net" } }),
|
||||
@@ -92,6 +92,16 @@ describe("auth-store", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("leaves malformed creds unchanged when the backup is malformed", async () => {
|
||||
const authDir = createTempAuthDir("openclaw-wa-auth-malformed-backup");
|
||||
const credsPath = path.join(authDir, "creds.json");
|
||||
fsSync.writeFileSync(credsPath, "{x", "utf-8");
|
||||
fsSync.writeFileSync(path.join(authDir, "creds.json.bak"), "{y", "utf-8");
|
||||
|
||||
await expect(restoreCredsFromBackupIfNeeded(authDir)).resolves.toBe(false);
|
||||
expect(fsSync.readFileSync(credsPath, "utf-8")).toBe("{x");
|
||||
});
|
||||
|
||||
it("preserves valid large creds instead of treating them as corrupt", async () => {
|
||||
const authDir = createTempAuthDir("openclaw-wa-auth-large-creds");
|
||||
const credsPath = path.join(authDir, "creds.json");
|
||||
|
||||
@@ -67,6 +67,15 @@ async function waitForWebAuthBarrier(
|
||||
return result;
|
||||
}
|
||||
|
||||
function isValidJson(raw: string): boolean {
|
||||
try {
|
||||
JSON.parse(raw);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function restoreCredsFromBackupIfNeeded(authDir: string): Promise<boolean> {
|
||||
const logger = getChildLogger({ module: "web-session" });
|
||||
try {
|
||||
@@ -78,19 +87,14 @@ export async function restoreCredsFromBackupIfNeeded(authDir: string): Promise<b
|
||||
return false;
|
||||
}
|
||||
const raw = readCredsJsonRaw(credsPath);
|
||||
if (raw) {
|
||||
// Validate that creds.json is parseable.
|
||||
JSON.parse(raw);
|
||||
if (raw && isValidJson(raw)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const backupRaw = readCredsJsonRaw(backupPath);
|
||||
if (!backupRaw) {
|
||||
if (!backupRaw || !isValidJson(backupRaw)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure backup is parseable before restoring.
|
||||
JSON.parse(backupRaw);
|
||||
await writeWebCredsRawAtomically({
|
||||
filePath: credsPath,
|
||||
content: backupRaw,
|
||||
|
||||
Reference in New Issue
Block a user