A helper utility for logging of WebdriverIO packages with enhanced features like progress logging and masking patterns for secure logging
—
Security-focused utilities for parsing masking patterns and applying masks to sensitive data in log messages. These utilities enable safe logging by automatically obfuscating credentials, tokens, passwords, and other sensitive information using regex patterns.
Parse comma-separated regex pattern strings into an array of RegExp objects for use in masking operations.
/**
* Parses comma-separated regex patterns into RegExp objects
* Supports both /pattern/flags and plain pattern formats
* @param maskingRegexString - String containing regex patterns separated by commas
* @returns Array of RegExp objects or undefined if input is invalid
*/
function parseMaskingPatterns(
maskingRegexString: string | undefined
): RegExp[] | undefined;Supported Pattern Formats:
--key=[^ ]* (becomes new RegExp('--key=[^ ]*'))/--key=[^ ]*/i (becomes new RegExp('--key=[^ ]*', 'i'))--key=[^ ]*,--secret=[^ ]* (comma-separated)/--key=([^ ]*)/i (only captured groups are masked)Usage Examples:
import { parseMaskingPatterns } from '@wdio/logger';
// Parse simple patterns
const patterns1 = parseMaskingPatterns('--key=[^ ]*,--secret=[^ ]*');
// Returns: [/--key=[^ ]*/, /--secret=[^ ]*/]
// Parse patterns with flags
const patterns2 = parseMaskingPatterns('/--key=([^ ]*)/i,/password=([^ ]*)/gi');
// Returns: [/--key=([^ ]*)/i, /password=([^ ]*)/gi]
// Handle mixed formats
const patterns3 = parseMaskingPatterns('token=[^ ]*,/bearer\\s+([^ ]*)/i');
// Returns: [/token=[^ ]*/, /bearer\s+([^ ]*)/i]
// Invalid patterns are filtered out
const patterns4 = parseMaskingPatterns('valid=[^ ]*,invalid[,another=[^ ]*');
// Returns: [/valid=[^ ]*/, /another=[^ ]*/] (invalid pattern excluded)
// Handle undefined/empty input
const patterns5 = parseMaskingPatterns(undefined);
// Returns: undefined
const patterns6 = parseMaskingPatterns('');
// Returns: []Apply masking patterns to text, replacing sensitive data with a masked placeholder.
/**
* Masks sensitive data in text using provided masking patterns
* @param text - The text to mask
* @param maskingPatterns - Array of RegExp patterns to use for masking
* @returns The masked text, or original text if no patterns provided
*/
function mask(
text: string,
maskingPatterns: RegExp[] | undefined
): string;Masking Behavior:
**MASKED****MASKED**Usage Examples:
import { mask, parseMaskingPatterns } from '@wdio/logger';
// Basic masking without capturing groups
const patterns1 = parseMaskingPatterns('--key=[^ ]*');
const result1 = mask('Command: wdio --key=secretKey123 --verbose', patterns1);
// Result: "Command: wdio **MASKED** --verbose"
// Masking with capturing groups (more precise)
const patterns2 = parseMaskingPatterns('/--key=([^ ]*)/');
const result2 = mask('Command: wdio --key=secretKey123 --verbose', patterns2);
// Result: "Command: wdio --key=**MASKED** --verbose"
// Multiple patterns and matches
const patterns3 = parseMaskingPatterns('/--key=([^ ]*)/,/--token=([^ ]*)/');
const result3 = mask('wdio --key=secret --token=abc123 test', patterns3);
// Result: "wdio --key=**MASKED** --token=**MASKED** test"
// Complex patterns with flags
const patterns4 = parseMaskingPatterns('/authorization:\\s*bearer\\s+([^ ]*)/i');
const result4 = mask('Headers: { Authorization: Bearer token123 }', patterns4);
// Result: "Headers: { Authorization: Bearer **MASKED** }"
// Multiple capturing groups
const patterns5 = parseMaskingPatterns('/user:([^ ]*) pass:([^ ]*)/');
const result5 = mask('Connecting with user:admin pass:secret123', patterns5);
// Result: "Connecting with user:**MASKED** pass:**MASKED**"
// Preserve newlines
const text = 'Line 1: --key=secret\nLine 2: normal\n';
const result6 = mask(text, parseMaskingPatterns('--key=([^ ]*)'));
// Result: "Line 1: --key=**MASKED**\nLine 2: normal\n"Constant string used as replacement text for masked sensitive data.
/**
* String constant used to replace masked sensitive data
*/
const SENSITIVE_DATA_REPLACER: "**MASKED**";Usage Examples:
import { SENSITIVE_DATA_REPLACER } from '@wdio/logger';
// Use in custom masking implementations
function customMask(text: string, pattern: RegExp): string {
return text.replace(pattern, SENSITIVE_DATA_REPLACER);
}
// Check for masked content
function containsMaskedData(text: string): boolean {
return text.includes(SENSITIVE_DATA_REPLACER);
}
// Custom validation
if (logMessage.includes(SENSITIVE_DATA_REPLACER)) {
console.log('Log contains masked sensitive data');
}import { parseMaskingPatterns, mask } from '@wdio/logger';
// AWS credentials
const awsPatterns = parseMaskingPatterns(
'/aws_access_key_id=([^ ]*)/i,/aws_secret_access_key=([^ ]*)/i'
);
// Database connections
const dbPatterns = parseMaskingPatterns(
'/password=([^ ]*)/i,/pwd=([^ ]*)/i,/connectionString=([^ ]*)/i'
);
// API tokens and keys
const apiPatterns = parseMaskingPatterns(
'/authorization:\\s*bearer\\s+([^ ]*)/i,/api[_-]?key=([^ ]*)/i,/token=([^ ]*)/i'
);
// URLs with credentials
const urlPatterns = parseMaskingPatterns(
'/\\/\\/([^:]+):([^@]+)@/g' // Matches user:pass in URLs
);
const logText = 'Connecting to mongodb://user:password123@localhost:27017/db';
const masked = mask(logText, urlPatterns);
// Result: "Connecting to mongodb://**MASKED**:**MASKED**@localhost:27017/db"// JSON structures
const jsonPatterns = parseMaskingPatterns(
'/"password"\\s*:\\s*"([^"]*)"/,/"token"\\s*:\\s*"([^"]*)"/,/"secret"\\s*:\\s*"([^"]*)"/i'
);
const jsonLog = 'Request body: {"username": "admin", "password": "secret123"}';
const maskedJson = mask(jsonLog, jsonPatterns);
// Result: 'Request body: {"username": "admin", "password": "**MASKED**"}'
// Command line arguments
const cmdPatterns = parseMaskingPatterns(
'/--[a-zA-Z-]*(?:key|pass|secret|token)[a-zA-Z-]*[=\\s]+([^ ]*)/gi'
);
const cmdLog = 'Executing: myapp --api-key secret123 --db-password mypass --verbose';
const maskedCmd = mask(cmdLog, cmdPatterns);
// Result: "Executing: myapp --api-key **MASKED** --db-password **MASKED** --verbose"safe-regex2 to prevent ReDoS attacksundefined (filtered out) rather than throwingInstall with Tessl CLI
npx tessl i tessl/npm-wdio--logger