doclyft
Version:
CLI for DocLyft - Interactive documentation generator with hosted documentation support
137 lines (136 loc) • 4.45 kB
JavaScript
;
/**
* Data sanitization utilities for security logging and error handling
* Prevents sensitive information from being exposed in logs or error messages
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.sanitizeObject = sanitizeObject;
exports.sanitizeHeaders = sanitizeHeaders;
exports.sanitizeResponseData = sanitizeResponseData;
exports.sanitizeRequestData = sanitizeRequestData;
// List of sensitive field names that should be sanitized
const SENSITIVE_FIELDS = [
'token', 'api_key', 'apikey', 'password', 'secret', 'key',
'github_token', 'authorization', 'bearer', 'x-api-key',
'access_token', 'refresh_token', 'session_id', 'csrf_token'
];
// List of sensitive header names that should be sanitized
const SENSITIVE_HEADERS = [
'authorization', 'x-api-key', 'apikey', 'cookie', 'set-cookie',
'x-auth-token', 'x-access-token', 'bearer', 'api-key'
];
/**
* Sanitize an object by replacing sensitive values with masked versions
*/
function sanitizeObject(obj, depth = 0) {
if (depth > 10)
return '[Max Depth Reached]'; // Prevent infinite recursion
if (obj === null || obj === undefined)
return obj;
if (typeof obj === 'string') {
return sanitizeString(obj);
}
if (typeof obj !== 'object')
return obj;
if (Array.isArray(obj)) {
return obj.map(item => sanitizeObject(item, depth + 1));
}
const sanitized = {};
for (const [key, value] of Object.entries(obj)) {
const lowerKey = key.toLowerCase();
if (SENSITIVE_FIELDS.some(field => lowerKey.includes(field))) {
sanitized[key] = maskSensitiveValue(value);
}
else {
sanitized[key] = sanitizeObject(value, depth + 1);
}
}
return sanitized;
}
/**
* Sanitize HTTP headers by masking sensitive header values
*/
function sanitizeHeaders(headers) {
if (!headers || typeof headers !== 'object')
return headers;
const sanitized = {};
for (const [key, value] of Object.entries(headers)) {
const lowerKey = key.toLowerCase();
if (SENSITIVE_HEADERS.includes(lowerKey)) {
sanitized[key] = maskSensitiveValue(value);
}
else {
sanitized[key] = value;
}
}
return sanitized;
}
/**
* Sanitize response data by removing or masking sensitive information
*/
function sanitizeResponseData(data) {
if (!data)
return data;
// Handle string responses that might contain sensitive data
if (typeof data === 'string') {
return sanitizeString(data);
}
return sanitizeObject(data);
}
/**
* Sanitize request data for logging
*/
function sanitizeRequestData(data) {
if (!data)
return data;
if (typeof data === 'string') {
try {
const parsed = JSON.parse(data);
return JSON.stringify(sanitizeObject(parsed));
}
catch {
return sanitizeString(data);
}
}
return sanitizeObject(data);
}
/**
* Mask sensitive values while preserving some information for debugging
*/
function maskSensitiveValue(value) {
if (typeof value !== 'string') {
return '[MASKED]';
}
if (value.length <= 8) {
return '[MASKED]';
}
// Show first 4 and last 4 characters for debugging purposes
return `${value.substring(0, 4)}...${value.substring(value.length - 4)}`;
}
/**
* Sanitize strings that might contain sensitive information
*/
function sanitizeString(str) {
if (typeof str !== 'string')
return str;
// Replace potential tokens or API keys with masked versions
const tokenPatterns = [
/ghp_[a-zA-Z0-9]{36}/g, // GitHub personal access tokens
/gho_[a-zA-Z0-9]{36}/g, // GitHub OAuth tokens
/ghu_[a-zA-Z0-9]{36}/g, // GitHub user tokens
/ghs_[a-zA-Z0-9]{36}/g, // GitHub server tokens
/ghr_[a-zA-Z0-9]{76}/g, // GitHub refresh tokens
/github_pat_[a-zA-Z0-9_]{82}/g, // GitHub fine-grained tokens
/dk_prod_[a-zA-Z0-9]{20,}/g, // DocLyft API keys
/Bearer\s+[a-zA-Z0-9._-]+/gi, // Bearer tokens
];
let sanitized = str;
tokenPatterns.forEach(pattern => {
sanitized = sanitized.replace(pattern, (match) => {
if (match.length <= 8)
return '[MASKED]';
return `${match.substring(0, 8)}...[MASKED]`;
});
});
return sanitized;
}