sanitize-contents 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,40 +1,127 @@
1
- # sanitize-content
1
+ # sanitize-contents
2
2
 
3
- A robust, lightweight library to sanitize sensitive information (passwords, tokens, connection strings, etc.) from strings and HTML content.
3
+ ![NPM Version](https://img.shields.io/npm/v/sanitize-contents?style=flat-square)
4
+ ![License](https://img.shields.io/npm/l/sanitize-contents?style=flat-square)
5
+ ![Downloads](https://img.shields.io/npm/dm/sanitize-contents?style=flat-square)
4
6
 
5
- ## Features
7
+ A **robust**, **lightweight**, and **customizable** library to sanitize sensitive information (passwords, tokens, API keys, connection strings, PCI/PII data) from strings and HTML content.
6
8
 
7
- - **Connection Strings**: Redacts user:pass from `mongodb://`, `postgres://`, `redis://`, etc.
8
- - **Query Parameters**: Redacts sensitive keys like `api_key`, `access_token`, `secret`, `password` from URLs.
9
- - **Authorization Headers**: Sanitizes `Bearer` and `Basic` auth tokens.
10
- - **Credential Labels**: Identifies and redacts common patterns like `Password: ...`, `API Key: ...`.
11
- - **CURL Auth**: Sanitizes `-u user:pass` flags in curl commands.
12
- - **Lightweight**: Zero dependencies.
9
+ Perfect for logging, error reporting, and audit trails where you need to keep data clean and safe.
13
10
 
14
- ## Installation
11
+ ## ✨ Features
12
+
13
+ - **🚀 Smart Detection**: Automatically identifies connection strings, raw SQL inserts, query parameters, auth headers, and more.
14
+ - **🛡️ Connection Strings**: Redacts credentials from `mongodb://`, `postgres://`, `redis://`, `mysql://`, and generic URIs.
15
+ - **🔑 Keys & Tokens**: Redacts common keys like `api_key`, `access_token`, `secret`, `jwt`, `bearer` tokens.
16
+ - **📝 Credential Labels**: Identifies patterns like `Password: ...`, `API Key: ...` in unstructured text.
17
+ - **🌐 Network Safe**: Sanitizes `Authorization` headers and `curl` command flags (`-u`).
18
+ - **🎨 Customizable**: Choose your replacement string (e.g., `[HIDDEN]`) or remove content entirely.
19
+ - **📄 HTML Support**: Safely sanitizes text content within HTML while preserving valid structure.
20
+ - **⚡ Lightweight**: Minimal overhead, high performance.
21
+
22
+ ## 📦 Installation
15
23
 
16
24
  ```bash
17
- npm install sanitize-content
25
+ npm install sanitize-contents
26
+ ```
27
+
28
+ ## 🚀 Usage
29
+
30
+ ### Basic Sanitization
31
+
32
+ ```javascript
33
+ import { sanitizeContent } from 'sanitize-contents';
34
+
35
+ // Connection Strings
36
+ const dbUrl = 'mongodb://admin:superSecretPassword@localhost:27017/my_app';
37
+ console.log(sanitizeContent(dbUrl));
38
+ // Output: mongodb://[REDACTED]@localhost:27017/my_app
39
+
40
+ // API Keys in URLs
41
+ const apiUrl = 'https://api.example.com?api_key=sk-123456789&lang=en';
42
+ console.log(sanitizeContent(apiUrl));
43
+ // Output: https://api.example.com?api_key=[REDACTED]&lang=en
44
+
45
+ // Authorization Headers
46
+ const authHeader = 'Authorization: Bearer my-confidential-token-value';
47
+ console.log(sanitizeContent(authHeader));
48
+ // Output: Authorization: Bearer [REDACTED]
49
+ ```
50
+
51
+ ### 🛠️ Custom Options
52
+
53
+ You can customize the replacement string or behavior using the options object.
54
+
55
+ #### Custom Replacement Text
56
+
57
+ ```javascript
58
+ const log = 'User password=secret123 failed login.';
59
+ console.log(sanitizeContent(log, { replacement: '[HIDDEN]' }));
60
+ // Output: User password=[HIDDEN] failed login.
18
61
  ```
19
62
 
20
- ## Usage
63
+ #### Complete Removal
64
+
65
+ Pass an empty string to remove the sensitive value entirely.
21
66
 
22
67
  ```javascript
23
- import { sanitizeContent } from 'sanitize-content';
68
+ const sensitive = 'api_key=12345';
69
+ console.log(sanitizeContent(sensitive, { replacement: '' }));
70
+ // Output: api_key=
71
+ ```
72
+
73
+ ### 📄 HTML Content
24
74
 
25
- const rawContent = 'Connecting to mongodb://user:pass123@localhost:27017/db';
26
- const cleanContent = sanitizeContent(rawContent);
27
- // Connecting to mongodb://[REDACTED]@localhost:27017/db
75
+ To sanitize content inside HTML without breaking tags:
28
76
 
29
- const url = 'https://api.example.com?api_key=sk-123456789';
30
- console.log(sanitizeContent(url));
31
- // https://api.example.com?api_key=[REDACTED]
77
+ ```javascript
78
+ import { sanitizeDescription } from 'sanitize-contents';
32
79
 
33
- const header = 'Authorization: Bearer my-secret-token';
34
- console.log(sanitizeContent(header));
35
- // Authorization: Bearer [REDACTED]
80
+ const html = '<div class="user-info">Password: <b>secret123</b></div>';
81
+ const result = sanitizeDescription(html);
82
+ console.log(result.sanitized_text);
83
+ // Output: <div class="user-info">Password: <b>[REDACTED]</b></div>
36
84
  ```
37
85
 
38
- ## License
86
+ ## 🔍 What it Detects
87
+
88
+ - **Databases**: MongoDB, MySQL, Postgres, Redis connection strings.
89
+ - **Web**: HTTP Query Params (`api_key`, `token`, `password`, `secret`, `session`, etc.).
90
+ - **Headers**: `Authorization` (Bearer/Basic), `Cookie` values (if resembling tokens).
91
+ - **Commands**: `curl` auth flags.
92
+ - **Code**: variable assignments like `PASSWORD = "..."`, `const secret = '...'`.
93
+ - **Text**: Natural language credential dumps (`"password is ..."`, `"login with ..."`).
94
+ - **Formats**: JSON (heuristic), XML tags, URL-encoded values.
95
+
96
+
97
+ ## 💡 User Help & Guidelines
98
+
99
+ To ensure the best balance between security and readability, follow these guidelines:
100
+
101
+ ### ✅ Recommended Patterns
102
+ The library is optimized to catch sensitive data following these labels:
103
+ - `password`, `pass`, `pwd`, `secret`, `token`, `key`
104
+ - `api_key`, `access_token`, `auth_token`
105
+ - `credentials`, `creds`
106
+
107
+ Examples that **will** be redacted:
108
+ - `"My password is: mySecret123"`
109
+ - `"Set the api_key to sk_abc123"`
110
+ - `"The token was something like XYZ789"`
111
+
112
+ ### ⚠️ Avoiding False Positives
113
+ We have implemented smart filtering for common words to avoid redacting helpful context.
114
+
115
+ Common words that **will NOT** be redacted (even if they follow a sensitive label):
116
+ - **Prepositions/Transitions**: `in`, `on`, `at`, `by`, `with`, `as`, `of`, `to`, `is`, `was`, `it`
117
+ - **Known Services**: `lastpass`, `home`
118
+ - **Temporary Indicators**: `temp`, `temporary` (e.g., `"temporary: somevalue"` is safe, but `"temporary password: 123"` is redacted)
119
+
120
+ ### 📋 Best Practices for Data Handling
121
+ 1. **Be Specific**: If you are logging a generic value that happens to follow the word "password" (e.g., `"I forgot my password in lastpass"`), the library will correctly ignore "in" and "lastpass".
122
+ 2. **Custom Replacement**: Use `{ replacement: '[HIDDEN]' }` if your log parser expects a specific tag.
123
+ 3. **HTML Sanitization**: Always use `sanitizeDescription()` for HTML strings to prevent accidental injection or breaking of the DOM structure.
124
+
125
+ ## 📄 License
39
126
 
40
127
  ISC
package/dist/index.d.mts CHANGED
@@ -2,16 +2,27 @@
2
2
  * Sanitizes sensitive information from content.
3
3
  * Redacts passwords, connection strings, API keys, etc.
4
4
  */
5
+ /**
6
+ * Options for sanitization.
7
+ */
8
+ interface SanitizeOptions {
9
+ /**
10
+ * The string to replace sensitive content with.
11
+ * Defaults to "[REDACTED]".
12
+ * set empty string to remove the sensitive content.
13
+ */
14
+ replacement?: string;
15
+ }
5
16
  /**
6
17
  * Sanitizes a string by redacting sensitive patterns.
7
18
  */
8
- declare function sanitizeContent(content: string): string;
19
+ declare function sanitizeContent(content: string, options?: SanitizeOptions): string;
9
20
  /**
10
21
  * Sanitizes HTML content by processing only text nodes.
11
22
  * Matches the API of the user's legacy script.
12
23
  */
13
- declare function sanitizeDescription(html: string): {
24
+ declare function sanitizeDescription(html: string, options?: SanitizeOptions): {
14
25
  sanitized_text: string;
15
26
  };
16
27
 
17
- export { sanitizeContent as default, sanitizeContent, sanitizeDescription };
28
+ export { type SanitizeOptions, sanitizeContent as default, sanitizeContent, sanitizeDescription };
package/dist/index.d.ts CHANGED
@@ -2,16 +2,27 @@
2
2
  * Sanitizes sensitive information from content.
3
3
  * Redacts passwords, connection strings, API keys, etc.
4
4
  */
5
+ /**
6
+ * Options for sanitization.
7
+ */
8
+ interface SanitizeOptions {
9
+ /**
10
+ * The string to replace sensitive content with.
11
+ * Defaults to "[REDACTED]".
12
+ * set empty string to remove the sensitive content.
13
+ */
14
+ replacement?: string;
15
+ }
5
16
  /**
6
17
  * Sanitizes a string by redacting sensitive patterns.
7
18
  */
8
- declare function sanitizeContent(content: string): string;
19
+ declare function sanitizeContent(content: string, options?: SanitizeOptions): string;
9
20
  /**
10
21
  * Sanitizes HTML content by processing only text nodes.
11
22
  * Matches the API of the user's legacy script.
12
23
  */
13
- declare function sanitizeDescription(html: string): {
24
+ declare function sanitizeDescription(html: string, options?: SanitizeOptions): {
14
25
  sanitized_text: string;
15
26
  };
16
27
 
17
- export { sanitizeContent as default, sanitizeContent, sanitizeDescription };
28
+ export { type SanitizeOptions, sanitizeContent as default, sanitizeContent, sanitizeDescription };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var g=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var b=(r,e)=>{for(var o in e)g(r,o,{get:e[o],enumerable:!0})},C=(r,e,o,_)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of S(e))!R.call(r,a)&&a!==o&&g(r,a,{get:()=>e[a],enumerable:!(_=A(e,a))||_.enumerable});return r};var N=r=>C(g({},"__esModule",{value:!0}),r);var D={};b(D,{default:()=>O,sanitizeContent:()=>T,sanitizeDescription:()=>I});module.exports=N(D);var f=require("jsdom"),d={CONNECTION_STRING:/([a-z0-9+.-]+:\/\/)([^:@\s]+):([^:@\s]+)@/gi,SQL_INSERT:/\bINSERT\s+INTO\b.*?\((?:[^)]*,\s*)?\b(password|pwd|pass|passcode)\b.*?\)\s*VALUES\s*\((?:[^,']*,|[^,"]*,)*\s*['"]([^'"]+)['"]/gi,HTML_INPUT:/<input[^>]+(?:type=["']password["'](?:\s+[^>]*?)?value=["']([^"']*)["']|value=["']([^"']*)["'](?:\s+[^>]*?)?type=["']password["'])/gi,QUERY_PARAM:/([?&])(api[_-]?key|access[_-]?token|secret|password|pass|passwrod|psswrd|pw|pwd|token|key|auth[_-]?token|u|p|user|username|passcode|wifi[_-]?password|p_?w_?d|confirm[_-]?password|confirm[_-]?pwd)=([^&\s<"']+)/gi,AUTH_TOKEN:/\b(authorization|auth[_-]?token)\s*[:=]\s*(bearer|basic|token)?\s*([a-zA-Z0-9.\-_~+/]{8,})|(?:\b(bearer|basic|token)\s+([a-zA-Z0-9.\-_~+/]{8,}))/gi,JWT:/\beyJ[a-zA-Z0-9._-]{10,}\b/gi,BASE64_PASS:/cGFzc3dvcmQ9[a-zA-Z0-9+/=]+/g,USER_PASS:/\b(user(?:name)?|login)\b\s*[:=\s/]\s*([^"'\s,]+)\s*(?:and\s+)?\b(pass(?:word)?|pwd|p|p_?w_?d)\b\s*[:=\s]\s*([^"'\s<,]+)/gi,SLASH_CRED:/\b(admin|user|root|api_?user)\/([^"'\s,;]{3,})\b/gi,CURL_AUTH:/(^|\s)(-u\s+)([^:\s]+):([^:\s\\]+)/gi,ASSIGNMENT:/\b(DB[_-]?PASSWORD|JWT[_-]?SECRET|SECRET[_-]?KEY|AUTH[_-]?PASSWORD|PASSWORD|SECRET|KEY|WIFI[_-]?PASSWORD|PASSCODE|API[_-]?KEY|CONFIRM[_-]?PASSWORD|PASSWROD)\s*[:=]\s*(?:["']?)([^"'\s;<>]{3,})(?:["']?)/gi,XML_TAG:/<([^>]*password|pass|secret|token|key)>([^<]+)<\/\1>/gi,LABEL_HINT:/(?:\b|["'<])(password|pass|passwrod|psswrd|pw|pwd|api[_-]?key|access[_-]?token|auth[_-]?token|credentials|creds|secret|token|key|passcode|wifi[_-]?password|p_?w_?d|u|p|confirm[_-]?password|confirm[_-]?pwd|actual|temp|temporary|new\s+one|old\s+one|new\s+password|old\s+password)(?:\b|["'>])[^a-zA-Z0-9\s]*\s*(?:[:=\s]|was\s+something\s+like|it\s+was\s+something\s+like|was|is|like|should\s+be|actual\s+was|could\s+be|might\s+be|set\s+to|entered)(?:\s+it)?\s*[:=]?\s*(?:["']?)([^"'\s<>&,;?]+)(?:["']?)(?:\s+or\s+([^"'\s<>&,;?]+))?/gi,URL:/\bhttps?:\/\/[^\s"'<>]+/gi,EMAIL:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,MENTION:/(^|\s|[(\[])(@([a-zA-Z0-9._-]+))/g},p="[REDACTED]",w=/^(value|type|name|id|class|and|or|was|is|it|the|set|to|values|into|select|from|where|union|join|table|input|button|form|label|div|span|script|style|html|body|head|meta|link|header|footer|auth|login|signin|signout|logout|session|cookie|token|true|false|null|undefined|error|success|failed|warn|info|debug|trace|admin|user|root|for|test|testing|staging|placeholder|password|pass|pwd|psswrd|passwrod|token|key|api[_-]?key|secret|hidden|entered|shown|verified)$/i;function l(r,e,o){if(!o||o===p||o.length<1||o.includes(p)||o.includes("__PROTECTED_"))return r;let _=o.replace(/["']/g,"").trim();if(_.length<2||w.test(_)||_.toLowerCase()===e.toLowerCase())return r;let a=r.toLowerCase().indexOf(e.toLowerCase());if(a===-1)return r;let t=r.substring(a+e.length).indexOf(o);if(t===-1)return r;let n=a+e.length+t;return r.substring(0,n)+p+r.substring(n+o.length)}function L(r){return r.replace(/(?<!\w)([A-Za-z\d@$!%*#?&^()_\-+=]{7,64})(?!\w)/g,e=>{if(/^__PROTECTED_/.test(e)||e.includes(p)||w.test(e))return e;let o=/[A-Z]/.test(e),_=/[a-z]/.test(e),a=/\d/.test(e),s=/[@$!%*#?&^()_\-+=]/.test(e);return[o,_,a,s].filter(Boolean).length>=3?p:e})}function T(r){if(!r||typeof r!="string")return r;let e=r;e=e.replace(d.CONNECTION_STRING,"$1"+p+"@"),e=e.replace(d.QUERY_PARAM,"$1$2="+p),e=e.replace(d.XML_TAG,(s,t,n)=>`<${t}>${p}</${t}>`);let o=[];e=e.replace(d.URL,s=>{let t=`__PROTECTED_URL_${o.length}__`;return o.push(s),t});let _=[];e=e.replace(d.EMAIL,s=>{let t=`__PROTECTED_EMAIL_${_.length}__`;return _.push(s),t});let a=[];if(e=e.replace(d.MENTION,(s,t,n)=>{let i=`__PROTECTED_MENTION_${a.length}__`;return a.push(n),t+i}),e=e.replace(d.SQL_INSERT,(s,t,n)=>s.replace(n,p)),e=e.replace(d.HTML_INPUT,(s,t,n)=>{let i=t||n;return i?l(s,"password",i):s}),e=e.replace(d.AUTH_TOKEN,(s,t,n,i,c,u)=>{if(c&&u)return`${c} ${p}`;let E=n?`${n} `:"";return`${t}: ${E}${p}`}),e=e.replace(d.JWT,p),e=e.replace(d.BASE64_PASS,"cGFzc3dvcmQ9W1JFREFDVEVEX1BBU1NXT1JEXQ=="),e=e.replace(d.USER_PASS,(s,t,n,i,c)=>l(s,i,c)),e=e.replace(d.CURL_AUTH,"$1$2$3:"+p),e=e.replace(d.ASSIGNMENT,(s,t,n)=>l(s,t,n)),e=e.replace(d.SLASH_CRED,"$1/"+p),e=e.replace(d.LABEL_HINT,(s,t,n,i)=>{let c=l(s,t,n);return i&&(c=l(c,p,i)),c}),e.toLowerCase().includes("password")&&e.includes(",")){let s=e.split(/\r?\n/),t=-1,n=-1;for(let i=0;i<s.length;i++)if(s[i].includes(",")&&!s[i].toUpperCase().includes("VALUES")){let u=s[i].toLowerCase().split(",").findIndex(E=>E.includes("password")||E.trim()==="pwd");if(u!==-1){t=i,n=u;break}}if(t!==-1){for(let i=t+1;i<s.length;i++){let c=s[i].split(",");c.length>n&&c[n].trim().length>0&&(w.test(c[n].trim())||(c[n]=p,s[i]=c.join(",")))}e=s.join(`
2
- `)}}return e=L(e),e=e.replace(/(\[REDACTED\]\s*){2,}/g,p+" "),o.forEach((s,t)=>{e=e.replace(`__PROTECTED_URL_${t}__`,s)}),_.forEach((s,t)=>{e=e.replace(`__PROTECTED_EMAIL_${t}__`,s)}),a.forEach((s,t)=>{e=e.replace(`__PROTECTED_MENTION_${t}__`,s)}),e}function I(r){if(!r||typeof r!="string")return{sanitized_text:""};let o=new f.JSDOM(`<body>${r}</body>`).window.document,_=a=>{a.nodeType===3?a.textContent&&(a.textContent=T(a.textContent)):a.childNodes.forEach(_)};return _(o.body),{sanitized_text:o.body.innerHTML.trim()}}var O=T;0&&(module.exports={sanitizeContent,sanitizeDescription});
1
+ "use strict";var w=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var C=(n,o)=>{for(var s in o)w(n,s,{get:o[s],enumerable:!0})},N=(n,o,s,e)=>{if(o&&typeof o=="object"||typeof o=="function")for(let p of R(o))!b.call(n,p)&&p!==s&&w(n,p,{get:()=>o[p],enumerable:!(e=A(o,p))||e.enumerable});return n};var L=n=>N(w({},"__esModule",{value:!0}),n);var D={};C(D,{default:()=>$,sanitizeContent:()=>T,sanitizeDescription:()=>h});module.exports=L(D);var S=require("jsdom"),c={CONNECTION_STRING:/([a-z0-9+.-]+:\/\/)([^:@\s]+):([^:@\s]+)@/gi,SQL_INSERT:/\bINSERT\s+INTO\b.*?\((?:[^)]*,\s*)?\b(password|pwd|pass|passcode)\b.*?\)\s*VALUES\s*\((?:[^,']*,|[^,"]*,)*\s*['"]([^'"]+)['"]/gi,HTML_INPUT:/<input[^>]+(?:type=["']password["'](?:\s+[^>]*?)?value=["']([^"']*)["']|value=["']([^"']*)["'](?:\s+[^>]*?)?type=["']password["'])/gi,QUERY_PARAM:/([?&])(api[_-]?key|access[_-]?token|secret|password|pass|passwrod|psswrd|pw|pwd|token|key|auth[_-]?token|u|p|user|username|passcode|wifi[_-]?password|p_?w_?d|confirm[_-]?password|confirm[_-]?pwd)=([^&\s<"']+)/gi,AUTH_TOKEN:/\b(authorization|auth[_-]?token)\s*[:=]\s*(bearer|basic|token)?\s*([a-zA-Z0-9.\-_~+/]{8,})|(?:\b(bearer|basic|token)\s+([a-zA-Z0-9.\-_~+/]{8,}))/gi,JWT:/\beyJ[a-zA-Z0-9._-]{10,}\b/gi,BASE64_PASS:/cGFzc3dvcmQ9[a-zA-Z0-9+/=]+/g,USER_PASS:/\b(user(?:name)?|login)\b\s*[:=\s/]\s*([^"'\s,]+)\s*(?:and\s+)?\b(pass(?:word)?|pwd|p|p_?w_?d)\b\s*[:=\s]\s*([^"'\s<,]+)/gi,SLASH_CRED:/\b(admin|user|root|api_?user)\/([^"'\s,;]{3,})\b/gi,CURL_AUTH:/(^|\s)(-u\s+)([^:\s]+):([^:\s\\]+)/gi,ASSIGNMENT:/\b(DB[_-]?PASSWORD|JWT[_-]?SECRET|SECRET[_-]?KEY|AUTH[_-]?PASSWORD|PASSWORD|SECRET|KEY|WIFI[_-]?PASSWORD|PASSCODE|API[_-]?KEY|CONFIRM[_-]?PASSWORD|PASSWROD)\s*[:=]\s*(?:["']?)([^"'\s;<>]{3,})(?:["']?)/gi,XML_TAG:/<([^>]*password|pass|secret|token|key)>([^<]+)<\/\1>/gi,LABEL_HINT:/(?:\b|["'<])(password|pass|passwrod|psswrd|pw|pwd|api[_-]?key|access[_-]?token|auth[_-]?token|credentials|creds|secret|token|key|passcode|wifi[_-]?password|p_?w_?d|u|p|confirm[_-]?password|confirm[_-]?pwd|actual|new\s+one|old\s+one|new\s+password|old\s+password)(?:\b|["'>])[^a-zA-Z0-9\s]*\s*(?:[:=\s]|was\s+something\s+like|it\s+was\s+something\s+like|was|is|like|should\s+be|actual\s+was|could\s+be|might\s+be|set\s+to|entered)(?:\s+it)?\s*[:=]?\s*(?:["']?)([^"'\s<>&,;?]+)(?:["']?)(?:\s+or\s+([^"'\s<>&,;?]+))?/gi,URL:/\bhttps?:\/\/[^\s"'<>]+/gi,EMAIL:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,MENTION:/(^|\s|[(\[])(@([a-zA-Z0-9._-]+))/g},O="[REDACTED]",f=/^(value|type|name|id|class|and|or|was|is|it|the|set|to|in|on|at|by|with|as|of|home|lastpass|temp|temporary|values|into|select|from|where|union|join|table|input|button|form|label|div|span|script|style|html|body|head|meta|link|header|footer|auth|login|signin|signout|logout|session|cookie|token|true|false|null|undefined|error|success|failed|warn|info|debug|trace|admin|user|root|for|test|testing|staging|placeholder|password|pass|pwd|psswrd|passwrod|token|key|api[_-]?key|secret|hidden|entered|shown|verified)$/i;function u(n,o,s,e){if(!s||s===e||s.length<1||e.length>0&&s.includes(e)||s.includes("__PROTECTED_"))return n;let p=s.replace(/["']/g,"").trim();if(p.length<2||f.test(p)||p.toLowerCase()===o.toLowerCase())return n;let d=n.toLowerCase().indexOf(o.toLowerCase());if(d===-1)return n;let t=n.substring(d+o.length).indexOf(s);if(t===-1)return n;let r=d+o.length+t;return n.substring(0,r)+e+n.substring(r+s.length)}function I(n,o){return n.replace(/(?<!\w)([A-Za-z\d@$!%*#?&^()_\-+=]{7,64})(?!\w)/g,s=>{if(/^__PROTECTED_/.test(s)||s.includes(o)||f.test(s))return s;let e=/[A-Z]/.test(s),p=/[a-z]/.test(s),d=/\d/.test(s),l=/[@$!%*#?&^()_\-+=]/.test(s);return[e,p,d,l].filter(Boolean).length>=3?o:s})}function T(n,o={}){if(!n||typeof n!="string")return n;let s=o.replacement??O,e=n;e=e.replace(c.CONNECTION_STRING,"$1"+s+"@"),e=e.replace(c.QUERY_PARAM,"$1$2="+s),e=e.replace(c.XML_TAG,(t,r,a)=>`<${r}>${s}</${r}>`);let p=[];e=e.replace(c.URL,t=>{let r=`__PROTECTED_URL_${p.length}__`;return p.push(t),r});let d=[];e=e.replace(c.EMAIL,t=>{let r=`__PROTECTED_EMAIL_${d.length}__`;return d.push(t),r});let l=[];if(e=e.replace(c.MENTION,(t,r,a)=>{let i=`__PROTECTED_MENTION_${l.length}__`;return l.push(a),r+i}),e=e.replace(c.SQL_INSERT,(t,r,a)=>t.replace(a,s)),e=e.replace(c.HTML_INPUT,(t,r,a)=>{let i=r||a;return i?u(t,"password",i,s):t}),e=e.replace(c.AUTH_TOKEN,(t,r,a,i,_,g)=>{if(_&&g)return`${_} ${s}`;let E=a?`${a} `:"";return`${r}: ${E}${s}`}),e=e.replace(c.JWT,s),e=e.replace(c.BASE64_PASS,"cGFzc3dvcmQ9W1JFREFDVEVEX1BBU1NXT1JEXQ=="),e=e.replace(c.USER_PASS,(t,r,a,i,_)=>u(t,i,_,s)),e=e.replace(c.CURL_AUTH,"$1$2$3:"+s),e=e.replace(c.ASSIGNMENT,(t,r,a)=>u(t,r,a,s)),e=e.replace(c.SLASH_CRED,"$1/"+s),e=e.replace(c.LABEL_HINT,(t,r,a,i)=>{let _=u(t,r,a,s);return i&&(_=u(_,s,i,s)),_}),e.toLowerCase().includes("password")&&e.includes(",")){let t=e.split(/\r?\n/),r=-1,a=-1;for(let i=0;i<t.length;i++)if(t[i].includes(",")&&!t[i].toUpperCase().includes("VALUES")){let g=t[i].toLowerCase().split(",").findIndex(E=>E.includes("password")||E.trim()==="pwd");if(g!==-1){r=i,a=g;break}}if(r!==-1){for(let i=r+1;i<t.length;i++){let _=t[i].split(",");_.length>a&&_[a].trim().length>0&&(f.test(_[a].trim())||(_[a]=s,t[i]=_.join(",")))}e=t.join(`
2
+ `)}}if(e=I(e,s),s.length>0){let t=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=new RegExp(`(${t}\\s*){2,}`,"g");e=e.replace(r,s+" ")}return p.forEach((t,r)=>{e=e.replace(`__PROTECTED_URL_${r}__`,t)}),d.forEach((t,r)=>{e=e.replace(`__PROTECTED_EMAIL_${r}__`,t)}),l.forEach((t,r)=>{e=e.replace(`__PROTECTED_MENTION_${r}__`,t)}),e}function h(n,o={}){if(!n||typeof n!="string")return{sanitized_text:""};let e=new S.JSDOM(`<body>${n}</body>`).window.document,p=d=>{d.nodeType===3?d.textContent&&(d.textContent=T(d.textContent,o)):d.childNodes.forEach(p)};return p(e.body),{sanitized_text:e.body.innerHTML.trim()}}var $=T;0&&(module.exports={sanitizeContent,sanitizeDescription});
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{JSDOM as T}from"jsdom";var p={CONNECTION_STRING:/([a-z0-9+.-]+:\/\/)([^:@\s]+):([^:@\s]+)@/gi,SQL_INSERT:/\bINSERT\s+INTO\b.*?\((?:[^)]*,\s*)?\b(password|pwd|pass|passcode)\b.*?\)\s*VALUES\s*\((?:[^,']*,|[^,"]*,)*\s*['"]([^'"]+)['"]/gi,HTML_INPUT:/<input[^>]+(?:type=["']password["'](?:\s+[^>]*?)?value=["']([^"']*)["']|value=["']([^"']*)["'](?:\s+[^>]*?)?type=["']password["'])/gi,QUERY_PARAM:/([?&])(api[_-]?key|access[_-]?token|secret|password|pass|passwrod|psswrd|pw|pwd|token|key|auth[_-]?token|u|p|user|username|passcode|wifi[_-]?password|p_?w_?d|confirm[_-]?password|confirm[_-]?pwd)=([^&\s<"']+)/gi,AUTH_TOKEN:/\b(authorization|auth[_-]?token)\s*[:=]\s*(bearer|basic|token)?\s*([a-zA-Z0-9.\-_~+/]{8,})|(?:\b(bearer|basic|token)\s+([a-zA-Z0-9.\-_~+/]{8,}))/gi,JWT:/\beyJ[a-zA-Z0-9._-]{10,}\b/gi,BASE64_PASS:/cGFzc3dvcmQ9[a-zA-Z0-9+/=]+/g,USER_PASS:/\b(user(?:name)?|login)\b\s*[:=\s/]\s*([^"'\s,]+)\s*(?:and\s+)?\b(pass(?:word)?|pwd|p|p_?w_?d)\b\s*[:=\s]\s*([^"'\s<,]+)/gi,SLASH_CRED:/\b(admin|user|root|api_?user)\/([^"'\s,;]{3,})\b/gi,CURL_AUTH:/(^|\s)(-u\s+)([^:\s]+):([^:\s\\]+)/gi,ASSIGNMENT:/\b(DB[_-]?PASSWORD|JWT[_-]?SECRET|SECRET[_-]?KEY|AUTH[_-]?PASSWORD|PASSWORD|SECRET|KEY|WIFI[_-]?PASSWORD|PASSCODE|API[_-]?KEY|CONFIRM[_-]?PASSWORD|PASSWROD)\s*[:=]\s*(?:["']?)([^"'\s;<>]{3,})(?:["']?)/gi,XML_TAG:/<([^>]*password|pass|secret|token|key)>([^<]+)<\/\1>/gi,LABEL_HINT:/(?:\b|["'<])(password|pass|passwrod|psswrd|pw|pwd|api[_-]?key|access[_-]?token|auth[_-]?token|credentials|creds|secret|token|key|passcode|wifi[_-]?password|p_?w_?d|u|p|confirm[_-]?password|confirm[_-]?pwd|actual|temp|temporary|new\s+one|old\s+one|new\s+password|old\s+password)(?:\b|["'>])[^a-zA-Z0-9\s]*\s*(?:[:=\s]|was\s+something\s+like|it\s+was\s+something\s+like|was|is|like|should\s+be|actual\s+was|could\s+be|might\s+be|set\s+to|entered)(?:\s+it)?\s*[:=]?\s*(?:["']?)([^"'\s<>&,;?]+)(?:["']?)(?:\s+or\s+([^"'\s<>&,;?]+))?/gi,URL:/\bhttps?:\/\/[^\s"'<>]+/gi,EMAIL:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,MENTION:/(^|\s|[(\[])(@([a-zA-Z0-9._-]+))/g},a="[REDACTED]",g=/^(value|type|name|id|class|and|or|was|is|it|the|set|to|values|into|select|from|where|union|join|table|input|button|form|label|div|span|script|style|html|body|head|meta|link|header|footer|auth|login|signin|signout|logout|session|cookie|token|true|false|null|undefined|error|success|failed|warn|info|debug|trace|admin|user|root|for|test|testing|staging|placeholder|password|pass|pwd|psswrd|passwrod|token|key|api[_-]?key|secret|hidden|entered|shown|verified)$/i;function l(n,e,i){if(!i||i===a||i.length<1||i.includes(a)||i.includes("__PROTECTED_"))return n;let c=i.replace(/["']/g,"").trim();if(c.length<2||g.test(c)||c.toLowerCase()===e.toLowerCase())return n;let d=n.toLowerCase().indexOf(e.toLowerCase());if(d===-1)return n;let t=n.substring(d+e.length).indexOf(i);if(t===-1)return n;let r=d+e.length+t;return n.substring(0,r)+a+n.substring(r+i.length)}function f(n){return n.replace(/(?<!\w)([A-Za-z\d@$!%*#?&^()_\-+=]{7,64})(?!\w)/g,e=>{if(/^__PROTECTED_/.test(e)||e.includes(a)||g.test(e))return e;let i=/[A-Z]/.test(e),c=/[a-z]/.test(e),d=/\d/.test(e),s=/[@$!%*#?&^()_\-+=]/.test(e);return[i,c,d,s].filter(Boolean).length>=3?a:e})}function w(n){if(!n||typeof n!="string")return n;let e=n;e=e.replace(p.CONNECTION_STRING,"$1"+a+"@"),e=e.replace(p.QUERY_PARAM,"$1$2="+a),e=e.replace(p.XML_TAG,(s,t,r)=>`<${t}>${a}</${t}>`);let i=[];e=e.replace(p.URL,s=>{let t=`__PROTECTED_URL_${i.length}__`;return i.push(s),t});let c=[];e=e.replace(p.EMAIL,s=>{let t=`__PROTECTED_EMAIL_${c.length}__`;return c.push(s),t});let d=[];if(e=e.replace(p.MENTION,(s,t,r)=>{let o=`__PROTECTED_MENTION_${d.length}__`;return d.push(r),t+o}),e=e.replace(p.SQL_INSERT,(s,t,r)=>s.replace(r,a)),e=e.replace(p.HTML_INPUT,(s,t,r)=>{let o=t||r;return o?l(s,"password",o):s}),e=e.replace(p.AUTH_TOKEN,(s,t,r,o,_,u)=>{if(_&&u)return`${_} ${a}`;let E=r?`${r} `:"";return`${t}: ${E}${a}`}),e=e.replace(p.JWT,a),e=e.replace(p.BASE64_PASS,"cGFzc3dvcmQ9W1JFREFDVEVEX1BBU1NXT1JEXQ=="),e=e.replace(p.USER_PASS,(s,t,r,o,_)=>l(s,o,_)),e=e.replace(p.CURL_AUTH,"$1$2$3:"+a),e=e.replace(p.ASSIGNMENT,(s,t,r)=>l(s,t,r)),e=e.replace(p.SLASH_CRED,"$1/"+a),e=e.replace(p.LABEL_HINT,(s,t,r,o)=>{let _=l(s,t,r);return o&&(_=l(_,a,o)),_}),e.toLowerCase().includes("password")&&e.includes(",")){let s=e.split(/\r?\n/),t=-1,r=-1;for(let o=0;o<s.length;o++)if(s[o].includes(",")&&!s[o].toUpperCase().includes("VALUES")){let u=s[o].toLowerCase().split(",").findIndex(E=>E.includes("password")||E.trim()==="pwd");if(u!==-1){t=o,r=u;break}}if(t!==-1){for(let o=t+1;o<s.length;o++){let _=s[o].split(",");_.length>r&&_[r].trim().length>0&&(g.test(_[r].trim())||(_[r]=a,s[o]=_.join(",")))}e=s.join(`
2
- `)}}return e=f(e),e=e.replace(/(\[REDACTED\]\s*){2,}/g,a+" "),i.forEach((s,t)=>{e=e.replace(`__PROTECTED_URL_${t}__`,s)}),c.forEach((s,t)=>{e=e.replace(`__PROTECTED_EMAIL_${t}__`,s)}),d.forEach((s,t)=>{e=e.replace(`__PROTECTED_MENTION_${t}__`,s)}),e}function S(n){if(!n||typeof n!="string")return{sanitized_text:""};let i=new T(`<body>${n}</body>`).window.document,c=d=>{d.nodeType===3?d.textContent&&(d.textContent=w(d.textContent)):d.childNodes.forEach(c)};return c(i.body),{sanitized_text:i.body.innerHTML.trim()}}var R=w;export{R as default,w as sanitizeContent,S as sanitizeDescription};
1
+ import{JSDOM as T}from"jsdom";var a={CONNECTION_STRING:/([a-z0-9+.-]+:\/\/)([^:@\s]+):([^:@\s]+)@/gi,SQL_INSERT:/\bINSERT\s+INTO\b.*?\((?:[^)]*,\s*)?\b(password|pwd|pass|passcode)\b.*?\)\s*VALUES\s*\((?:[^,']*,|[^,"]*,)*\s*['"]([^'"]+)['"]/gi,HTML_INPUT:/<input[^>]+(?:type=["']password["'](?:\s+[^>]*?)?value=["']([^"']*)["']|value=["']([^"']*)["'](?:\s+[^>]*?)?type=["']password["'])/gi,QUERY_PARAM:/([?&])(api[_-]?key|access[_-]?token|secret|password|pass|passwrod|psswrd|pw|pwd|token|key|auth[_-]?token|u|p|user|username|passcode|wifi[_-]?password|p_?w_?d|confirm[_-]?password|confirm[_-]?pwd)=([^&\s<"']+)/gi,AUTH_TOKEN:/\b(authorization|auth[_-]?token)\s*[:=]\s*(bearer|basic|token)?\s*([a-zA-Z0-9.\-_~+/]{8,})|(?:\b(bearer|basic|token)\s+([a-zA-Z0-9.\-_~+/]{8,}))/gi,JWT:/\beyJ[a-zA-Z0-9._-]{10,}\b/gi,BASE64_PASS:/cGFzc3dvcmQ9[a-zA-Z0-9+/=]+/g,USER_PASS:/\b(user(?:name)?|login)\b\s*[:=\s/]\s*([^"'\s,]+)\s*(?:and\s+)?\b(pass(?:word)?|pwd|p|p_?w_?d)\b\s*[:=\s]\s*([^"'\s<,]+)/gi,SLASH_CRED:/\b(admin|user|root|api_?user)\/([^"'\s,;]{3,})\b/gi,CURL_AUTH:/(^|\s)(-u\s+)([^:\s]+):([^:\s\\]+)/gi,ASSIGNMENT:/\b(DB[_-]?PASSWORD|JWT[_-]?SECRET|SECRET[_-]?KEY|AUTH[_-]?PASSWORD|PASSWORD|SECRET|KEY|WIFI[_-]?PASSWORD|PASSCODE|API[_-]?KEY|CONFIRM[_-]?PASSWORD|PASSWROD)\s*[:=]\s*(?:["']?)([^"'\s;<>]{3,})(?:["']?)/gi,XML_TAG:/<([^>]*password|pass|secret|token|key)>([^<]+)<\/\1>/gi,LABEL_HINT:/(?:\b|["'<])(password|pass|passwrod|psswrd|pw|pwd|api[_-]?key|access[_-]?token|auth[_-]?token|credentials|creds|secret|token|key|passcode|wifi[_-]?password|p_?w_?d|u|p|confirm[_-]?password|confirm[_-]?pwd|actual|new\s+one|old\s+one|new\s+password|old\s+password)(?:\b|["'>])[^a-zA-Z0-9\s]*\s*(?:[:=\s]|was\s+something\s+like|it\s+was\s+something\s+like|was|is|like|should\s+be|actual\s+was|could\s+be|might\s+be|set\s+to|entered)(?:\s+it)?\s*[:=]?\s*(?:["']?)([^"'\s<>&,;?]+)(?:["']?)(?:\s+or\s+([^"'\s<>&,;?]+))?/gi,URL:/\bhttps?:\/\/[^\s"'<>]+/gi,EMAIL:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,MENTION:/(^|\s|[(\[])(@([a-zA-Z0-9._-]+))/g},S="[REDACTED]",w=/^(value|type|name|id|class|and|or|was|is|it|the|set|to|in|on|at|by|with|as|of|home|lastpass|temp|temporary|values|into|select|from|where|union|join|table|input|button|form|label|div|span|script|style|html|body|head|meta|link|header|footer|auth|login|signin|signout|logout|session|cookie|token|true|false|null|undefined|error|success|failed|warn|info|debug|trace|admin|user|root|for|test|testing|staging|placeholder|password|pass|pwd|psswrd|passwrod|token|key|api[_-]?key|secret|hidden|entered|shown|verified)$/i;function u(n,_,s,e){if(!s||s===e||s.length<1||e.length>0&&s.includes(e)||s.includes("__PROTECTED_"))return n;let d=s.replace(/["']/g,"").trim();if(d.length<2||w.test(d)||d.toLowerCase()===_.toLowerCase())return n;let p=n.toLowerCase().indexOf(_.toLowerCase());if(p===-1)return n;let t=n.substring(p+_.length).indexOf(s);if(t===-1)return n;let r=p+_.length+t;return n.substring(0,r)+e+n.substring(r+s.length)}function A(n,_){return n.replace(/(?<!\w)([A-Za-z\d@$!%*#?&^()_\-+=]{7,64})(?!\w)/g,s=>{if(/^__PROTECTED_/.test(s)||s.includes(_)||w.test(s))return s;let e=/[A-Z]/.test(s),d=/[a-z]/.test(s),p=/\d/.test(s),l=/[@$!%*#?&^()_\-+=]/.test(s);return[e,d,p,l].filter(Boolean).length>=3?_:s})}function f(n,_={}){if(!n||typeof n!="string")return n;let s=_.replacement??S,e=n;e=e.replace(a.CONNECTION_STRING,"$1"+s+"@"),e=e.replace(a.QUERY_PARAM,"$1$2="+s),e=e.replace(a.XML_TAG,(t,r,o)=>`<${r}>${s}</${r}>`);let d=[];e=e.replace(a.URL,t=>{let r=`__PROTECTED_URL_${d.length}__`;return d.push(t),r});let p=[];e=e.replace(a.EMAIL,t=>{let r=`__PROTECTED_EMAIL_${p.length}__`;return p.push(t),r});let l=[];if(e=e.replace(a.MENTION,(t,r,o)=>{let i=`__PROTECTED_MENTION_${l.length}__`;return l.push(o),r+i}),e=e.replace(a.SQL_INSERT,(t,r,o)=>t.replace(o,s)),e=e.replace(a.HTML_INPUT,(t,r,o)=>{let i=r||o;return i?u(t,"password",i,s):t}),e=e.replace(a.AUTH_TOKEN,(t,r,o,i,c,g)=>{if(c&&g)return`${c} ${s}`;let E=o?`${o} `:"";return`${r}: ${E}${s}`}),e=e.replace(a.JWT,s),e=e.replace(a.BASE64_PASS,"cGFzc3dvcmQ9W1JFREFDVEVEX1BBU1NXT1JEXQ=="),e=e.replace(a.USER_PASS,(t,r,o,i,c)=>u(t,i,c,s)),e=e.replace(a.CURL_AUTH,"$1$2$3:"+s),e=e.replace(a.ASSIGNMENT,(t,r,o)=>u(t,r,o,s)),e=e.replace(a.SLASH_CRED,"$1/"+s),e=e.replace(a.LABEL_HINT,(t,r,o,i)=>{let c=u(t,r,o,s);return i&&(c=u(c,s,i,s)),c}),e.toLowerCase().includes("password")&&e.includes(",")){let t=e.split(/\r?\n/),r=-1,o=-1;for(let i=0;i<t.length;i++)if(t[i].includes(",")&&!t[i].toUpperCase().includes("VALUES")){let g=t[i].toLowerCase().split(",").findIndex(E=>E.includes("password")||E.trim()==="pwd");if(g!==-1){r=i,o=g;break}}if(r!==-1){for(let i=r+1;i<t.length;i++){let c=t[i].split(",");c.length>o&&c[o].trim().length>0&&(w.test(c[o].trim())||(c[o]=s,t[i]=c.join(",")))}e=t.join(`
2
+ `)}}if(e=A(e,s),s.length>0){let t=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=new RegExp(`(${t}\\s*){2,}`,"g");e=e.replace(r,s+" ")}return d.forEach((t,r)=>{e=e.replace(`__PROTECTED_URL_${r}__`,t)}),p.forEach((t,r)=>{e=e.replace(`__PROTECTED_EMAIL_${r}__`,t)}),l.forEach((t,r)=>{e=e.replace(`__PROTECTED_MENTION_${r}__`,t)}),e}function b(n,_={}){if(!n||typeof n!="string")return{sanitized_text:""};let e=new T(`<body>${n}</body>`).window.document,d=p=>{p.nodeType===3?p.textContent&&(p.textContent=f(p.textContent,_)):p.childNodes.forEach(d)};return d(e.body),{sanitized_text:e.body.innerHTML.trim()}}var C=f;export{C as default,f as sanitizeContent,b as sanitizeDescription};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sanitize-contents",
3
- "version": "1.0.0",
4
- "description": "A robust library to sanitize sensitive information from content.",
3
+ "version": "1.0.2",
4
+ "description": "A robust, lightweight, and customizable library to sanitize/redact sensitive information (passwords, tokens, API keys, connection strings) from strings and HTML content.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
@@ -28,7 +28,16 @@
28
28
  "security",
29
29
  "password",
30
30
  "sensitive",
31
- "content"
31
+ "content",
32
+ "pii",
33
+ "gdpr",
34
+ "token",
35
+ "auth",
36
+ "secret",
37
+ "cleaner",
38
+ "filter",
39
+ "data-masking",
40
+ "masking"
32
41
  ],
33
42
  "author": "Kishan",
34
43
  "license": "ISC",