diff --git a/src/app/api/_gatewayLogging.ts b/src/app/api/_gatewayLogging.ts index 85dcd3d1..202e2c7c 100644 --- a/src/app/api/_gatewayLogging.ts +++ b/src/app/api/_gatewayLogging.ts @@ -1,4 +1,5 @@ import { logger } from "@/utils/logger"; +import { createHash } from "crypto"; const SENSITIVE_KEY_PATTERN = /authorization|token|api[-_]?key|apikey|secret|password/i; const MAX_STRING_LENGTH = 500; @@ -13,7 +14,16 @@ type JsonLike = function redactValue(value: string): string { if (!value) return "[empty]"; - return `[redacted:${value.length}]`; + const match = value.match(/^(\S+)\s+(.+)$/); + const scheme = match?.[1]; + const secret = match?.[2] ?? value; + const hash = createHash("sha256").update(secret).digest("hex").slice(0, 12); + const preview = + secret.length <= 10 + ? `${secret.slice(0, 2)}...${secret.slice(-2)}` + : `${secret.slice(0, 6)}...${secret.slice(-4)}`; + const prefix = scheme ? `${scheme} ` : ""; + return `${prefix}${preview} (len=${secret.length}, sha256=${hash})`; } function summarizeString(value: string): string | { type: string; length: number; prefix?: string } { @@ -83,6 +93,11 @@ function sanitizeBody(body?: BodyInit | null): JsonLike | undefined { } } +function stringifyForLog(value: JsonLike | undefined): string { + if (value === undefined) return ""; + return JSON.stringify(value); +} + export function logGatewayRequest( label: string, url: string, @@ -93,7 +108,7 @@ export function logGatewayRequest( ...(context || {}), url, method: init.method || "GET", - headers: sanitizeHeaders(init.headers), - params: sanitizeBody(init.body), + headers: stringifyForLog(sanitizeHeaders(init.headers)), + params: stringifyForLog(sanitizeBody(init.body)), }); }