UNPKG

autotel

Version:
167 lines (166 loc) 5.42 kB
// src/attribute-redacting-processor.ts var REDACTOR_PATTERNS = { // Value patterns (match content in attribute values) email: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/gi, phone: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g, ssn: /\b\d{3}[-]?\d{2}[-]?\d{4}\b/g, creditCard: /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g, bearerToken: /Bearer\s+[A-Za-z0-9._~+/=-]+/gi, apiKeyInValue: /(?:api[_-]?key|apikey|api_secret)[=:][\s"']*[A-Za-z0-9_-]+/gi, jwt: /eyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*/g, // Key patterns (match attribute names - redacts entire value) sensitiveKey: /^(password|passwd|pwd|secret|token|api[_-]?key|auth|credential|private[_-]?key|authorization)$/i }; var DEFAULT_VALUE_PATTERNS = [ { name: "email", pattern: REDACTOR_PATTERNS.email }, { name: "phone", pattern: REDACTOR_PATTERNS.phone }, { name: "ssn", pattern: REDACTOR_PATTERNS.ssn }, { name: "creditCard", pattern: REDACTOR_PATTERNS.creditCard } ]; var REDACTOR_PRESETS = { /** * Default preset - covers common PII patterns * Detects: emails, phone numbers, SSNs, credit cards * Redacts keys: password, secret, token, apiKey, auth, credential */ default: { keyPatterns: [REDACTOR_PATTERNS.sensitiveKey], valuePatterns: DEFAULT_VALUE_PATTERNS, replacement: "[REDACTED]" }, /** * Strict preset - more aggressive redaction for high-security environments * Includes everything in default plus: Bearer tokens, JWTs, API keys in values */ strict: { keyPatterns: [REDACTOR_PATTERNS.sensitiveKey, /bearer/i, /jwt/i], valuePatterns: [ ...DEFAULT_VALUE_PATTERNS, { name: "bearerToken", pattern: REDACTOR_PATTERNS.bearerToken }, { name: "apiKeyInValue", pattern: REDACTOR_PATTERNS.apiKeyInValue }, { name: "jwt", pattern: REDACTOR_PATTERNS.jwt } ], replacement: "[REDACTED]" }, /** * PCI-DSS preset - focused on payment card industry compliance * Redacts: credit card numbers, CVV-like patterns, card-related keys */ "pci-dss": { keyPatterns: [/card/i, /cvv/i, /cvc/i, /pan/i, /expir/i, /ccn/i], valuePatterns: [ { name: "creditCard", pattern: REDACTOR_PATTERNS.creditCard } ], replacement: "[REDACTED]" } }; function resolveConfig(config) { if (typeof config === "string") { const preset = REDACTOR_PRESETS[config]; if (!preset) { throw new Error( `Unknown attribute redactor preset: "${config}". Available presets: ${Object.keys(REDACTOR_PRESETS).join(", ")}` ); } return preset; } return config; } function createRedactorFromConfig(config) { if (config.redactor) { return config.redactor; } const keyPatterns = config.keyPatterns ?? []; const valuePatterns = config.valuePatterns ?? []; const defaultReplacement = config.replacement ?? "[REDACTED]"; return (key, value) => { for (const pattern of keyPatterns) { pattern.lastIndex = 0; if (pattern.test(key)) { return defaultReplacement; } } if (typeof value !== "string") { if (Array.isArray(value)) { return value.map((item) => { if (typeof item === "string") { return redactStringValue( item, valuePatterns, defaultReplacement ); } return item; }); } return value; } return redactStringValue(value, valuePatterns, defaultReplacement); }; } function redactStringValue(value, patterns, defaultReplacement) { let result = value; for (const { pattern, replacement } of patterns) { pattern.lastIndex = 0; result = result.replaceAll(pattern, replacement ?? defaultReplacement); } return result; } function createRedactedSpan(span, redactor) { const redactedAttributes = {}; for (const [key, value] of Object.entries(span.attributes)) { if (value !== void 0) { redactedAttributes[key] = redactor(key, value); } } return new Proxy(span, { get(target, prop) { if (prop === "attributes") { return redactedAttributes; } const value = Reflect.get(target, prop); if (typeof value === "function") { return value.bind(target); } return value; } }); } function createAttributeRedactor(config) { return createRedactorFromConfig(resolveConfig(config)); } var AttributeRedactingProcessor = class { wrappedProcessor; redactor; constructor(wrappedProcessor, options) { this.wrappedProcessor = wrappedProcessor; const config = resolveConfig(options.redactor); this.redactor = createRedactorFromConfig(config); } /** * Pass through onStart unchanged - attributes aren't finalized yet */ onStart(span, parentContext) { this.wrappedProcessor.onStart(span, parentContext); } /** * Redact attributes and forward to wrapped processor */ onEnd(span) { try { const redactedSpan = createRedactedSpan(span, this.redactor); this.wrappedProcessor.onEnd(redactedSpan); } catch { this.wrappedProcessor.onEnd(span); } } forceFlush() { return this.wrappedProcessor.forceFlush(); } shutdown() { return this.wrappedProcessor.shutdown(); } }; export { AttributeRedactingProcessor, REDACTOR_PATTERNS, REDACTOR_PRESETS, createAttributeRedactor, createRedactedSpan }; //# sourceMappingURL=chunk-SNINLBEE.js.map //# sourceMappingURL=chunk-SNINLBEE.js.map