diff --git a/packages/spike/src/log.ts b/packages/spike/src/log.ts index e6b1669..a0ed52a 100644 --- a/packages/spike/src/log.ts +++ b/packages/spike/src/log.ts @@ -59,17 +59,22 @@ export function listLogFiles(): string[] { } export function readLogFile(filename: string): StoredLogEvent[] { - // Reject path traversal attempts (e.g. "../../../etc/passwd") - if (filename !== basename(filename)) return [] + const raw = readLogFileRaw(filename) + if (!raw) return [] + return raw + .trim() + .split("\n") + .filter(Boolean) + .map((line) => JSON.parse(line) as StoredLogEvent) +} + +export function readLogFileRaw(filename: string): string | undefined { + if (filename !== basename(filename)) throw new Error("Invalid filename") const path = `${logsDir}/${filename}` try { return readFileSync(path, "utf-8") - .trim() - .split("\n") - .filter(Boolean) - .map((line) => JSON.parse(line) as StoredLogEvent) } catch { - return [] + return } } diff --git a/packages/spike/src/server/index.tsx b/packages/spike/src/server/index.tsx index ff596be..7f1a7dd 100644 --- a/packages/spike/src/server/index.tsx +++ b/packages/spike/src/server/index.tsx @@ -1,7 +1,7 @@ import { serve } from "bun" import { handleGiteaWebhook } from "../bridge" import { startDiscord } from "../discord" -import { log } from "../log" +import { listLogFiles, log, readLogFileRaw } from "../log" import { LogsPage } from "./logs" await startDiscord() @@ -32,7 +32,24 @@ const server = serve({ }, }, "/logs": { - GET: (req) => LogsPage(req), + GET: (req) => { + const accept = req.headers.get("Accept") || "" + const wantsRaw = !accept.includes("text/html") + if (!wantsRaw) return LogsPage(req) + + const file = new URL(req.url).searchParams.get("file") + if (!file) { + const files = listLogFiles() + return Response.json(files) + } + try { + const raw = readLogFileRaw(file) + if (!raw) return new Response("Not found", { status: 404 }) + return new Response(raw, { headers: { "Content-Type": "application/jsonl" } }) + } catch { + return new Response("Internal server error", { status: 500 }) + } + }, }, "/discord/auth": async () => { const permissions = 536870912 // from https://discord.com/developers/applications