@nurv-llc/redact-it
v1.0.4
Published
A TypeScript library for redacting sensitive information from objects by matching property names
Maintainers
Readme
@nurv-llc/redact-it
A TypeScript library for redacting sensitive information from objects and arrays by matching property names against configurable filters.
Installation
npm install @nurv-llc/redact-itQuick Start
import { redactIt } from '@nurv-llc/redact-it';
const userData = {
name: 'John Doe',
email: '[email protected]',
phoneNumber: '555-123-4567',
address: '123 Main St',
};
const redacted = redactIt(userData);
console.log(redacted);
// Output: {
// name: 'John Doe',
// email: '[REDACTED]',
// phoneNumber: '[REDACTED]',
// address: '[REDACTED]'
// }More Examples
// Example with various PII types
const sensitiveData = {
name: 'Jane Smith',
email: '[email protected]',
creditCard: '4111-1111-1111-1111',
driverLicense: 'DL123456789',
dateOfBirth: '1990-01-15',
passport: 'US123456789',
apiKey: 'sk_live_abc123xyz',
ipAddress: '192.168.1.100',
bankAccount: '12345678901',
taxId: '12-3456789',
medicalRecord: 'MRN987654321',
nationalId: 'SSN123-45-6789'
};
const redacted = redactIt(sensitiveData);
console.log(redacted);
// Output: {
// name: 'Jane Smith',
// email: '[REDACTED]',
// creditCard: '[REDACTED]',
// driverLicense: '[REDACTED]',
// dateOfBirth: '[REDACTED]',
// passport: '[REDACTED]',
// apiKey: '[REDACTED]',
// ipAddress: '[REDACTED]',
// bankAccount: '[REDACTED]',
// taxId: '[REDACTED]',
// medicalRecord: '[REDACTED]',
// nationalId: '[REDACTED]'
// }How It Works
redact-it searches for property names (keys) that match sensitive data patterns and replaces their values with redaction text. By default, it looks for properties that indicate:
- Email addresses:
email,emailAddress,userEmail, etc. - Phone numbers:
phone,phoneNumber,mobile,cellPhone, etc. - Social Security Numbers:
ssn,socialSecurityNumber,socialSecurity, etc. - Credit Card Information:
creditCard,cardNumber,ccNumber, etc. - Driver's License:
driverLicense,licenseNumber,dlNumber, etc. - Passport Information:
passport,passportNumber,passportId, etc. - IP Addresses:
ipAddress,clientIp,remoteIp, etc. - Passwords & Secrets:
password,token,apiKey,secret, etc. - Bank Account Info:
accountNumber,bankAccount,routingNumber, etc. - Date of Birth:
dateOfBirth,birthDate,dob, etc. - Tax IDs:
taxId,ein,taxpayerId, etc. - Medical Records:
medicalRecord,mrn,patientId, etc. - National IDs:
nationalId,citizenId,personalId, etc.
API Reference
redactIt(data, options?)
Redacts sensitive information from an object or array of objects.
Parameters:
data: Record<string, any> | Record<string, any>[]- The object or array to redactoptions?: RedactOptions- Configuration options
Returns: The redacted data with the same structure as input
RedactOptions
interface RedactOptions {
deepScan?: boolean; // Default: false
caseSensitive?: boolean; // Default: false
filters?: (FilterConfig | string)[];
additionalFilters?: (FilterConfig | string)[];
}FilterConfig
interface FilterConfig {
search: string | RegExp; // Pattern to match property names
replace?: string; // Replacement text (default: '[REDACTED]')
}Configuration Options
deepScan (default: false)
Controls whether to recursively scan nested objects and arrays.
const data = {
user: {
email: '[email protected]',
profile: {
workEmail: '[email protected]',
},
},
};
// Default behavior - only top level
redactIt(data);
// Output: {
// user: {
// email: '[email protected]',
// profile: { workEmail: '[email protected]' }
// }
// }
// Deep scan enabled
redactIt(data, { deepScan: true });
// Output: {
// user: {
// email: '[REDACTED]',
// profile: { workEmail: '[REDACTED]' }
// }
// }caseSensitive (default: false)
Controls whether property name matching is case-sensitive.
const data = {
EMAIL: '[email protected]',
email: '[email protected]',
Phone: '555-0123',
};
// Case insensitive (default)
redactIt(data);
// Output: {
// EMAIL: '[REDACTED]',
// email: '[REDACTED]',
// Phone: '[REDACTED]'
// }
// Case sensitive
redactIt(data, { caseSensitive: true });
// Output: {
// EMAIL: '[email protected]', // No match - EMAIL ≠ email
// email: '[REDACTED]', // Match
// Phone: '555-0123' // No match - Phone ≠ phone
// }filters
Replace default filters entirely with custom ones.
const data = {
email: '[email protected]',
password: 'secret123',
apiKey: 'abc-def-123',
};
redactIt(data, {
filters: [
{ search: 'password', replace: '[HIDDEN]' },
{ search: /.*key.*$/i, replace: '[SECRET]' },
'email', // Reference to default email filter
],
});
// Output: {
// email: '[REDACTED]',
// password: '[HIDDEN]',
// apiKey: '[SECRET]'
// }additionalFilters
Add custom filters while keeping default ones.
const data = {
email: '[email protected]', // Matched by default email filter
phone: '555-0123', // Matched by default phone filter
password: 'secret123', // Matched by additional filter
creditCard: '4111-1111-1111-1111',
};
redactIt(data, {
additionalFilters: [
{ search: 'password', replace: '[HIDDEN]' },
{ search: /credit.*card/i, replace: '[PAYMENT_INFO]' },
],
});
// Output: {
// email: '[REDACTED]',
// phone: '[REDACTED]',
// password: '[HIDDEN]',
// creditCard: '[PAYMENT_INFO]'
// }Advanced Examples
Working with Arrays
const users = [
{ name: 'John', email: '[email protected]', role: 'admin' },
{ name: 'Jane', mobile: '555-0123', role: 'user' },
];
const redacted = redactIt(users);
console.log(redacted);
// Output: [
// { name: 'John', email: '[REDACTED]', role: 'admin' },
// { name: 'Jane', mobile: '[REDACTED]', role: 'user' }
// ]Complex Nested Structures
const complexData = {
company: 'ACME Corp',
employees: [
{
id: 1,
profile: {
name: 'John Doe',
contactInfo: {
email: '[email protected]',
phone: '555-0001',
},
},
},
{
id: 2,
profile: {
name: 'Jane Smith',
contactInfo: {
workEmail: '[email protected]',
mobile: '555-0002',
},
},
},
],
};
const redacted = redactIt(complexData, { deepScan: true });
console.log(redacted);
// Output: {
// company: 'ACME Corp',
// employees: [
// {
// id: 1,
// profile: {
// name: 'John Doe',
// contactInfo: {
// email: '[REDACTED]',
// phone: '[REDACTED]'
// }
// }
// },
// {
// id: 2,
// profile: {
// name: 'Jane Smith',
// contactInfo: {
// workEmail: '[REDACTED]',
// mobile: '[REDACTED]'
// }
// }
// }
// ]
// }Custom Regex Patterns
const data = {
customerEmail: '[email protected]',
internalEmail: '[email protected]',
userPhone: '555-0123',
emergencyContact: '911',
apiToken: 'tok_abc123',
refreshToken: 'ref_xyz789',
};
redactIt(data, {
filters: [
// Only match email properties ending with 'Email' (case insensitive)
{ search: /.*email$/i, replace: '[EMAIL_REDACTED]' },
// Match any property containing 'token'
{ search: /.*token.*/i, replace: '[TOKEN_REDACTED]' },
// Exact match for specific property
{ search: 'emergencyContact', replace: '[EMERGENCY_REDACTED]' },
],
});
// Output: {
// customerEmail: '[EMAIL_REDACTED]',
// internalEmail: '[EMAIL_REDACTED]',
// userPhone: '555-0123', // Not matched by custom filters
// emergencyContact: '[EMERGENCY_REDACTED]',
// apiToken: '[TOKEN_REDACTED]',
// refreshToken: '[TOKEN_REDACTED]'
// }Default Filters
The library includes sixteen built-in filters for common PII types:
| Filter | Pattern Examples | Matches |
| ---------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| email | /^.*email.*$/i | email, emailAddress, userEmail, contactEmail, etc. |
| phone | /^.*(phone\|mobile\|cell\|telephone).*$/i | phone, mobile, cellPhone, telephone, etc. |
| ssn | /^.*(ssn\|social.*security\|socialsecurity).*$/i | ssn, socialSecurityNumber, social_security, etc. |
| creditCard | /^.*(credit.*card\|card.*number\|cc.*number).*$/i | creditCard, cardNumber, ccNumber, paymentCard, etc. |
| driverLicense | /^.*(driver.*license\|license.*number\|dl.*number).*$/i | driverLicense, licenseNumber, dlNumber, drivingLicense, etc. |
| passport | /^.*(passport\|passport.*number\|passport.*id).*$/i | passport, passportNumber, passportId, etc. |
| ipAddress | /^.*(ip.*address\|client.*ip\|remote.*ip\|user.*ip).*$/i| ipAddress, clientIp, remoteIp, userIp, ip, etc. |
| password | /^.*(password\|passwd\|pwd\|token\|secret).*$/i | password, token, apiKey, secret, authToken, accessToken, etc. |
| bankAccount | /^.*(account.*number\|bank.*account\|routing.*number).*$/i| accountNumber, bankAccount, routingNumber, iban, etc. |
| dateOfBirth | /^.*(date.*of.*birth\|birth.*date\|dob\|birthday).*$/i | dateOfBirth, birthDate, dob, birthday, etc. |
| taxId | /^.*(tax.*id\|ein\|taxpayer.*id\|federal.*id).*$/i | taxId, ein, taxpayerId, federalId, taxNumber, etc. |
| medicalRecord | /^.*(medical.*record\|mrn\|patient.*id\|health.*id).*$/i| medicalRecord, mrn, patientId, healthId, medicalNumber, etc. |
| nationalId | /^.*(national.*id\|citizen.*id\|personal.*id).*$/i | nationalId, citizenId, personalId, governmentId, identityNumber, etc. |
| address | /^.*((billing\|shipping\|mailing).*address\|address(line)?\d*\|street\|addr(line)?\d*\|apt\|apartment\|suite\|unit\|po.*box).*$/i | address, billingAddress, shippingAddress, addressLine1, streetAddress, aptNumber, poBox, etc. |
| postalCode | /^.*((postal\|post).*(code\|zip)\|zip(?=(Code\|Postal\|Plus4\|PlusFour\|Id\|[_-]\|$\|\d))\|zipcode).*$/i | zip, zipCode, postalCode, postCode, zip_plus4, zipPostal, etc. |
| securityAnswer | /^.*(security.*question\|security.*answer\|secret.*question\|secret.*answer\|mother.*maiden.*name).*$/i | securityQuestion, securityAnswer, secretQuestion, secretAnswer, motherMaidenName, etc. |
All filters are case-insensitive and match property names containing the specified patterns.
TypeScript Support
The library is written in TypeScript and includes full type definitions:
import { redactIt, RedactOptions, FilterConfig } from '@nurv-llc/redact-it';
// Type-safe options
const options: RedactOptions = {
deepScan: true,
caseSensitive: false,
additionalFilters: [{ search: 'password', replace: '[HIDDEN]' }],
};
// Input and output maintain type structure
interface User {
name: string;
email: string;
phone: string;
}
const user: User = {
name: 'John',
email: '[email protected]',
phone: '555-0123',
};
const redactedUser: User = redactIt(user);Error Handling
The library will throw errors for invalid configurations:
// Error: Unknown default filter
redactIt(data, { filters: ['invalidFilter'] });
// Error: Invalid filter configuration
redactIt(data, { filters: [{ search: null }] });Performance Considerations
- Circular References: The library handles circular references safely without infinite loops
- Large Objects: For very large objects with deep nesting, consider using
deepScan: falseif you only need top-level redaction - Filter Complexity: Simple string filters are faster than complex regex patterns
License
MIT License - see LICENSE file for details.
Development
Prerequisites
- Node.js 16.x or higher
- npm 7.x or higher
Setup
git clone https://github.com/cyb3rsyph0n/redact-it.git
cd redact-it
npm installScripts
npm run build # Build the project
npm run test # Run tests
npm run test:coverage # Run tests with coverage
npm run format # Format code with Prettier
npm run format:check # Check code formatting
npm run type-check # Run TypeScript compiler checkContributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
npm test) - Format your code (
npm run format) - Commit your changes using conventional commits
- Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support
- GitHub Issues: Report bugs or request features
- Documentation: Full API documentation
