openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
71 lines (70 loc) • 2.93 kB
JavaScript
//#region packages/memory-host-sdk/src/host/error-utils.ts
const SECRET_PATTERNS = [
/\b[A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD)\b\s*[=:]\s*(["']?)([^\s"'\\]+)\1/g,
/[?&](?:access[-_]?token|auth[-_]?token|hook[-_]?token|refresh[-_]?token|api[-_]?key|client[-_]?secret|token|key|secret|password|pass|passwd|auth|signature)=([^&\s"'<>]+)/gi,
/"(?:apiKey|token|secret|password|passwd|accessToken|refreshToken)"\s*:\s*"([^"]+)"/g,
/--(?:api[-_]?key|hook[-_]?token|token|secret|password|passwd)\s+(["']?)([^\s"']+)\1/g,
/Authorization\s*[:=]\s*Bearer\s+([A-Za-z0-9._\-+=]+)/g,
/\bBearer\s+([A-Za-z0-9._\-+=]{18,})\b/g,
/(^|[\s,;])(?:access_token|refresh_token|api[-_]?key|token|secret|password|passwd)=([^\s&#]+)/g,
/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]+?-----END [A-Z ]*PRIVATE KEY-----/g,
/\b(sk-[A-Za-z0-9_-]{8,})\b/g,
/\b(ghp_[A-Za-z0-9]{20,})\b/g,
/\b(github_pat_[A-Za-z0-9_]{20,})\b/g,
/\b(xox[baprs]-[A-Za-z0-9-]{10,})\b/g,
/\b(xapp-[A-Za-z0-9-]{10,})\b/g,
/\b(gsk_[A-Za-z0-9_-]{10,})\b/g,
/\b(AIza[0-9A-Za-z\-_]{20,})\b/g,
/\b(pplx-[A-Za-z0-9_-]{10,})\b/g,
/\b(npm_[A-Za-z0-9]{10,})\b/g,
/\bbot(\d{6,}:[A-Za-z0-9_-]{20,})\b/g,
/\b(\d{6,}:[A-Za-z0-9_-]{20,})\b/g
];
function maskToken(token) {
if (token.length < 18) return "***";
return `${token.slice(0, 6)}...${token.slice(-4)}`;
}
function redactPemBlock(block) {
const lines = block.split(/\r?\n/).filter(Boolean);
if (lines.length < 2) return "***";
return `${lines[0]}\n...redacted...\n${lines[lines.length - 1]}`;
}
function redactMatch(match, groups) {
if (match.includes("PRIVATE KEY-----")) return redactPemBlock(match);
const token = groups.findLast((value) => typeof value === "string" && value.length > 0) ?? match;
const masked = maskToken(token);
return token === match ? masked : match.replace(token, masked);
}
function redactSensitiveText(text) {
let next = text;
for (const pattern of SECRET_PATTERNS) next = next.replace(pattern, (...args) => redactMatch(args[0] ?? "", args.slice(1, -2)));
return next;
}
/** Format unknown errors with causes while redacting likely secrets. */
function formatErrorMessage(err) {
let formatted;
if (err instanceof Error) {
formatted = err.message || err.name || "Error";
let cause = err.cause;
const seen = new Set([err]);
while (cause && !seen.has(cause)) {
seen.add(cause);
if (cause instanceof Error) {
if (cause.message) formatted += ` | ${cause.message}`;
cause = cause.cause;
} else if (typeof cause === "string") {
formatted += ` | ${cause}`;
break;
} else break;
}
} else if (typeof err === "string") formatted = err;
else if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") formatted = String(err);
else try {
formatted = JSON.stringify(err);
} catch {
formatted = Object.prototype.toString.call(err);
}
return redactSensitiveText(formatted);
}
//#endregion
export { formatErrorMessage as t };