@ai-capabilities-suite/mcp-debugger-core
Version:
Core debugging engine for Node.js and TypeScript applications. Provides Inspector Protocol integration, breakpoint management, variable inspection, execution control, profiling, hang detection, and source map support.
262 lines • 7.92 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataMasker = void 0;
/**
* Manages sensitive data masking for variable inspection
* Detects and masks common PII patterns
*/
class DataMasker {
constructor(config = { enabled: false }) {
this.rules = [];
this.config = {
maskEmails: true,
maskPhones: true,
maskCreditCards: true,
maskSSNs: true,
maskApiKeys: true,
maskPasswords: true,
...config,
};
this.initializeRules();
}
/**
* Initialize masking rules based on configuration
* Rules are ordered by specificity to avoid conflicts
*/
initializeRules() {
this.rules = [];
// Apply more specific patterns first to avoid conflicts
if (this.config.maskCreditCards) {
this.rules.push({
name: 'credit_card',
pattern: DataMasker.CREDIT_CARD_PATTERN,
replacement: '[CREDIT_CARD]',
enabled: true,
});
}
if (this.config.maskSSNs) {
this.rules.push({
name: 'ssn',
pattern: DataMasker.SSN_PATTERN,
replacement: '[SSN]',
enabled: true,
});
}
if (this.config.maskApiKeys) {
this.rules.push({
name: 'api_key',
pattern: DataMasker.API_KEY_PATTERN,
replacement: '[API_KEY]',
enabled: true,
});
}
if (this.config.maskPhones) {
this.rules.push({
name: 'phone',
pattern: DataMasker.PHONE_PATTERN,
replacement: '[PHONE]',
enabled: true,
});
}
if (this.config.maskEmails) {
this.rules.push({
name: 'email',
pattern: DataMasker.EMAIL_PATTERN,
replacement: '[EMAIL]',
enabled: true,
});
}
if (this.config.maskPasswords) {
this.rules.push({
name: 'password',
pattern: DataMasker.PASSWORD_PATTERN,
replacement: '$1: [REDACTED]',
enabled: true,
});
}
// Add custom rules
if (this.config.customRules) {
this.rules.push(...this.config.customRules);
}
}
/**
* Mask sensitive data in a string
* @param value The string to mask
* @returns The masked string
*/
maskString(value) {
if (!this.config.enabled) {
return value;
}
let masked = value;
for (const rule of this.rules) {
if (rule.enabled) {
masked = masked.replace(rule.pattern, rule.replacement);
}
}
return masked;
}
/**
* Mask sensitive data (works with both strings and objects)
* @param data The data to mask (string or object)
* @param maxDepth Maximum recursion depth for objects (default: 10)
* @returns The masked data
*/
maskData(data, maxDepth = 10) {
if (!this.config.enabled) {
return data;
}
if (typeof data === 'string') {
return this.maskString(data);
}
return this.maskObject(data, maxDepth);
}
/**
* Mask sensitive data in an object
* Recursively masks all string values in the object
* @param obj The object to mask
* @param maxDepth Maximum recursion depth (default: 10)
* @returns The masked object
*/
maskObject(obj, maxDepth = 10) {
if (!this.config.enabled) {
return obj;
}
return this.maskObjectRecursive(obj, maxDepth, 0);
}
/**
* Recursively mask an object
* @param obj The object to mask
* @param maxDepth Maximum recursion depth
* @param currentDepth Current recursion depth
* @returns The masked object
*/
maskObjectRecursive(obj, maxDepth, currentDepth) {
if (currentDepth >= maxDepth) {
return obj;
}
if (typeof obj === 'string') {
return this.maskString(obj);
}
if (Array.isArray(obj)) {
return obj.map((item) => this.maskObjectRecursive(item, maxDepth, currentDepth + 1));
}
if (obj !== null && typeof obj === 'object') {
const masked = {};
for (const [key, value] of Object.entries(obj)) {
// Mask the key if it contains sensitive information
const maskedKey = this.maskString(key);
masked[maskedKey] = this.maskObjectRecursive(value, maxDepth, currentDepth + 1);
}
return masked;
}
return obj;
}
/**
* Add a custom masking rule
* @param rule The masking rule to add
*/
addRule(rule) {
this.rules.push(rule);
}
/**
* Remove a masking rule by name
* @param name The name of the rule to remove
* @returns True if the rule was found and removed
*/
removeRule(name) {
const index = this.rules.findIndex((rule) => rule.name === name);
if (index !== -1) {
this.rules.splice(index, 1);
return true;
}
return false;
}
/**
* Enable a masking rule by name
* @param name The name of the rule to enable
* @returns True if the rule was found
*/
enableRule(name) {
const rule = this.rules.find((r) => r.name === name);
if (rule) {
rule.enabled = true;
return true;
}
return false;
}
/**
* Disable a masking rule by name
* @param name The name of the rule to disable
* @returns True if the rule was found
*/
disableRule(name) {
const rule = this.rules.find((r) => r.name === name);
if (rule) {
rule.enabled = false;
return true;
}
return false;
}
/**
* Get all masking rules
* @returns Array of all masking rules
*/
getRules() {
return [...this.rules];
}
/**
* Get a masking rule by name
* @param name The name of the rule
* @returns The masking rule or undefined if not found
*/
getRule(name) {
return this.rules.find((rule) => rule.name === name);
}
/**
* Check if masking is enabled
* @returns True if masking is enabled
*/
isEnabled() {
return this.config.enabled;
}
/**
* Enable masking
*/
enable() {
this.config.enabled = true;
}
/**
* Disable masking
*/
disable() {
this.config.enabled = false;
}
/**
* Clear all custom rules
*/
clearCustomRules() {
this.rules = this.rules.filter((rule) => rule.name === 'email' ||
rule.name === 'phone' ||
rule.name === 'credit_card' ||
rule.name === 'ssn' ||
rule.name === 'api_key' ||
rule.name === 'password');
}
/**
* Get the current configuration
* @returns The current configuration
*/
getConfig() {
return { ...this.config };
}
}
exports.DataMasker = DataMasker;
// Common PII patterns
DataMasker.EMAIL_PATTERN = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g;
DataMasker.PHONE_PATTERN = /(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g;
DataMasker.CREDIT_CARD_PATTERN = /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g;
DataMasker.SSN_PATTERN = /\b\d{3}-\d{2}-\d{4}\b/g;
DataMasker.API_KEY_PATTERN = /\b[A-Za-z0-9]{32,}\b/g; // Generic long alphanumeric strings
DataMasker.PASSWORD_PATTERN = /\b(password|passwd|pwd|secret|token)\s*[:=]\s*['"]?([^'"\s]+)['"]?/gi;
//# sourceMappingURL=data-masker.js.map