pi_masking
v1.0.3
Published
A lightweight Node.js utility to mask sensitive fields in nested JavaScript objects for JSON format. This package recursively masks specified string fields in objects and arrays, ideal for protecting sensitive data like emails, PAN numbers, or phone numbe
Readme
secure-data-masker
A lightweight Node.js utility to mask sensitive fields in nested JavaScript objects for JSON format. This package recursively masks specified string fields in objects and arrays, ideal for protecting sensitive data like emails, PAN numbers, or phone numbers before logging or serializing to JSON.
🚀 Installation
npm install secure-data-masker
🔐 Features
- ✅ Recursively masks string fields in nested objects and arrays
- ✅ Supports both JSON and XML inputs
- ✅ Supports custom mask characters (e.g., *, #)
- ✅ Handles XML namespaces (e.g., xsd1:email)
- ✅ Validates input to ensure JSON-serializability
- ✅ Safe defaults to prevent unintended data exposure
- ✅ Lightweight with minimal dependencies (xml2js only)
- ✅ Async support with Promises
📦 Usage
1. With JSON format.
const masker = require('secure-data-masker');
const information = {
email: '[email protected]',
pan_no: 'ABCDE1234F',
guest: {
phone_no: '9876543210'
},
users: [
{
email: '[email protected]',
pan_no: 'ABCDE1234F',
phone_no: '1234567890'
},
{
email: '[email protected]',
pan_no: 'ZZZZZ9999Z',
phone_no: '9876543210'
}
]
};
const maskOptions = {
maskWith: '*',
fields: ['email', 'pan_no']
};
const masked = masker.maskSensitiveDetails(information, maskOptions);
console.log(JSON.stringify(masked, null, 2));
Output:
{
"email": "*****************",
"pan_no": "**********",
"guest": {
"phone_no": "9876543210"
},
"users": [
{
"email": "*****************",
"pan_no": "**********",
"phone_no": "1234567890"
},
{
"email": "*****************",
"pan_no": "**********",
"phone_no": "9876543210"
}
]
}
2. With Non JSON format
Example 1:
import masker from 'secure-data-masker';
const information = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AvailabilitySearch>
<xmlns>http://www.abc.com/WebServices/Xml</xmlns>
<Authority>
<Org>abcde</Org>
<User>123abc</User>
<Password>abcer456</Password>
<Currency>INR</Currency>
<Language>en</Language>
<TestDebug>false</TestDebug>
<Version>0.0</Version>
</Authority>
<Hotels>
<Id>1234</Id>
</Hotels>
<HotelStayDetails>
<ArrivalDate>2025-09-13</ArrivalDate>
<Nationality>IN</Nationality>
<Nights>1</Nights>
<Room>
<Guests>
<Adult/>
</Guests>
</Room>
</HotelStayDetails>
</AvailabilitySearch>`
const maskOptions = {
maskWith: '*',
fields: ['Org', 'Nationality', "Currency"],
isJson: false
};
const maskedXml = await masker.maskSensitiveDetails(information, maskOptions);
console.log(maskedXml);
Output:
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AvailabilitySearch>
<xmlns>http://www.abc.com/WebServices/Xml</xmlns>
<Authority>
<Org>*****</Org>
<User>123abc</User>
<Password>abcer456</Password>
<Currency>***</Currency>
<Language>en</Language>
<TestDebug>false</TestDebug>
<Version>0.0</Version>
</Authority>
<Hotels>
<Id>1234</Id>
</Hotels>
<HotelStayDetails>
<ArrivalDate>2025-09-13</ArrivalDate>
<Nationality>**</Nationality>
<Nights>1</Nights>
<Room>
<Guests>
<Adult/>
</Guests>
</Room>
</HotelStayDetails>
</AvailabilitySearch>`
Example: 2
const information =
`<soapenv:Envelope xmlns:soapenv="http://schemas.abc.org/soap/envelope/"
xmlns:xsd="http://hotel.com/xsd"
xmlns:xsd1="http://hotel.com/xsd">
<soapenv:Header/>
<soapenv:Body>
<xsd:SearchHotelsRequest>
<xsd1:loginDetails xsd1:email="[email protected]" xsd1:password="12abc"/>
<xsd:criteria>
<xsd1:checkIn>2025-06-20</xsd1:checkIn>
<xsd1:checkOut>2025-06-24</xsd1:checkOut>
<xsd1:clientNationality>IN</xsd1:clientNationality>
<xsd1:hotelSelector>
<xsd1:hotelIds>
<xsd1:hotelId>9090</xsd1:hotelId>
</xsd1:hotelIds>
</xsd1:hotelSelector>
<xsd1:room xsd1:adults="1" xsd1:children="0" xsd1:seqNo="0"></xsd1:room>
<xsd1:room xsd1:adults="1" xsd1:children="1" xsd1:seqNo="1">
<xsd1:childAge>5</xsd1:childAge>
</xsd1:room>
</xsd:criteria>
</xsd:SearchHotelsRequest>
</soapenv:Body>
</soapenv:Envelope>`
const maskOptions = {
maskWith: "*", fields: [
"xsd1:email", "xsd1:password"
],
isJSON: false
}
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<soapenv:Envelope>
<xmlns:soapenv>http://schemas.abc.org/soap/envelope/</xmlns:soapenv>
<xmlns:xsd>http://hotel.com/xsd</xmlns:xsd>
<xmlns:xsd1>http://hotel.com/xsd</xmlns:xsd1>
<soapenv:Header/>
<soapenv:Body>
<xsd:SearchHotelsRequest>
<xsd1:loginDetails>
<xsd1:email>**************</xsd1:email>
<xsd1:password>******</xsd1:password>
</xsd1:loginDetails>
<xsd:criteria>
<xsd1:checkIn>2025-06-20</xsd1:checkIn>
<xsd1:checkOut>2025-06-24</xsd1:checkOut>
<xsd1:clientNationality>IN</xsd1:clientNationality>
<xsd1:hotelSelector>
<xsd1:hotelIds>
<xsd1:hotelId>9090</xsd1:hotelId>
</xsd1:hotelIds>
</xsd1:hotelSelector>
<xsd1:room>
<xsd1:adults>1</xsd1:adults>
<xsd1:children>0</xsd1:children>
<xsd1:seqNo>0</xsd1:seqNo>
</xsd1:room>
<xsd1:room>
<xsd1:adults>1</xsd1:adults>
<xsd1:children>1</xsd1:children>
<xsd1:seqNo>1</xsd1:seqNo>
<xsd1:childAge>5</xsd1:childAge>
</xsd1:room>
</xsd:criteria>
</xsd:SearchHotelsRequest>
</soapenv:Body>
</soapenv:Envelope>
📘 API
maskSensitiveDetails(information, maskOptions)
Parameters:
1. information (Object | Array): A JSON-serializable object or array to be masked.
2. maskOptions (Object - Optional): Configuration object
2a. maskWith (string): Single character used for masking. Default: '*'
2b. fields (array): List of string field names to mask (e.g., ['email', 'pan_no'])
2c. isJson (boolean): Set to true for JSON input, false for non JSON.
Returns:
- Promise<Object|string>: Returns the masked JSON object or XML strin
⚠️ Throws
"Input must be a valid JSON-serializable object or array" – if input is not object or array
"Input is not JSON-serializable" – if input has circular refs or non-JSON-safe values
"maskOptions must be a non-array object" – if maskOptions is invalid
"maskWith must be a single-character string" – if maskWith is not a single char
"fields must be an array of strings" – if field names are not all strings
"Information input must be a string" (for Non JSON mode)
📌 Things Users Should Know
Default Behavior:
If maskOptions is not provided, { maskWith: '*', fields: [] } is used.
If maskWith is omitted, it defaults to '*'.
If fields is omitted, no fields are masked.
JSON Compatibility:
Input must be JSON-serializable (no functions, undefined, or circular references).
Non-serializable inputs will throw an error.
Security Considerations:
Always specify fields explicitly to avoid unintended data leaks.
Only string values are masked. Non-string values (e.g., numbers, objects, null) remain unchanged.
Limitations:
Field name matching is case-sensitive.
The input object is modified in-place. Make a deep copy beforehand if needed.
Non-object or non-array inputs will throw an error.
🧪 Example with Default Options
const masker = require('secure-data-masker');
const data = {
email: '[email protected]',
pan_no: 'ABCDE1234F'
};
const masked = masker.maskSensitiveDetails(data);
console.log(JSON.stringify(masked, null, 2));
Output:
{
"email": "[email protected]",
"pan_no": "ABCDE1234F"
}
🧩 Example with Custom Mask Character
const masker = require('secure-data-masker');
const data = {
email: '[email protected]',
pan_no: 'ABCDE1234F'
};
const maskOptions = {
maskWith: '#',
fields: ['email']
};
const masked = masker.maskSensitiveDetails(data, maskOptions);
console.log(JSON.stringify(masked, null, 2));
Output:
{
"email": "#################",
"pan_no": "ABCDE1234F"
}
📄 License : MIT