28 lines
1.5 KiB
JavaScript
28 lines
1.5 KiB
JavaScript
// Copyright (c) 2026 Gordon Bolton. MIT License.
|
|
// Query-param secrets (SABnzbd apikey, generic token/password params)
|
|
const QUERY_SECRET_PATTERN = /([?&](?:apikey|token|password|api_key|key|secret)=)[^&\s#]*/gi;
|
|
// HTTP auth header values (X-Api-Key, X-MediaBrowser-Token, Authorization, X-Emby-Authorization)
|
|
// Redact everything after the colon to end-of-line (MediaBrowser headers span the full line)
|
|
const HEADER_PATTERN = /(?:x-api-key|x-mediabrowser-token|x-emby-authorization|authorization)\s*:[^\n]*/gi;
|
|
// Bearer tokens
|
|
const BEARER_PATTERN = /bearer\s+[A-Za-z0-9\-._~+/]+=*/gi;
|
|
// Basic auth credentials in URLs (http://user:pass@host)
|
|
const BASIC_AUTH_URL_PATTERN = /\/\/[^:@/\s]+:[^@/\s]+@/gi;
|
|
// Redact only the host:port authority portion of URLs, preserving path/query so
|
|
// other patterns (QUERY_SECRET_PATTERN etc.) can still act on them.
|
|
// Negative lookahead skips URLs already handled by BASIC_AUTH_URL_PATTERN.
|
|
const HOST_PATTERN = /(https?:\/\/)(?!\[REDACTED\]@)([^\s/?#]+)/gi;
|
|
|
|
function sanitizeError(err) {
|
|
let msg = (err && err.message) ? err.message : String(err);
|
|
msg = msg.replace(QUERY_SECRET_PATTERN, '$1[REDACTED]');
|
|
msg = msg.replace(HEADER_PATTERN, (m) => m.split(/[\s:]/)[0] + ':[REDACTED]');
|
|
msg = msg.replace(BEARER_PATTERN, 'bearer [REDACTED]');
|
|
msg = msg.replace(BASIC_AUTH_URL_PATTERN, '//[REDACTED]@'); // must run before HOST_PATTERN
|
|
msg = msg.replace(HOST_PATTERN, '$1[HOST]');
|
|
// Never leak stack traces to API responses
|
|
return msg;
|
|
}
|
|
|
|
module.exports = sanitizeError;
|