UNPKG

@bugspotter/sdk

Version:

Professional bug reporting SDK with screenshots, session replay, and automatic error capture for web applications

255 lines (254 loc) 9.27 kB
"use strict"; /** * PII Detection and Sanitization Utility - REFACTORED * Follows SOLID, DRY, and KISS principles */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Sanitizer = exports.validatePattern = exports.getPatternsByCategory = exports.getPattern = exports.createPatternConfig = exports.PatternBuilder = exports.PATTERN_CATEGORIES = exports.PATTERN_PRESETS = exports.DEFAULT_PATTERNS = void 0; exports.createSanitizer = createSanitizer; const sanitize_patterns_1 = require("./sanitize-patterns"); var sanitize_patterns_2 = require("./sanitize-patterns"); Object.defineProperty(exports, "DEFAULT_PATTERNS", { enumerable: true, get: function () { return sanitize_patterns_2.DEFAULT_PATTERNS; } }); Object.defineProperty(exports, "PATTERN_PRESETS", { enumerable: true, get: function () { return sanitize_patterns_2.PATTERN_PRESETS; } }); Object.defineProperty(exports, "PATTERN_CATEGORIES", { enumerable: true, get: function () { return sanitize_patterns_2.PATTERN_CATEGORIES; } }); Object.defineProperty(exports, "PatternBuilder", { enumerable: true, get: function () { return sanitize_patterns_2.PatternBuilder; } }); Object.defineProperty(exports, "createPatternConfig", { enumerable: true, get: function () { return sanitize_patterns_2.createPatternConfig; } }); Object.defineProperty(exports, "getPattern", { enumerable: true, get: function () { return sanitize_patterns_2.getPattern; } }); Object.defineProperty(exports, "getPatternsByCategory", { enumerable: true, get: function () { return sanitize_patterns_2.getPatternsByCategory; } }); Object.defineProperty(exports, "validatePattern", { enumerable: true, get: function () { return sanitize_patterns_2.validatePattern; } }); /** * Pattern Manager - SRP: Handles pattern initialization and storage */ class PatternManager { constructor(selectedPatterns, customPatterns) { this.patterns = new Map(); this.initializePatterns(selectedPatterns, customPatterns); } initializePatterns(selectedPatterns, customPatterns) { // Resolve preset to pattern names let patternNames; if (typeof selectedPatterns === 'string') { // It's a preset name like 'all', 'minimal', etc. patternNames = sanitize_patterns_1.PATTERN_PRESETS[selectedPatterns]; } else { // It's an array of pattern names patternNames = selectedPatterns.filter((p) => { return p !== 'custom'; }); } // Get pattern definitions and sort by priority const patternDefs = patternNames.map((name) => { return sanitize_patterns_1.DEFAULT_PATTERNS[name]; }); const sortedPatterns = (0, sanitize_patterns_1.getPatternsByPriority)(patternDefs); // Add built-in patterns in priority order sortedPatterns.forEach((patternDef) => { this.patterns.set(patternDef.name, patternDef.regex); }); // Add custom patterns (convert to PatternDefinition format) customPatterns.forEach((custom) => { this.patterns.set(custom.name, custom.regex); }); } getPatterns() { return this.patterns; } } /** * String Sanitizer - SRP: Handles string-level PII detection and replacement */ class StringSanitizer { constructor(patterns) { this.patterns = patterns; } sanitize(value) { if (typeof value !== 'string') { return value; } let sanitized = value; this.patterns.forEach((regex, name) => { const patternType = name.toUpperCase(); sanitized = sanitized.replace(regex, `[REDACTED-${patternType}]`); }); return sanitized; } } /** * Value Sanitizer - SRP: Handles recursive object/array traversal */ class ValueSanitizer { constructor(stringSanitizer) { this.stringSanitizer = stringSanitizer; } sanitize(value) { // Handle null/undefined if (value == null) { return value; } // Handle strings if (typeof value === 'string') { return this.stringSanitizer.sanitize(value); } // Handle arrays if (Array.isArray(value)) { return value.map((item) => { return this.sanitize(item); }); } // Handle objects if (typeof value === 'object') { return this.sanitizeObject(value); } // Return primitives as-is return value; } sanitizeObject(obj) { const sanitized = {}; for (const [key, val] of Object.entries(obj)) { const sanitizedKey = this.stringSanitizer.sanitize(key); sanitized[sanitizedKey] = this.sanitize(val); } return sanitized; } } /** * Element Matcher - SRP: Handles DOM element exclusion logic */ class ElementMatcher { constructor(excludeSelectors) { this.excludeSelectors = excludeSelectors; } shouldExclude(element) { if (!element || !this.excludeSelectors.length) { return false; } return this.excludeSelectors.some((selector) => { try { return element.matches(selector); } catch (_a) { return false; } }); } } /** * Main Sanitizer - Facade pattern: Coordinates all sanitization operations * SOLID: Open/Closed - easily extensible without modification */ class Sanitizer { constructor(config) { var _a, _b, _c, _d; this.enabled = (_a = config.enabled) !== null && _a !== void 0 ? _a : true; if (!this.enabled) { // Create no-op implementations when disabled this.stringSanitizer = new StringSanitizer(new Map()); this.valueSanitizer = new ValueSanitizer(this.stringSanitizer); this.elementMatcher = new ElementMatcher([]); return; } // Default to 'all' preset if no patterns specified const selectedPatterns = (_b = config.patterns) !== null && _b !== void 0 ? _b : 'all'; const customPatterns = (_c = config.customPatterns) !== null && _c !== void 0 ? _c : []; const excludeSelectors = (_d = config.excludeSelectors) !== null && _d !== void 0 ? _d : []; const patternManager = new PatternManager(selectedPatterns, customPatterns); this.stringSanitizer = new StringSanitizer(patternManager.getPatterns()); this.valueSanitizer = new ValueSanitizer(this.stringSanitizer); this.elementMatcher = new ElementMatcher(excludeSelectors); } /** * Guard clause helper - DRY principle */ guardDisabled(value) { return this.enabled ? undefined : value; } /** * Sanitize any value (string, object, array, etc.) */ sanitize(value) { const guarded = this.guardDisabled(value); if (guarded !== undefined) { return guarded; } return this.valueSanitizer.sanitize(value); } /** * Sanitize console arguments - KISS: delegates to generic sanitize */ sanitizeConsoleArgs(args) { const guarded = this.guardDisabled(args); if (guarded !== undefined) { return guarded; } return args.map((arg) => { return this.sanitize(arg); }); } /** * Sanitize network data - KISS: uses generic sanitize with type safety */ sanitizeNetworkData(data) { const guarded = this.guardDisabled(data); if (guarded !== undefined) { return guarded; } return this.sanitize(data); } /** * Sanitize error - KISS: uses generic sanitize with type safety */ sanitizeError(error) { const guarded = this.guardDisabled(error); if (guarded !== undefined) { return guarded; } return this.sanitize(error); } /** * Check if element should be excluded */ shouldExclude(element) { if (!this.enabled) { return false; } return this.elementMatcher.shouldExclude(element); } /** * Sanitize DOM text node */ sanitizeTextNode(text, element) { const guarded = this.guardDisabled(text); if (guarded !== undefined) { return guarded; } if (this.elementMatcher.shouldExclude(element)) { return text; } return this.stringSanitizer.sanitize(text); } /** * Detect PII patterns in text without sanitizing * Returns a map of pattern names to match counts */ detectPII(text) { const detections = new Map(); if (!this.enabled || !text) { return detections; } for (const [name, regex] of this.stringSanitizer['patterns']) { const matches = text.match(new RegExp(regex, 'g')); if (matches && matches.length > 0) { detections.set(name, matches.length); } } return detections; } } exports.Sanitizer = Sanitizer; /** * Factory function to create a Sanitizer instance */ function createSanitizer(config) { return new Sanitizer(config); }