mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-22 02:05:26 -04:00
fix: prevent crashes from corrupted JSON files in storage
- Add null byte/control character detection in storage read/update - Wrap JSON.parse in try-catch with descriptive error messages - Make stats command resilient to corrupted files by catching errors - Fixes 'JSON Parse error: Unterminated string' crashes in stats command
This commit is contained in:
@@ -86,13 +86,13 @@ async function getAllSessions(): Promise<Session.Info[]> {
|
||||
const sessions: Session.Info[] = []
|
||||
|
||||
const projectKeys = await Storage.list(["project"])
|
||||
const projects = await Promise.all(projectKeys.map((key) => Storage.read<Project.Info>(key)))
|
||||
const projects = await Promise.all(projectKeys.map((key) => Storage.read<Project.Info>(key).catch(() => undefined)))
|
||||
|
||||
for (const project of projects) {
|
||||
if (!project) continue
|
||||
|
||||
const sessionKeys = await Storage.list(["session", project.id])
|
||||
const projectSessions = await Promise.all(sessionKeys.map((key) => Storage.read<Session.Info>(key)))
|
||||
const projectSessions = await Promise.all(sessionKeys.map((key) => Storage.read<Session.Info>(key).catch(() => undefined)))
|
||||
|
||||
for (const session of projectSessions) {
|
||||
if (session) {
|
||||
|
||||
@@ -174,8 +174,17 @@ export namespace Storage {
|
||||
if (!content.trim()) {
|
||||
throw new NotFoundError({ message: `Empty file: ${target}` })
|
||||
}
|
||||
const result = JSON.parse(content)
|
||||
return result as T
|
||||
const hasControlCharacters = /[\x00-\x08\x0B\x0C\x0E-\x1F]/.test(content)
|
||||
if (hasControlCharacters) {
|
||||
throw new NotFoundError({ message: `Corrupted file detected: ${target}` })
|
||||
}
|
||||
try {
|
||||
const result = JSON.parse(content)
|
||||
return result as T
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : String(e)
|
||||
throw new NotFoundError({ message: `Failed to parse JSON from ${target}: ${message}` })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -188,10 +197,19 @@ export namespace Storage {
|
||||
if (!content.trim()) {
|
||||
throw new NotFoundError({ message: `Empty file: ${target}` })
|
||||
}
|
||||
const parsed = JSON.parse(content)
|
||||
fn(parsed)
|
||||
await Bun.write(target, JSON.stringify(parsed, null, 2))
|
||||
return parsed as T
|
||||
const hasControlCharacters = /[\x00-\x08\x0B\x0C\x0E-\x1F]/.test(content)
|
||||
if (hasControlCharacters) {
|
||||
throw new NotFoundError({ message: `Corrupted file detected: ${target}` })
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(content)
|
||||
fn(parsed)
|
||||
await Bun.write(target, JSON.stringify(parsed, null, 2))
|
||||
return parsed as T
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : String(e)
|
||||
throw new NotFoundError({ message: `Failed to parse JSON from ${target}: ${message}` })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user