@yellowsakura/js-pii-mask 0.8.93
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/LICENSE +21 -0
- package/README.md +263 -0
- package/dist/index.d.mts +45 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/pii-custom-rules.d.mts +56 -0
- package/dist/pii-custom-rules.d.ts +56 -0
- package/dist/pii-fixed-rules.d.mts +121 -0
- package/dist/pii-fixed-rules.d.ts +121 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yellow Sakura
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# js-pii-mask
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.typescriptlang.org)
|
|
5
|
+
[](https://www.npmjs.com/package/@yellowsakura/js-pii-mask)
|
|
6
|
+
|
|
7
|
+
<img align="left" width="100px" src="docs/logo.webp">
|
|
8
|
+
|
|
9
|
+
Simple lightweight PII (Personally Identifiable Information) masking library for **TypeScript / JavaScript**.
|
|
10
|
+
|
|
11
|
+
It provides **regex-based detection and masking** of common PII patterns, inspired by [OpenAI's guardrails-js](https://github.com/openai/openai-guardrails-js), with a strong focus on **simplicity, predictability, and extensibility**.
|
|
12
|
+
|
|
13
|
+
> ⚠️ Heuristic-based detection: useful in practice, **not a compliance guarantee**.
|
|
14
|
+
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
1. [Features](#features)
|
|
18
|
+
2. [Installation and use](#installation-and-use)
|
|
19
|
+
3. [Supported PII entities](#supported-pii-entities)
|
|
20
|
+
4. [API reference](#api-reference)
|
|
21
|
+
5. [How it works and recommended use cases](#how-it-works-and-recommended-use-cases)
|
|
22
|
+
6. [Licences](#licences)
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- 🔎 Detects **35+ common PII types** (global + regional)
|
|
27
|
+
- 🧩 **Custom rules** for managing specific domains
|
|
28
|
+
- ⚡ Fast, dependency-free, sequential processing
|
|
29
|
+
- ❌ **Cannot**: Understand semantic context or perform deep NLP analysis
|
|
30
|
+
- 🔍 **Trade-offs**: Balanced for minimal false positives, but may miss some edge cases
|
|
31
|
+
|
|
32
|
+
This library is **pattern-based**.
|
|
33
|
+
|
|
34
|
+
**Works well for**:
|
|
35
|
+
- Structured formats (emails, credit cards, SSNs, IBANs, phone numbers)
|
|
36
|
+
|
|
37
|
+
**Does NOT**:
|
|
38
|
+
- Understand semantic context
|
|
39
|
+
- Detect unstructured personal data
|
|
40
|
+
- Perform NER or NLP
|
|
41
|
+
- Guarantee 100% accuracy
|
|
42
|
+
|
|
43
|
+
**Expect**:
|
|
44
|
+
- False positives (numbers matching known formats)
|
|
45
|
+
- False negatives (PII without clear patterns)
|
|
46
|
+
|
|
47
|
+
Always combine with **manual review, access controls, encryption, and legal validation** for sensitive use cases.
|
|
48
|
+
|
|
49
|
+
## Installation and use
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install @yellowsakura/js-pii-mask
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Quick start:
|
|
56
|
+
|
|
57
|
+
For ESM:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { mask } from '@yellowsakura/js-pii-mask'
|
|
61
|
+
|
|
62
|
+
mask('Email: admin@example.com, SSN: 123-45-6789')
|
|
63
|
+
// → "Email: <EMAIL_ADDRESS>, SSN: <US_SSN>"
|
|
64
|
+
|
|
65
|
+
mask('Contact john@example.com or call +1-555-123-4567')
|
|
66
|
+
// → "Contact <EMAIL_ADDRESS> or call +1-<PHONE_NUMBER>"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For CommonJS:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
const { mask, FixedPIIEntity } = require('@yellowsakura/js-pii-mask');
|
|
73
|
+
|
|
74
|
+
mask('Email: admin@example.com, SSN: 123-45-6789')
|
|
75
|
+
// → "Email: <EMAIL_ADDRESS>, SSN: <US_SSN>"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Note:** all the following examples use **ESM syntax**.
|
|
79
|
+
|
|
80
|
+
### Selective fixed rule
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { mask, FixedPIIEntity } from '@yellowsakura/js-pii-mask'
|
|
84
|
+
|
|
85
|
+
// Mask only specific entity types
|
|
86
|
+
mask("Email: test@example.com, SSN: 123-45-6789", {
|
|
87
|
+
fixedPiiEntities: [FixedPIIEntity.EMAIL_ADDRESS]
|
|
88
|
+
})
|
|
89
|
+
// Output: "Email: <EMAIL_ADDRESS>, SSN: 123-45-6789"
|
|
90
|
+
|
|
91
|
+
// Mask only financial information
|
|
92
|
+
mask("Card: 1234-5678-9012-3456, Email: test@example.com", {
|
|
93
|
+
fixedPiiEntities: [FixedPIIEntity.CREDIT_CARD, FixedPIIEntity.US_BANK_NUMBER]
|
|
94
|
+
})
|
|
95
|
+
// Output: "Card: <CREDIT_CARD>, Email: test@example.com"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Custom rules
|
|
99
|
+
|
|
100
|
+
Use custom rules for internal or domain-specific identifiers.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { mask } from '@yellowsakura/js-pii-mask'
|
|
104
|
+
import type { CustomRule } from '@yellowsakura/js-pii-mask'
|
|
105
|
+
|
|
106
|
+
const rules: CustomRule[] = [
|
|
107
|
+
{ pattern: /EMP-\d{5}/g, replacement: 'EMPLOYEE_ID' },
|
|
108
|
+
{ pattern: /TICKET-[A-Z0-9]{8}/gi, replacement: 'TICKET_ID' }
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
mask('Employee EMP-12345 opened TICKET-ABC12345', { customRules: rules })
|
|
112
|
+
// → "Employee <EMPLOYEE_ID> opened <TICKET_ID>"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
> Custom rules are applied **before** built-in PII detection.
|
|
116
|
+
|
|
117
|
+
### Custom + fixed rules
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { mask, FixedPIIEntity } from '@yellowsakura/js-pii-mask'
|
|
121
|
+
import type { CustomRule } from '@yellowsakura/js-pii-mask'
|
|
122
|
+
|
|
123
|
+
mask('Employee EMP-12345 (email: john@company.com) submitted ticket', {
|
|
124
|
+
customRules: [
|
|
125
|
+
{ pattern: /EMP-\d{5}/g, replacement: 'EMPLOYEE_ID' }
|
|
126
|
+
],
|
|
127
|
+
fixedPiiEntities: [FixedPIIEntity.EMAIL_ADDRESS]
|
|
128
|
+
})
|
|
129
|
+
// Output: "Employee <EMPLOYEE_ID> (email: <EMAIL_ADDRESS>) submitted ticket"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Supported PII entities
|
|
133
|
+
|
|
134
|
+
The library includes **35+ predefined patterns**, including:
|
|
135
|
+
|
|
136
|
+
### Global
|
|
137
|
+
- EMAIL_ADDRESS
|
|
138
|
+
- PHONE_NUMBER
|
|
139
|
+
- CREDIT_CARD
|
|
140
|
+
- IP_ADDRESS (IPv4 / IPv6)
|
|
141
|
+
- IBAN_CODE
|
|
142
|
+
- URL
|
|
143
|
+
- DATE_TIME
|
|
144
|
+
|
|
145
|
+
### Country-specific (examples)
|
|
146
|
+
- US: SSN, Passport, Bank Number, ITIN
|
|
147
|
+
- UK: NHS, NINO
|
|
148
|
+
- EU: IT Fiscal Code, VAT, PESEL, NIF/NIE
|
|
149
|
+
- APAC: Aadhaar, PAN, NRIC/FIN, TFN, Medicare
|
|
150
|
+
|
|
151
|
+
Some entities require **context keywords** (e.g. `CVV`, `BIC_SWIFT`) to reduce false positives.
|
|
152
|
+
|
|
153
|
+
For overlapping patterns, explicitly specify `fixedPiiEntities`, see [`src/pii-fixed-rules.ts`](./src/pii-fixed-rules.ts) for an exhaustive list.
|
|
154
|
+
|
|
155
|
+
## API reference
|
|
156
|
+
|
|
157
|
+
### `mask(text: string, options?: MaskOptions): string`
|
|
158
|
+
|
|
159
|
+
Main function to mask PII in text.
|
|
160
|
+
|
|
161
|
+
**Parameters:**
|
|
162
|
+
- `text: string` - The text to scan and mask
|
|
163
|
+
- `options?: MaskOptions` - Optional configuration object
|
|
164
|
+
|
|
165
|
+
**Mask options:**
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
type MaskOptions = {
|
|
169
|
+
// Array of custom masking rules (always applied FIRST)
|
|
170
|
+
customRules?: CustomRule[]
|
|
171
|
+
|
|
172
|
+
// Array of specific fixed PII entities to detect (always applied AFTER custom rules)
|
|
173
|
+
// If empty or undefined, ALL fixed entities are checked
|
|
174
|
+
fixedPiiEntities?: FixedPIIEntity[]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Returns:**
|
|
179
|
+
- `string` - The masked text with PII replaced by `<REPLACED>` placeholders
|
|
180
|
+
|
|
181
|
+
### `CustomRule` interface
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
interface CustomRule {
|
|
185
|
+
// Regular expression pattern to match (should use global flag /g)
|
|
186
|
+
pattern: RegExp
|
|
187
|
+
|
|
188
|
+
// Replacement string (will be wrapped in < >)
|
|
189
|
+
replacement: string
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Guidelines:**
|
|
194
|
+
- Always use global flag (`/g`) to match all occurrences
|
|
195
|
+
- Be specific to avoid matching unintended text
|
|
196
|
+
- Use word boundaries (`\b`) when appropriate
|
|
197
|
+
- Test thoroughly with representative data
|
|
198
|
+
|
|
199
|
+
**Examples:**
|
|
200
|
+
```ts
|
|
201
|
+
// Good: Specific pattern with word boundaries
|
|
202
|
+
{
|
|
203
|
+
pattern: /\bEMP-\d{5}\b/g,
|
|
204
|
+
replacement: 'EMPLOYEE_ID'
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Good: Case-insensitive matching
|
|
208
|
+
{
|
|
209
|
+
pattern: /ticket-[a-z0-9]{8}/gi,
|
|
210
|
+
replacement: 'TICKET_ID'
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Warning: Too broad
|
|
214
|
+
{
|
|
215
|
+
pattern: /\d{5}/g, // Matches any 5 digits
|
|
216
|
+
replacement: 'NUMBER'
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### `FixedPIIEntity` Enum
|
|
221
|
+
|
|
222
|
+
Enumeration of all predefined PII entity types. Import to specify which entities to detect:
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
import { FixedPIIEntity } from '@yellowsakura/js-pii-mask'
|
|
226
|
+
|
|
227
|
+
mask(text, {
|
|
228
|
+
fixedPiiEntities: [
|
|
229
|
+
FixedPIIEntity.EMAIL_ADDRESS,
|
|
230
|
+
FixedPIIEntity.PHONE_NUMBER,
|
|
231
|
+
FixedPIIEntity.US_SSN
|
|
232
|
+
]
|
|
233
|
+
})
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## How it works and recommended use cases:
|
|
237
|
+
|
|
238
|
+
1. Unicode normalization (NFKC, zero-width removal)
|
|
239
|
+
2. Apply custom rules (in order)
|
|
240
|
+
3. Apply fixed PII rules (all or selected)
|
|
241
|
+
4. Replace matches inline
|
|
242
|
+
|
|
243
|
+
Deterministic, sequential, and predictable.
|
|
244
|
+
|
|
245
|
+
## Use cases
|
|
246
|
+
|
|
247
|
+
✅ Test / staging data anonymization
|
|
248
|
+
✅ API response redaction
|
|
249
|
+
✅ Preprocessing before third-party services (e.g. LLM)
|
|
250
|
+
✅ Masking internal identifiers
|
|
251
|
+
|
|
252
|
+
⚠️ Use with caution for:
|
|
253
|
+
- Legal, medical, or financial documents
|
|
254
|
+
- Automated compliance enforcement
|
|
255
|
+
|
|
256
|
+
❌ Not suitable as a standalone compliance solution.
|
|
257
|
+
|
|
258
|
+
# License
|
|
259
|
+
|
|
260
|
+
The code is licensed under the [MIT](https://opensource.org/licenses/MIT) by [Yellow Sakura](https://www.yellowsakura.com), [support@yellowsakura.com](mailto:support@yellowsakura.com), see the LICENSE file.
|
|
261
|
+
For more details, please refer to the [project page](https://www.yellowsakura.com/en/projects/js-pii-mask).
|
|
262
|
+
|
|
263
|
+
This library is adapted from [OpenAI's guardrails-js](https://github.com/openai/openai-guardrails-js) PII detection patterns.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CustomRule } from './pii-custom-rules';
|
|
2
|
+
import { FixedPIIEntity } from './pii-fixed-rules';
|
|
3
|
+
export type { CustomRule } from './pii-custom-rules';
|
|
4
|
+
export { FixedPIIEntity } from './pii-fixed-rules';
|
|
5
|
+
/**
|
|
6
|
+
* Configuration options for the `mask` function.
|
|
7
|
+
*
|
|
8
|
+
* - customRules: Optional array of custom rules for masking text patterns.
|
|
9
|
+
* Each rule defines a regex pattern and its replacement string.
|
|
10
|
+
* - fixedPiiEntities: Optional array of predefined PII (Personally
|
|
11
|
+
* Identifiable Information) entities to mask in the input text.
|
|
12
|
+
*
|
|
13
|
+
* Both properties are optional.
|
|
14
|
+
*/
|
|
15
|
+
type MaskOptions = {
|
|
16
|
+
customRules?: CustomRule[];
|
|
17
|
+
fixedPiiEntities?: FixedPIIEntity[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Mask PII (Personally Identifiable Information) in text.
|
|
21
|
+
*
|
|
22
|
+
* Detects and replaces PII entities with placeholder tokens.
|
|
23
|
+
*
|
|
24
|
+
* @param text - The text to scan and mask
|
|
25
|
+
* @param options - Optional configuration object for masking rules,
|
|
26
|
+
* see .MaskOptions
|
|
27
|
+
*
|
|
28
|
+
* @returns The text with PII entities replaced by placeholders
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Basic usage with default fixed rules
|
|
32
|
+
* mask("Contact me at john@example.com or call 555-123-4567")
|
|
33
|
+
* // Returns: "Contact me at <EMAIL_ADDRESS> or call <PHONE_NUMBER>"
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // With custom rules
|
|
37
|
+
* mask("My name is John Doe", {
|
|
38
|
+
* customRules: [
|
|
39
|
+
* { pattern: /John/gi, replacement: 'FIRST_NAME' },
|
|
40
|
+
* { pattern: /Doe/gi, replacement: 'LAST_NAME' }
|
|
41
|
+
* ]
|
|
42
|
+
* })
|
|
43
|
+
* // Returns: "My name is <FIRST_NAME> <LAST_NAME>"
|
|
44
|
+
*/
|
|
45
|
+
export declare function mask(inputText: string, options?: MaskOptions): string;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CustomRule } from './pii-custom-rules';
|
|
2
|
+
import { FixedPIIEntity } from './pii-fixed-rules';
|
|
3
|
+
export type { CustomRule } from './pii-custom-rules';
|
|
4
|
+
export { FixedPIIEntity } from './pii-fixed-rules';
|
|
5
|
+
/**
|
|
6
|
+
* Configuration options for the `mask` function.
|
|
7
|
+
*
|
|
8
|
+
* - customRules: Optional array of custom rules for masking text patterns.
|
|
9
|
+
* Each rule defines a regex pattern and its replacement string.
|
|
10
|
+
* - fixedPiiEntities: Optional array of predefined PII (Personally
|
|
11
|
+
* Identifiable Information) entities to mask in the input text.
|
|
12
|
+
*
|
|
13
|
+
* Both properties are optional.
|
|
14
|
+
*/
|
|
15
|
+
type MaskOptions = {
|
|
16
|
+
customRules?: CustomRule[];
|
|
17
|
+
fixedPiiEntities?: FixedPIIEntity[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Mask PII (Personally Identifiable Information) in text.
|
|
21
|
+
*
|
|
22
|
+
* Detects and replaces PII entities with placeholder tokens.
|
|
23
|
+
*
|
|
24
|
+
* @param text - The text to scan and mask
|
|
25
|
+
* @param options - Optional configuration object for masking rules,
|
|
26
|
+
* see .MaskOptions
|
|
27
|
+
*
|
|
28
|
+
* @returns The text with PII entities replaced by placeholders
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Basic usage with default fixed rules
|
|
32
|
+
* mask("Contact me at john@example.com or call 555-123-4567")
|
|
33
|
+
* // Returns: "Contact me at <EMAIL_ADDRESS> or call <PHONE_NUMBER>"
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // With custom rules
|
|
37
|
+
* mask("My name is John Doe", {
|
|
38
|
+
* customRules: [
|
|
39
|
+
* { pattern: /John/gi, replacement: 'FIRST_NAME' },
|
|
40
|
+
* { pattern: /Doe/gi, replacement: 'LAST_NAME' }
|
|
41
|
+
* ]
|
|
42
|
+
* })
|
|
43
|
+
* // Returns: "My name is <FIRST_NAME> <LAST_NAME>"
|
|
44
|
+
*/
|
|
45
|
+
export declare function mask(inputText: string, options?: MaskOptions): string;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t){if(!e||!t||t.length===0)return e;for(let n of t){if(!n.pattern||n.replacement===void 0)continue;e=e.replace(n.pattern,`<${n.replacement}>`)}return e}let t=function(e){return e.CREDIT_CARD=`CREDIT_CARD`,e.CRYPTO=`CRYPTO`,e.DATE_TIME=`DATE_TIME`,e.EMAIL_ADDRESS=`EMAIL_ADDRESS`,e.IBAN_CODE=`IBAN_CODE`,e.IP_ADDRESS=`IP_ADDRESS`,e.PHONE_NUMBER=`PHONE_NUMBER`,e.URL=`URL`,e.CVV=`CVV`,e.BIC_SWIFT=`BIC_SWIFT`,e.US_BANK_NUMBER=`US_BANK_NUMBER`,e.US_DRIVER_LICENSE=`US_DRIVER_LICENSE`,e.US_ITIN=`US_ITIN`,e.US_PASSPORT=`US_PASSPORT`,e.US_SSN=`US_SSN`,e.UK_NHS=`UK_NHS`,e.UK_NINO=`UK_NINO`,e.ES_NIF=`ES_NIF`,e.ES_NIE=`ES_NIE`,e.IT_FISCAL_CODE=`IT_FISCAL_CODE`,e.IT_DOCUMENT=`IT_DOCUMENT`,e.IT_VAT_CODE=`IT_VAT_CODE`,e.PL_PESEL=`PL_PESEL`,e.FI_PERSONAL_IDENTITY_CODE=`FI_PERSONAL_IDENTITY_CODE`,e.SG_NRIC_FIN=`SG_NRIC_FIN`,e.SG_UEN=`SG_UEN`,e.AU_ABN=`AU_ABN`,e.AU_ACN=`AU_ACN`,e.AU_TFN=`AU_TFN`,e.AU_MEDICARE=`AU_MEDICARE`,e.IN_PAN=`IN_PAN`,e.IN_AADHAAR=`IN_AADHAAR`,e.IN_VEHICLE_REGISTRATION=`IN_VEHICLE_REGISTRATION`,e.IN_VOTER=`IN_VOTER`,e.IN_PASSPORT=`IN_PASSPORT`,e.KR_RRN=`KR_RRN`,e}({});const n=[`(?:[sS][wW][iI][fF][tT])`,`(?:[bB][iI][cC])`,`(?:[bB][aA][nN][kK][\\s-]?[cC][oO][dD][eE])`,`(?:[sS][wW][iI][fF][tT][\\s-]?[cC][oO][dD][eE])`,`(?:[bB][iI][cC][\\s-]?[cC][oO][dD][eE])`].join(`|`),r=RegExp(`(?:${n})[:\\s=]+([A-Z]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A-Z0-9]{3})?)\\b`,`g`),i={[t.CREDIT_CARD]:[/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g],[t.CRYPTO]:[/\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b/g],[t.DATE_TIME]:[/\b(0[1-9]|1[0-2])[/-](0[1-9]|[12]\d|3[01])[/-](19|20)\d{2}\b/g],[t.EMAIL_ADDRESS]:[/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,RegExp(`(?<=[?&=/])[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}`,`g`)],[t.IBAN_CODE]:[/\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\b/g],[t.IP_ADDRESS]:[/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/g,/\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g,/\b(?:[0-9a-fA-F]{1,4}:){1,7}:|:(?::[0-9a-fA-F]{1,4}){1,7}\b/g],[t.PHONE_NUMBER]:[/\b(\+\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g],[t.URL]:[/\bhttps?:\/\/(?:[-\w.])+(?::[0-9]+)?(?:\/(?:[\w/_.])*(?:\?(?:[\w&=%.])*)?(?:#(?:[\w.])*)?)?/g],[t.CVV]:[/\b(?:cvv|cvc|security\s*code|card\s*code)[\s:=]*[0-9]{3,4}\b/gi],[t.BIC_SWIFT]:[r],[t.US_BANK_NUMBER]:[/\b\d{8,17}\b/g],[t.US_DRIVER_LICENSE]:[/\b[A-Z]\d{7}\b/g],[t.US_ITIN]:[/\b9\d{2}-\d{2}-\d{4}\b/g],[t.US_PASSPORT]:[/\b[A-Z]\d{8}\b/g],[t.US_SSN]:[/\b\d{3}-\d{2}-\d{4}\b|\b\d{9}\b/g],[t.UK_NHS]:[/\b\d{3} \d{3} \d{4}\b/g],[t.UK_NINO]:[/\b[A-Z]{2}\d{6}[A-Z]\b/g],[t.ES_NIF]:[/\b\d{8}[A-Z]\b/g],[t.ES_NIE]:[/\b[XYZ]\d{7}[A-Z]\b/g],[t.IT_FISCAL_CODE]:[/\b[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]\b/g],[t.IT_DOCUMENT]:[/\b[A-Z]{2}\d{7}\b/g],[t.IT_VAT_CODE]:[/\bIT\d{11}\b/g],[t.PL_PESEL]:[/\b\d{11}\b/g],[t.FI_PERSONAL_IDENTITY_CODE]:[/\b\d{6}[+-A]\d{3}[A-Z0-9]\b/g],[t.SG_NRIC_FIN]:[/\b[A-Z]\d{7}[A-Z]\b/g],[t.SG_UEN]:[/\b\d{8}[A-Z]\b|\b\d{9}[A-Z]\b/g],[t.AU_ABN]:[/\b\d{2} \d{3} \d{3} \d{3}\b/g],[t.AU_ACN]:[/\b\d{3} \d{3} \d{3}\b/g],[t.AU_TFN]:[/\b\d{9}\b/g],[t.AU_MEDICARE]:[/\b\d{4} \d{5} \d{1}\b/g],[t.IN_PAN]:[/\b[A-Z]{5}\d{4}[A-Z]\b/g],[t.IN_AADHAAR]:[/\b\d{4} \d{4} \d{4}\b/g],[t.IN_VEHICLE_REGISTRATION]:[/\b[A-Z]{2}\d{2}[A-Z]{2}\d{4}\b/g],[t.IN_VOTER]:[/\b[A-Z]{3}\d{7}\b/g],[t.IN_PASSPORT]:[/\b[A-Z]\d{7}\b/g],[t.KR_RRN]:[/\b\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])-[1-4]\d{6}\b/g]};function a(e,n=Object.values(t)){if(!e)return e;for(let t of n){let n=i[t];if(!n||!n.length)continue;for(let r of n)e=e.replace(r,`<${t}>`)}return e}function o(e){if(!e)return e;let t=/(?:\u200B|\u200C|\u200D|\u2060|\uFEFF)/g;try{return e.normalize(`NFKC`).replace(t,``)}catch{return e.replace(t,``)}}function s(t,n){let{customRules:r=[],fixedPiiEntities:i=[]}=n||{},s=o(t);return r.length>0&&(s=e(s,r)),i.length>0?a(s,i):a(s)}exports.FixedPIIEntity=t,exports.mask=s;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t){if(!e||!t||t.length===0)return e;for(let n of t){if(!n.pattern||n.replacement===void 0)continue;e=e.replace(n.pattern,`<${n.replacement}>`)}return e}let t=function(e){return e.CREDIT_CARD=`CREDIT_CARD`,e.CRYPTO=`CRYPTO`,e.DATE_TIME=`DATE_TIME`,e.EMAIL_ADDRESS=`EMAIL_ADDRESS`,e.IBAN_CODE=`IBAN_CODE`,e.IP_ADDRESS=`IP_ADDRESS`,e.PHONE_NUMBER=`PHONE_NUMBER`,e.URL=`URL`,e.CVV=`CVV`,e.BIC_SWIFT=`BIC_SWIFT`,e.US_BANK_NUMBER=`US_BANK_NUMBER`,e.US_DRIVER_LICENSE=`US_DRIVER_LICENSE`,e.US_ITIN=`US_ITIN`,e.US_PASSPORT=`US_PASSPORT`,e.US_SSN=`US_SSN`,e.UK_NHS=`UK_NHS`,e.UK_NINO=`UK_NINO`,e.ES_NIF=`ES_NIF`,e.ES_NIE=`ES_NIE`,e.IT_FISCAL_CODE=`IT_FISCAL_CODE`,e.IT_DOCUMENT=`IT_DOCUMENT`,e.IT_VAT_CODE=`IT_VAT_CODE`,e.PL_PESEL=`PL_PESEL`,e.FI_PERSONAL_IDENTITY_CODE=`FI_PERSONAL_IDENTITY_CODE`,e.SG_NRIC_FIN=`SG_NRIC_FIN`,e.SG_UEN=`SG_UEN`,e.AU_ABN=`AU_ABN`,e.AU_ACN=`AU_ACN`,e.AU_TFN=`AU_TFN`,e.AU_MEDICARE=`AU_MEDICARE`,e.IN_PAN=`IN_PAN`,e.IN_AADHAAR=`IN_AADHAAR`,e.IN_VEHICLE_REGISTRATION=`IN_VEHICLE_REGISTRATION`,e.IN_VOTER=`IN_VOTER`,e.IN_PASSPORT=`IN_PASSPORT`,e.KR_RRN=`KR_RRN`,e}({});const n=[`(?:[sS][wW][iI][fF][tT])`,`(?:[bB][iI][cC])`,`(?:[bB][aA][nN][kK][\\s-]?[cC][oO][dD][eE])`,`(?:[sS][wW][iI][fF][tT][\\s-]?[cC][oO][dD][eE])`,`(?:[bB][iI][cC][\\s-]?[cC][oO][dD][eE])`].join(`|`),r=RegExp(`(?:${n})[:\\s=]+([A-Z]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A-Z0-9]{3})?)\\b`,`g`),i={[t.CREDIT_CARD]:[/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g],[t.CRYPTO]:[/\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b/g],[t.DATE_TIME]:[/\b(0[1-9]|1[0-2])[/-](0[1-9]|[12]\d|3[01])[/-](19|20)\d{2}\b/g],[t.EMAIL_ADDRESS]:[/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,RegExp(`(?<=[?&=/])[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}`,`g`)],[t.IBAN_CODE]:[/\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\b/g],[t.IP_ADDRESS]:[/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/g,/\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g,/\b(?:[0-9a-fA-F]{1,4}:){1,7}:|:(?::[0-9a-fA-F]{1,4}){1,7}\b/g],[t.PHONE_NUMBER]:[/\b(\+\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g],[t.URL]:[/\bhttps?:\/\/(?:[-\w.])+(?::[0-9]+)?(?:\/(?:[\w/_.])*(?:\?(?:[\w&=%.])*)?(?:#(?:[\w.])*)?)?/g],[t.CVV]:[/\b(?:cvv|cvc|security\s*code|card\s*code)[\s:=]*[0-9]{3,4}\b/gi],[t.BIC_SWIFT]:[r],[t.US_BANK_NUMBER]:[/\b\d{8,17}\b/g],[t.US_DRIVER_LICENSE]:[/\b[A-Z]\d{7}\b/g],[t.US_ITIN]:[/\b9\d{2}-\d{2}-\d{4}\b/g],[t.US_PASSPORT]:[/\b[A-Z]\d{8}\b/g],[t.US_SSN]:[/\b\d{3}-\d{2}-\d{4}\b|\b\d{9}\b/g],[t.UK_NHS]:[/\b\d{3} \d{3} \d{4}\b/g],[t.UK_NINO]:[/\b[A-Z]{2}\d{6}[A-Z]\b/g],[t.ES_NIF]:[/\b\d{8}[A-Z]\b/g],[t.ES_NIE]:[/\b[XYZ]\d{7}[A-Z]\b/g],[t.IT_FISCAL_CODE]:[/\b[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]\b/g],[t.IT_DOCUMENT]:[/\b[A-Z]{2}\d{7}\b/g],[t.IT_VAT_CODE]:[/\bIT\d{11}\b/g],[t.PL_PESEL]:[/\b\d{11}\b/g],[t.FI_PERSONAL_IDENTITY_CODE]:[/\b\d{6}[+-A]\d{3}[A-Z0-9]\b/g],[t.SG_NRIC_FIN]:[/\b[A-Z]\d{7}[A-Z]\b/g],[t.SG_UEN]:[/\b\d{8}[A-Z]\b|\b\d{9}[A-Z]\b/g],[t.AU_ABN]:[/\b\d{2} \d{3} \d{3} \d{3}\b/g],[t.AU_ACN]:[/\b\d{3} \d{3} \d{3}\b/g],[t.AU_TFN]:[/\b\d{9}\b/g],[t.AU_MEDICARE]:[/\b\d{4} \d{5} \d{1}\b/g],[t.IN_PAN]:[/\b[A-Z]{5}\d{4}[A-Z]\b/g],[t.IN_AADHAAR]:[/\b\d{4} \d{4} \d{4}\b/g],[t.IN_VEHICLE_REGISTRATION]:[/\b[A-Z]{2}\d{2}[A-Z]{2}\d{4}\b/g],[t.IN_VOTER]:[/\b[A-Z]{3}\d{7}\b/g],[t.IN_PASSPORT]:[/\b[A-Z]\d{7}\b/g],[t.KR_RRN]:[/\b\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])-[1-4]\d{6}\b/g]};function a(e,n=Object.values(t)){if(!e)return e;for(let t of n){let n=i[t];if(!n||!n.length)continue;for(let r of n)e=e.replace(r,`<${t}>`)}return e}function o(e){if(!e)return e;let t=/(?:\u200B|\u200C|\u200D|\u2060|\uFEFF)/g;try{return e.normalize(`NFKC`).replace(t,``)}catch{return e.replace(t,``)}}function s(t,n){let{customRules:r=[],fixedPiiEntities:i=[]}=n||{},s=o(t);return r.length>0&&(s=e(s,r)),i.length>0?a(s,i):a(s)}export{t as FixedPIIEntity,s as mask};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII Custom Rules Engine
|
|
3
|
+
*
|
|
4
|
+
* This module provides a simple mechanism for applying user-defined masking rules
|
|
5
|
+
* to text content. Unlike fixed rules, custom rules are provided at runtime and
|
|
6
|
+
* allow users to mask domain-specific or organization-specific sensitive data.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Custom masking rule defined by the user.
|
|
10
|
+
*
|
|
11
|
+
* A custom rule consists of a regex pattern to match and a replacement string.
|
|
12
|
+
* The pattern should use the global flag (`g`) to match all occurrences.
|
|
13
|
+
*/
|
|
14
|
+
export interface CustomRule {
|
|
15
|
+
pattern: RegExp;
|
|
16
|
+
replacement: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Apply custom masking rules to text.
|
|
20
|
+
*
|
|
21
|
+
* Rules are processed sequentially in the order they appear in the array.
|
|
22
|
+
* Each rule's pattern is matched against the text, and all matches are
|
|
23
|
+
* replaced with the corresponding replacement string.
|
|
24
|
+
*
|
|
25
|
+
* Processing Behavior
|
|
26
|
+
*
|
|
27
|
+
* - Sequential: Rules are applied one after another
|
|
28
|
+
* - Stateful: Later rules operate on text modified by earlier rules
|
|
29
|
+
* - No validation: Patterns are used as-is without checking
|
|
30
|
+
* - No overlap handling: First match wins
|
|
31
|
+
*
|
|
32
|
+
* @param text - The text to scan and mask
|
|
33
|
+
* @param rules - Array of custom masking rules to apply
|
|
34
|
+
*
|
|
35
|
+
* @returns The text with all custom rules applied
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Basic usage
|
|
39
|
+
* const text = "Employee EMP-12345 logged in"
|
|
40
|
+
* const rules: CustomRule[] = [
|
|
41
|
+
* { pattern: /EMP-\d{5}/g, replacement: 'EMPLOYEE_ID' }
|
|
42
|
+
* ]
|
|
43
|
+
* applyCustomRules(text, rules)
|
|
44
|
+
* // Returns: "Employee <EMPLOYEE_ID> logged in"
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // Multiple rules
|
|
48
|
+
* const text2 = "Ticket T-123 assigned to EMP-99999"
|
|
49
|
+
* const rules2: CustomRule[] = [
|
|
50
|
+
* { pattern: /T-\d{3}/g, replacement: 'TICKET_ID' },
|
|
51
|
+
* { pattern: /EMP-\d{5}/g, replacement: 'EMPLOYEE_ID' }
|
|
52
|
+
* ]
|
|
53
|
+
* applyCustomRules(text2, rules2)
|
|
54
|
+
* // Returns: "Ticket <TICKET_ID> assigned to <EMPLOYEE_ID>"
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyCustomRules(text: string, rules: CustomRule[]): string;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII Custom Rules Engine
|
|
3
|
+
*
|
|
4
|
+
* This module provides a simple mechanism for applying user-defined masking rules
|
|
5
|
+
* to text content. Unlike fixed rules, custom rules are provided at runtime and
|
|
6
|
+
* allow users to mask domain-specific or organization-specific sensitive data.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Custom masking rule defined by the user.
|
|
10
|
+
*
|
|
11
|
+
* A custom rule consists of a regex pattern to match and a replacement string.
|
|
12
|
+
* The pattern should use the global flag (`g`) to match all occurrences.
|
|
13
|
+
*/
|
|
14
|
+
export interface CustomRule {
|
|
15
|
+
pattern: RegExp;
|
|
16
|
+
replacement: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Apply custom masking rules to text.
|
|
20
|
+
*
|
|
21
|
+
* Rules are processed sequentially in the order they appear in the array.
|
|
22
|
+
* Each rule's pattern is matched against the text, and all matches are
|
|
23
|
+
* replaced with the corresponding replacement string.
|
|
24
|
+
*
|
|
25
|
+
* Processing Behavior
|
|
26
|
+
*
|
|
27
|
+
* - Sequential: Rules are applied one after another
|
|
28
|
+
* - Stateful: Later rules operate on text modified by earlier rules
|
|
29
|
+
* - No validation: Patterns are used as-is without checking
|
|
30
|
+
* - No overlap handling: First match wins
|
|
31
|
+
*
|
|
32
|
+
* @param text - The text to scan and mask
|
|
33
|
+
* @param rules - Array of custom masking rules to apply
|
|
34
|
+
*
|
|
35
|
+
* @returns The text with all custom rules applied
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Basic usage
|
|
39
|
+
* const text = "Employee EMP-12345 logged in"
|
|
40
|
+
* const rules: CustomRule[] = [
|
|
41
|
+
* { pattern: /EMP-\d{5}/g, replacement: 'EMPLOYEE_ID' }
|
|
42
|
+
* ]
|
|
43
|
+
* applyCustomRules(text, rules)
|
|
44
|
+
* // Returns: "Employee <EMPLOYEE_ID> logged in"
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // Multiple rules
|
|
48
|
+
* const text2 = "Ticket T-123 assigned to EMP-99999"
|
|
49
|
+
* const rules2: CustomRule[] = [
|
|
50
|
+
* { pattern: /T-\d{3}/g, replacement: 'TICKET_ID' },
|
|
51
|
+
* { pattern: /EMP-\d{5}/g, replacement: 'EMPLOYEE_ID' }
|
|
52
|
+
* ]
|
|
53
|
+
* applyCustomRules(text2, rules2)
|
|
54
|
+
* // Returns: "Ticket <TICKET_ID> assigned to <EMPLOYEE_ID>"
|
|
55
|
+
*/
|
|
56
|
+
export declare function applyCustomRules(text: string, rules: CustomRule[]): string;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII Detection and Masking - Fixed Rules Engine
|
|
3
|
+
*
|
|
4
|
+
* This module provides a simplified PII detection system based on fixed regex patterns.
|
|
5
|
+
* It is adapted from OpenAI's guardrails-js project with significant simplifications.
|
|
6
|
+
*
|
|
7
|
+
* Original Source:
|
|
8
|
+
* https://github.com/openai/openai-guardrails-js/blob/main/src/checks/pii.ts
|
|
9
|
+
*
|
|
10
|
+
* Key differences from original:
|
|
11
|
+
*
|
|
12
|
+
* 1. Simplified Architecture: Removed guardrail system infrastructure, blocking/tripwire
|
|
13
|
+
* functionality, and encoded PII detection (base64, hex, URL encoding)
|
|
14
|
+
*
|
|
15
|
+
* 2. Sequential Processing: Removed complex overlap detection and span deduplication.
|
|
16
|
+
* Entities are now processed sequentially, first match wins.
|
|
17
|
+
* This heuristic makes behavior more predictable but requires careful ordering of entity
|
|
18
|
+
* types when overlap is possible.
|
|
19
|
+
*
|
|
20
|
+
* 3. No Capture Groups: Removed group-based pattern matching (previously used for CVV
|
|
21
|
+
* and BIC_SWIFT). All patterns now match the entire entity directly.
|
|
22
|
+
*
|
|
23
|
+
* 4. Pure Masking Focus: Designed exclusively for text masking operations, not for
|
|
24
|
+
* validation or blocking.
|
|
25
|
+
*
|
|
26
|
+
* This is a "fixed rules engine", patterns are predefined and well-tested. Users who need
|
|
27
|
+
* flexibility should use custom rules rather than modifying these patterns.
|
|
28
|
+
*
|
|
29
|
+
* License:
|
|
30
|
+
*
|
|
31
|
+
* The original OpenAI guardrails-js project is licensed under the MIT License.
|
|
32
|
+
* Copyright (c) OpenAI
|
|
33
|
+
*
|
|
34
|
+
* This adapted version maintains the same MIT License.
|
|
35
|
+
*
|
|
36
|
+
* @see https://github.com/openai/openai-guardrails-js
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Supported PII entity types for detection.
|
|
40
|
+
*
|
|
41
|
+
* These represent common personally identifiable information patterns across
|
|
42
|
+
* different regions and use cases. Each entity type maps to one or more regex
|
|
43
|
+
* patterns optimized for that specific format.
|
|
44
|
+
*/
|
|
45
|
+
export declare enum FixedPIIEntity {
|
|
46
|
+
CREDIT_CARD = "CREDIT_CARD",
|
|
47
|
+
CRYPTO = "CRYPTO",
|
|
48
|
+
DATE_TIME = "DATE_TIME",
|
|
49
|
+
EMAIL_ADDRESS = "EMAIL_ADDRESS",
|
|
50
|
+
IBAN_CODE = "IBAN_CODE",
|
|
51
|
+
IP_ADDRESS = "IP_ADDRESS",
|
|
52
|
+
PHONE_NUMBER = "PHONE_NUMBER",
|
|
53
|
+
URL = "URL",
|
|
54
|
+
CVV = "CVV",
|
|
55
|
+
BIC_SWIFT = "BIC_SWIFT",
|
|
56
|
+
US_BANK_NUMBER = "US_BANK_NUMBER",
|
|
57
|
+
US_DRIVER_LICENSE = "US_DRIVER_LICENSE",
|
|
58
|
+
US_ITIN = "US_ITIN",
|
|
59
|
+
US_PASSPORT = "US_PASSPORT",
|
|
60
|
+
US_SSN = "US_SSN",
|
|
61
|
+
UK_NHS = "UK_NHS",
|
|
62
|
+
UK_NINO = "UK_NINO",
|
|
63
|
+
ES_NIF = "ES_NIF",
|
|
64
|
+
ES_NIE = "ES_NIE",
|
|
65
|
+
IT_FISCAL_CODE = "IT_FISCAL_CODE",
|
|
66
|
+
IT_DOCUMENT = "IT_DOCUMENT",
|
|
67
|
+
IT_VAT_CODE = "IT_VAT_CODE",
|
|
68
|
+
PL_PESEL = "PL_PESEL",
|
|
69
|
+
FI_PERSONAL_IDENTITY_CODE = "FI_PERSONAL_IDENTITY_CODE",
|
|
70
|
+
SG_NRIC_FIN = "SG_NRIC_FIN",
|
|
71
|
+
SG_UEN = "SG_UEN",
|
|
72
|
+
AU_ABN = "AU_ABN",
|
|
73
|
+
AU_ACN = "AU_ACN",
|
|
74
|
+
AU_TFN = "AU_TFN",
|
|
75
|
+
AU_MEDICARE = "AU_MEDICARE",
|
|
76
|
+
IN_PAN = "IN_PAN",
|
|
77
|
+
IN_AADHAAR = "IN_AADHAAR",
|
|
78
|
+
IN_VEHICLE_REGISTRATION = "IN_VEHICLE_REGISTRATION",
|
|
79
|
+
IN_VOTER = "IN_VOTER",
|
|
80
|
+
IN_PASSPORT = "IN_PASSPORT",
|
|
81
|
+
KR_RRN = "KR_RRN"
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Apply fixed PII masking rules to text
|
|
85
|
+
*
|
|
86
|
+
* This function uses a sequential, non-overlapping approach:
|
|
87
|
+
*
|
|
88
|
+
* 1. Entities are processed in the order provided
|
|
89
|
+
* 2. Once text is masked, it won't be re-matched by subsequent patterns
|
|
90
|
+
* 3. No overlap detection or resolution is performed
|
|
91
|
+
*
|
|
92
|
+
* This design prioritizes predictability and performance over handling edge cases.
|
|
93
|
+
*
|
|
94
|
+
* If patterns might overlap (e.g., CREDIT_CARD vs US_BANK_NUMBER), place the
|
|
95
|
+
* more specific pattern first in the entities array to ensure it takes precedence.
|
|
96
|
+
*
|
|
97
|
+
* @param text - The text to scan and mask
|
|
98
|
+
* @param entities - List of PII entity types to detect
|
|
99
|
+
*
|
|
100
|
+
* @returns The text with PII entities replaced
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Default behavior
|
|
104
|
+
* applyFixedRules("Email: test@example.com")
|
|
105
|
+
* // Returns: "Email: <EMAIL_ADDRESS>"
|
|
106
|
+
*
|
|
107
|
+
* // Specific entities only
|
|
108
|
+
* applyFixedRules(
|
|
109
|
+
* "Email: test@example.com, SSN: 123-45-6789",
|
|
110
|
+
* [FixedPIIEntity.EMAIL_ADDRESS]
|
|
111
|
+
* )
|
|
112
|
+
* // Returns: "Email: <EMAIL_ADDRESS>, SSN: 123-45-6789"
|
|
113
|
+
*
|
|
114
|
+
* // Priority ordering matters
|
|
115
|
+
* applyFixedRules(
|
|
116
|
+
* "1234567890123456",
|
|
117
|
+
* [FixedPIIEntity.CREDIT_CARD, FixedPIIEntity.US_BANK_NUMBER] // Credit card checked first
|
|
118
|
+
* )
|
|
119
|
+
* // Returns: "<CREDIT_CARD>"
|
|
120
|
+
*/
|
|
121
|
+
export declare function applyFixedRules(text: string, entities?: FixedPIIEntity[]): string;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII Detection and Masking - Fixed Rules Engine
|
|
3
|
+
*
|
|
4
|
+
* This module provides a simplified PII detection system based on fixed regex patterns.
|
|
5
|
+
* It is adapted from OpenAI's guardrails-js project with significant simplifications.
|
|
6
|
+
*
|
|
7
|
+
* Original Source:
|
|
8
|
+
* https://github.com/openai/openai-guardrails-js/blob/main/src/checks/pii.ts
|
|
9
|
+
*
|
|
10
|
+
* Key differences from original:
|
|
11
|
+
*
|
|
12
|
+
* 1. Simplified Architecture: Removed guardrail system infrastructure, blocking/tripwire
|
|
13
|
+
* functionality, and encoded PII detection (base64, hex, URL encoding)
|
|
14
|
+
*
|
|
15
|
+
* 2. Sequential Processing: Removed complex overlap detection and span deduplication.
|
|
16
|
+
* Entities are now processed sequentially, first match wins.
|
|
17
|
+
* This heuristic makes behavior more predictable but requires careful ordering of entity
|
|
18
|
+
* types when overlap is possible.
|
|
19
|
+
*
|
|
20
|
+
* 3. No Capture Groups: Removed group-based pattern matching (previously used for CVV
|
|
21
|
+
* and BIC_SWIFT). All patterns now match the entire entity directly.
|
|
22
|
+
*
|
|
23
|
+
* 4. Pure Masking Focus: Designed exclusively for text masking operations, not for
|
|
24
|
+
* validation or blocking.
|
|
25
|
+
*
|
|
26
|
+
* This is a "fixed rules engine", patterns are predefined and well-tested. Users who need
|
|
27
|
+
* flexibility should use custom rules rather than modifying these patterns.
|
|
28
|
+
*
|
|
29
|
+
* License:
|
|
30
|
+
*
|
|
31
|
+
* The original OpenAI guardrails-js project is licensed under the MIT License.
|
|
32
|
+
* Copyright (c) OpenAI
|
|
33
|
+
*
|
|
34
|
+
* This adapted version maintains the same MIT License.
|
|
35
|
+
*
|
|
36
|
+
* @see https://github.com/openai/openai-guardrails-js
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Supported PII entity types for detection.
|
|
40
|
+
*
|
|
41
|
+
* These represent common personally identifiable information patterns across
|
|
42
|
+
* different regions and use cases. Each entity type maps to one or more regex
|
|
43
|
+
* patterns optimized for that specific format.
|
|
44
|
+
*/
|
|
45
|
+
export declare enum FixedPIIEntity {
|
|
46
|
+
CREDIT_CARD = "CREDIT_CARD",
|
|
47
|
+
CRYPTO = "CRYPTO",
|
|
48
|
+
DATE_TIME = "DATE_TIME",
|
|
49
|
+
EMAIL_ADDRESS = "EMAIL_ADDRESS",
|
|
50
|
+
IBAN_CODE = "IBAN_CODE",
|
|
51
|
+
IP_ADDRESS = "IP_ADDRESS",
|
|
52
|
+
PHONE_NUMBER = "PHONE_NUMBER",
|
|
53
|
+
URL = "URL",
|
|
54
|
+
CVV = "CVV",
|
|
55
|
+
BIC_SWIFT = "BIC_SWIFT",
|
|
56
|
+
US_BANK_NUMBER = "US_BANK_NUMBER",
|
|
57
|
+
US_DRIVER_LICENSE = "US_DRIVER_LICENSE",
|
|
58
|
+
US_ITIN = "US_ITIN",
|
|
59
|
+
US_PASSPORT = "US_PASSPORT",
|
|
60
|
+
US_SSN = "US_SSN",
|
|
61
|
+
UK_NHS = "UK_NHS",
|
|
62
|
+
UK_NINO = "UK_NINO",
|
|
63
|
+
ES_NIF = "ES_NIF",
|
|
64
|
+
ES_NIE = "ES_NIE",
|
|
65
|
+
IT_FISCAL_CODE = "IT_FISCAL_CODE",
|
|
66
|
+
IT_DOCUMENT = "IT_DOCUMENT",
|
|
67
|
+
IT_VAT_CODE = "IT_VAT_CODE",
|
|
68
|
+
PL_PESEL = "PL_PESEL",
|
|
69
|
+
FI_PERSONAL_IDENTITY_CODE = "FI_PERSONAL_IDENTITY_CODE",
|
|
70
|
+
SG_NRIC_FIN = "SG_NRIC_FIN",
|
|
71
|
+
SG_UEN = "SG_UEN",
|
|
72
|
+
AU_ABN = "AU_ABN",
|
|
73
|
+
AU_ACN = "AU_ACN",
|
|
74
|
+
AU_TFN = "AU_TFN",
|
|
75
|
+
AU_MEDICARE = "AU_MEDICARE",
|
|
76
|
+
IN_PAN = "IN_PAN",
|
|
77
|
+
IN_AADHAAR = "IN_AADHAAR",
|
|
78
|
+
IN_VEHICLE_REGISTRATION = "IN_VEHICLE_REGISTRATION",
|
|
79
|
+
IN_VOTER = "IN_VOTER",
|
|
80
|
+
IN_PASSPORT = "IN_PASSPORT",
|
|
81
|
+
KR_RRN = "KR_RRN"
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Apply fixed PII masking rules to text
|
|
85
|
+
*
|
|
86
|
+
* This function uses a sequential, non-overlapping approach:
|
|
87
|
+
*
|
|
88
|
+
* 1. Entities are processed in the order provided
|
|
89
|
+
* 2. Once text is masked, it won't be re-matched by subsequent patterns
|
|
90
|
+
* 3. No overlap detection or resolution is performed
|
|
91
|
+
*
|
|
92
|
+
* This design prioritizes predictability and performance over handling edge cases.
|
|
93
|
+
*
|
|
94
|
+
* If patterns might overlap (e.g., CREDIT_CARD vs US_BANK_NUMBER), place the
|
|
95
|
+
* more specific pattern first in the entities array to ensure it takes precedence.
|
|
96
|
+
*
|
|
97
|
+
* @param text - The text to scan and mask
|
|
98
|
+
* @param entities - List of PII entity types to detect
|
|
99
|
+
*
|
|
100
|
+
* @returns The text with PII entities replaced
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* // Default behavior
|
|
104
|
+
* applyFixedRules("Email: test@example.com")
|
|
105
|
+
* // Returns: "Email: <EMAIL_ADDRESS>"
|
|
106
|
+
*
|
|
107
|
+
* // Specific entities only
|
|
108
|
+
* applyFixedRules(
|
|
109
|
+
* "Email: test@example.com, SSN: 123-45-6789",
|
|
110
|
+
* [FixedPIIEntity.EMAIL_ADDRESS]
|
|
111
|
+
* )
|
|
112
|
+
* // Returns: "Email: <EMAIL_ADDRESS>, SSN: 123-45-6789"
|
|
113
|
+
*
|
|
114
|
+
* // Priority ordering matters
|
|
115
|
+
* applyFixedRules(
|
|
116
|
+
* "1234567890123456",
|
|
117
|
+
* [FixedPIIEntity.CREDIT_CARD, FixedPIIEntity.US_BANK_NUMBER] // Credit card checked first
|
|
118
|
+
* )
|
|
119
|
+
* // Returns: "<CREDIT_CARD>"
|
|
120
|
+
*/
|
|
121
|
+
export declare function applyFixedRules(text: string, entities?: FixedPIIEntity[]): string;
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yellowsakura/js-pii-mask",
|
|
3
|
+
"version": "0.8.93",
|
|
4
|
+
"description": "Simple and effective PII data masking library for TypeScript/JavaScript",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pii",
|
|
7
|
+
"mask",
|
|
8
|
+
"masking",
|
|
9
|
+
"data-privacy",
|
|
10
|
+
"privacy",
|
|
11
|
+
"gdpr",
|
|
12
|
+
"ccpa",
|
|
13
|
+
"anonymization",
|
|
14
|
+
"typescript",
|
|
15
|
+
"personal-data",
|
|
16
|
+
"sensitive-data"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://github.com/YellowSakura/js-pii-mask#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/YellowSakura/js-pii-mask/issues"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/YellowSakura/js-pii-mask.git"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"author": "Yellow Sakura",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"directories": {
|
|
31
|
+
"doc": "docs",
|
|
32
|
+
"test": "test"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsdown",
|
|
41
|
+
"dev": "tsdown --watch",
|
|
42
|
+
"quality": "eslint src *.ts",
|
|
43
|
+
"test": "jest",
|
|
44
|
+
"test:single": "jest -t"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@swc/jest": "^0.2.39",
|
|
48
|
+
"@types/jest": "^30.0.0",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^8.51.0",
|
|
50
|
+
"@typescript-eslint/parser": "^8.51.0",
|
|
51
|
+
"eslint": "^9.39.0",
|
|
52
|
+
"jest": "^30.2.0",
|
|
53
|
+
"tsdown": "^0.2.0",
|
|
54
|
+
"typescript": "^5.9.3"
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=24.12.0"
|
|
58
|
+
},
|
|
59
|
+
"module": "./dist/index.mjs"
|
|
60
|
+
}
|