n8n-nodes-redactor 2.0.0

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.

Potentially problematic release.


This version of n8n-nodes-redactor might be problematic. Click here for more details.

Files changed (37) hide show
  1. package/LICENSE +42 -0
  2. package/README.dev.md +134 -0
  3. package/README.md +376 -0
  4. package/README.npm.md +376 -0
  5. package/dist/nodes/PiiRedactor/PiiRedactor.node.d.ts +5 -0
  6. package/dist/nodes/PiiRedactor/PiiRedactor.node.js +872 -0
  7. package/dist/nodes/PiiRedactor/__tests__/engine.test.d.ts +1 -0
  8. package/dist/nodes/PiiRedactor/__tests__/engine.test.js +524 -0
  9. package/dist/nodes/PiiRedactor/__tests__/operations.test.d.ts +1 -0
  10. package/dist/nodes/PiiRedactor/__tests__/operations.test.js +316 -0
  11. package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.d.ts +1 -0
  12. package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.js +427 -0
  13. package/dist/nodes/PiiRedactor/__tests__/patterns.test.d.ts +1 -0
  14. package/dist/nodes/PiiRedactor/__tests__/patterns.test.js +481 -0
  15. package/dist/nodes/PiiRedactor/__tests__/phase1.test.d.ts +1 -0
  16. package/dist/nodes/PiiRedactor/__tests__/phase1.test.js +343 -0
  17. package/dist/nodes/PiiRedactor/__tests__/security.test.d.ts +1 -0
  18. package/dist/nodes/PiiRedactor/__tests__/security.test.js +178 -0
  19. package/dist/nodes/PiiRedactor/__tests__/semantic.test.d.ts +1 -0
  20. package/dist/nodes/PiiRedactor/__tests__/semantic.test.js +319 -0
  21. package/dist/nodes/PiiRedactor/__tests__/vault.test.d.ts +1 -0
  22. package/dist/nodes/PiiRedactor/__tests__/vault.test.js +247 -0
  23. package/dist/nodes/PiiRedactor/context.d.ts +57 -0
  24. package/dist/nodes/PiiRedactor/context.js +260 -0
  25. package/dist/nodes/PiiRedactor/engine.d.ts +17 -0
  26. package/dist/nodes/PiiRedactor/engine.js +813 -0
  27. package/dist/nodes/PiiRedactor/names.d.ts +25 -0
  28. package/dist/nodes/PiiRedactor/names.js +188 -0
  29. package/dist/nodes/PiiRedactor/patterns.d.ts +17 -0
  30. package/dist/nodes/PiiRedactor/patterns.js +1741 -0
  31. package/dist/nodes/PiiRedactor/redact.png +0 -0
  32. package/dist/nodes/PiiRedactor/redact.svg +3 -0
  33. package/dist/nodes/PiiRedactor/types.d.ts +78 -0
  34. package/dist/nodes/PiiRedactor/types.js +3 -0
  35. package/dist/nodes/PiiRedactor/vault.d.ts +60 -0
  36. package/dist/nodes/PiiRedactor/vault.js +299 -0
  37. package/package.json +87 -0
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ /**
3
+ * Context words and confidence scoring for PII patterns.
4
+ *
5
+ * Context words are keywords that appear near a PII match and boost confidence.
6
+ * For example, "SSN" appearing before "123-45-6789" boosts confidence from 0.60 to 0.85.
7
+ *
8
+ * Base confidence scores reflect how reliable a pattern is:
9
+ * - 0.95: Checksum validated (Luhn, IBAN, PESEL, etc.)
10
+ * - 0.90: Semantic field-name match
11
+ * - 0.85: Context-aware ambiguous field
12
+ * - 0.80: Regex match WITH context words nearby
13
+ * - 0.60: Regex match WITHOUT context words (bare pattern)
14
+ * - 0.70: Custom pattern match
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.CONTEXT_WINDOW = exports.DENY_LIST_CONFIDENCE = exports.CUSTOM_PATTERN_CONFIDENCE = exports.AMBIGUOUS_FIELD_CONFIDENCE = exports.SEMANTIC_CONFIDENCE = exports.CONTEXT_BOOST = exports.DEFAULT_BASE_CONFIDENCE = exports.BASE_CONFIDENCE = exports.CONTEXT_WORDS = void 0;
18
+ exports.hasContextWords = hasContextWords;
19
+ exports.calculateConfidence = calculateConfidence;
20
+ /** Context words by pattern name. Case-insensitive matching. */
21
+ exports.CONTEXT_WORDS = {
22
+ // Contact
23
+ email: ['email', 'e-mail', 'mail', 'contact', 'reach', 'send', 'Kontakt', 'correo', 'posta'],
24
+ phone: ['phone', 'call', 'mobile', 'cell', 'tel', 'telephone', 'dial', 'ring', 'Telefon', 'anrufen', 'Handy', 'appeler', 'llamar'],
25
+ phoneDE: ['Telefon', 'anrufen', 'Handy', 'Rufnummer', 'Festnetz', 'mobil'],
26
+ phoneUK: ['phone', 'call', 'mobile', 'ring', 'dial', 'landline'],
27
+ phoneAT: ['Telefon', 'anrufen', 'Handy'],
28
+ phoneCH: ['Telefon', 'anrufen', 'Natel', 'Handy'],
29
+ phoneFR: ['telephone', 'appeler', 'portable', 'fixe', 'numero'],
30
+ phoneNL: ['telefoon', 'bellen', 'mobiel'],
31
+ phoneES: ['telefono', 'llamar', 'movil', 'celular'],
32
+ phoneIT: ['telefono', 'chiamare', 'cellulare'],
33
+ phoneAU: ['phone', 'call', 'mobile'],
34
+ phoneIN: ['phone', 'call', 'mobile'],
35
+ phoneBR: ['telefone', 'ligar', 'celular'],
36
+ phoneCN: ['phone', 'call', 'mobile'],
37
+ phoneKR: ['phone', 'call'],
38
+ phoneRU: ['telefon', 'pozvonit'],
39
+ phoneMX: ['telefono', 'llamar', 'celular'],
40
+ phoneZA: ['phone', 'call', 'mobile'],
41
+ // Identity - person names
42
+ personName: ['name', 'person', 'contact', 'customer', 'client', 'patient', 'employee', 'user', 'Mr', 'Mrs', 'Ms', 'Dr', 'Herr', 'Frau'],
43
+ // Identity - government IDs
44
+ ssn: ['social security', 'SSN', 'social', 'security number', 'Sozialversicherung'],
45
+ itinUS: ['ITIN', 'taxpayer', 'individual taxpayer'],
46
+ sinCA: ['SIN', 'social insurance', 'insurance number'],
47
+ ninoUK: ['national insurance', 'NINO', 'NI number'],
48
+ nhsNumber: ['NHS', 'national health', 'health service', 'patient'],
49
+ passportUS: ['passport', 'travel document', 'Reisepass'],
50
+ passportEU: ['passport', 'travel document', 'Reisepass', 'passeport'],
51
+ passportDE: ['Reisepass', 'passport', 'Passnummer'],
52
+ nationalIdDE: ['Personalausweis', 'Ausweis', 'ID card', 'identity card'],
53
+ taxIdUS: ['EIN', 'employer identification', 'tax ID', 'federal tax'],
54
+ taxIdDE: ['Steuer', 'Identifikationsnummer', 'Finanzamt'],
55
+ sozialversicherungDE: ['Sozialversicherung', 'Rentenversicherung', 'SV-Nummer'],
56
+ ahvCH: ['AHV', 'AVS', 'Sozialversicherung', 'assurance'],
57
+ nationalIdFR: ['securite sociale', 'NIR', 'numero national'],
58
+ codiceFiscaleIT: ['codice fiscale', 'fiscal code', 'CF'],
59
+ dniES: ['DNI', 'documento nacional', 'identidad'],
60
+ nieES: ['NIE', 'extranjero', 'foreigner'],
61
+ peselPL: ['PESEL', 'numer identyfikacyjny'],
62
+ bsnNL: ['BSN', 'burgerservicenummer', 'burger service'],
63
+ ppsIE: ['PPS', 'personal public service'],
64
+ tfnAU: ['TFN', 'tax file', 'tax number'],
65
+ nricSG: ['NRIC', 'identity card', 'IC'],
66
+ panIN: ['PAN', 'permanent account', 'income tax'],
67
+ aadhaarIN: ['Aadhaar', 'UID', 'unique identification'],
68
+ cpfBR: ['CPF', 'cadastro', 'pessoa fisica'],
69
+ hetuFI: ['HETU', 'henkilotunnus', 'personal identity'],
70
+ personnummerSE: ['personnummer', 'personal number'],
71
+ fodselsnummerNO: ['fodselsnummer', 'personal number'],
72
+ cprDK: ['CPR', 'personnummer'],
73
+ nifPT: ['NIF', 'numero fiscal', 'contribuinte'],
74
+ nationalIdCN: ['identity card', 'resident card', 'shenfenzheng'],
75
+ nationalIdTR: ['TC Kimlik', 'kimlik no', 'identity'],
76
+ curpMX: ['CURP', 'poblacion'],
77
+ rfcMX: ['RFC', 'registro federal'],
78
+ emiratesIdUAE: ['emirates ID', 'UAE ID'],
79
+ // Financial
80
+ creditCard: ['card', 'credit', 'debit', 'visa', 'mastercard', 'amex', 'payment', 'Kreditkarte', 'carte', 'tarjeta'],
81
+ amex: ['amex', 'american express', 'card', 'payment'],
82
+ iban: ['IBAN', 'bank account', 'Kontonummer', 'compte', 'cuenta', 'conto'],
83
+ bic: ['BIC', 'SWIFT', 'bank', 'routing'],
84
+ vatEU: ['VAT', 'MwSt', 'Umsatzsteuer', 'TVA', 'IVA', 'BTW'],
85
+ abaRouting: ['routing', 'ABA', 'bank', 'transfer'],
86
+ sortCodeUK: ['sort code', 'bank', 'branch'],
87
+ cardExpiry: ['expiry', 'expiration', 'valid', 'exp', 'Gultig'],
88
+ cvvCtx: ['CVV', 'CVC', 'security code', 'verification'],
89
+ bankAccountCtx: ['account', 'bank', 'checking', 'savings', 'Konto'],
90
+ insurancePolicyCtx: ['insurance', 'policy', 'Versicherung', 'assurance', 'polizza'],
91
+ salaryCtx: ['salary', 'compensation', 'pay', 'wage', 'Gehalt', 'salaire'],
92
+ // Network
93
+ ipv4: ['IP', 'address', 'server', 'host', 'network'],
94
+ ipv6: ['IP', 'address', 'server', 'IPv6'],
95
+ macAddress: ['MAC', 'hardware', 'network', 'device', 'adapter'],
96
+ url: ['URL', 'link', 'website', 'http', 'visit'],
97
+ privateIp: ['internal', 'private', 'LAN', 'intranet', 'network'],
98
+ // Location
99
+ addressDE: ['Adresse', 'Anschrift', 'wohnt', 'Straße', 'address'],
100
+ addressLabeledEN: ['address', 'lives', 'located', 'residing'],
101
+ addressLabeledDE: ['Adresse', 'Anschrift', 'wohnt', 'Wohnort'],
102
+ gpsCoordinates: ['GPS', 'coordinates', 'location', 'latitude', 'longitude', 'Standort'],
103
+ // Medical
104
+ medicalRecordNumber: ['MRN', 'medical record', 'patient', 'chart', 'Krankenakte'],
105
+ deaNumber: ['DEA', 'drug enforcement', 'prescriber'],
106
+ npiNumber: ['NPI', 'provider', 'physician', 'doctor'],
107
+ rxNumber: ['prescription', 'Rx', 'pharmacy', 'medication', 'Rezept'],
108
+ healthPlanCtx: ['health plan', 'insurance', 'member', 'subscriber', 'beneficiary'],
109
+ bloodTypeCtx: ['blood', 'type', 'group', 'Blutgruppe'],
110
+ // Enterprise
111
+ awsAccessKey: ['AWS', 'amazon', 'access key', 'credential'],
112
+ gcpApiKey: ['Google', 'GCP', 'API key', 'cloud'],
113
+ stripeKey: ['Stripe', 'payment', 'API key'],
114
+ openaiKey: ['OpenAI', 'API key', 'GPT'],
115
+ githubToken: ['GitHub', 'token', 'personal access'],
116
+ slackToken: ['Slack', 'token', 'bot'],
117
+ jwtToken: ['JWT', 'token', 'auth', 'bearer', 'session'],
118
+ pemPrivateKey: ['private key', 'RSA', 'certificate', 'SSL', 'TLS'],
119
+ sshPublicKey: ['SSH', 'key', 'public key', 'authorized'],
120
+ genericSecret: ['password', 'secret', 'credential', 'API key', 'token'],
121
+ dbConnectionString: ['database', 'connection', 'JDBC', 'mongo', 'postgres', 'mysql'],
122
+ internalHostname: ['server', 'host', 'internal', 'intranet'],
123
+ // Vehicle
124
+ vin: ['VIN', 'vehicle', 'chassis', 'Fahrgestell', 'vehicule'],
125
+ // Crypto
126
+ bitcoinAddress: ['bitcoin', 'BTC', 'wallet', 'crypto'],
127
+ ethereumAddress: ['ethereum', 'ETH', 'wallet', 'crypto', 'contract'],
128
+ };
129
+ /**
130
+ * Base confidence scores by pattern name.
131
+ * Patterns with checksum validation get higher scores.
132
+ */
133
+ exports.BASE_CONFIDENCE = {
134
+ // Checksum validated = 0.95
135
+ creditCard: 0.95,
136
+ amex: 0.95,
137
+ iban: 0.95,
138
+ nhsNumber: 0.95,
139
+ sinCA: 0.95,
140
+ peselPL: 0.95,
141
+ bsnNL: 0.95,
142
+ nifPT: 0.95,
143
+ tfnAU: 0.95,
144
+ abaRouting: 0.95,
145
+ // Strong format (unique structure) = 0.85
146
+ email: 0.90,
147
+ codiceFiscaleIT: 0.90,
148
+ hetuFI: 0.90,
149
+ ahvCH: 0.90,
150
+ nricSG: 0.90,
151
+ panIN: 0.90,
152
+ passportUS: 0.85,
153
+ passportEU: 0.85,
154
+ passportDE: 0.85,
155
+ ssn: 0.85,
156
+ ninoUK: 0.85,
157
+ dniES: 0.85,
158
+ nieES: 0.85,
159
+ nationalIdCN: 0.85,
160
+ nationalIdTH: 0.85,
161
+ emiratesIdUAE: 0.85,
162
+ curpMX: 0.85,
163
+ bitcoinAddress: 0.85,
164
+ ethereumAddress: 0.85,
165
+ vin: 0.85,
166
+ jwtToken: 0.85,
167
+ awsAccessKey: 0.90,
168
+ gcpApiKey: 0.90,
169
+ stripeKey: 0.90,
170
+ openaiKey: 0.90,
171
+ githubToken: 0.90,
172
+ pemPrivateKey: 0.90,
173
+ sshPublicKey: 0.90,
174
+ // Medium format = 0.70
175
+ phone: 0.70,
176
+ phoneDE: 0.75,
177
+ phoneUK: 0.75,
178
+ phoneAT: 0.75,
179
+ phoneCH: 0.75,
180
+ phoneFR: 0.75,
181
+ personName: 0.80,
182
+ ipv4: 0.70,
183
+ ipv6: 0.80,
184
+ macAddress: 0.80,
185
+ url: 0.75,
186
+ vatEU: 0.80,
187
+ bic: 0.65,
188
+ // Broad patterns (high false positive risk) = 0.50-0.60
189
+ postalCodeDE: 0.40,
190
+ postalCodeAT: 0.40,
191
+ postalCodeCH: 0.40,
192
+ postalCodeUS: 0.50,
193
+ postalCodeIT: 0.40,
194
+ postalCodeES: 0.50,
195
+ postalCodeIN: 0.40,
196
+ dateSlash: 0.50,
197
+ dateDash: 0.50,
198
+ dateDot: 0.50,
199
+ sortCodeUK: 0.50,
200
+ cardExpiry: 0.50,
201
+ socialHandle: 0.60,
202
+ licensePlateDE: 0.55,
203
+ dnaSequence: 0.50,
204
+ };
205
+ /**
206
+ * Default base confidence for patterns not in the BASE_CONFIDENCE map.
207
+ */
208
+ exports.DEFAULT_BASE_CONFIDENCE = 0.65;
209
+ /**
210
+ * Confidence boost when context words are found nearby.
211
+ */
212
+ exports.CONTEXT_BOOST = 0.20;
213
+ /**
214
+ * Confidence score for semantic field-name matches.
215
+ */
216
+ exports.SEMANTIC_CONFIDENCE = 0.90;
217
+ /**
218
+ * Confidence score for context-aware ambiguous field matches.
219
+ */
220
+ exports.AMBIGUOUS_FIELD_CONFIDENCE = 0.85;
221
+ /**
222
+ * Confidence score for custom pattern matches.
223
+ */
224
+ exports.CUSTOM_PATTERN_CONFIDENCE = 0.70;
225
+ /**
226
+ * Confidence score for deny list matches.
227
+ */
228
+ exports.DENY_LIST_CONFIDENCE = 1.0;
229
+ /**
230
+ * Window size (characters) to search for context words around a match.
231
+ */
232
+ exports.CONTEXT_WINDOW = 80;
233
+ /**
234
+ * Check if any context words appear near a match position in the text.
235
+ */
236
+ function hasContextWords(text, matchStart, matchEnd, words) {
237
+ if (!words || words.length === 0)
238
+ return false;
239
+ const windowStart = Math.max(0, matchStart - exports.CONTEXT_WINDOW);
240
+ const windowEnd = Math.min(text.length, matchEnd + exports.CONTEXT_WINDOW);
241
+ const surrounding = text.slice(windowStart, windowEnd).toLowerCase();
242
+ return words.some((word) => surrounding.includes(word.toLowerCase()));
243
+ }
244
+ /**
245
+ * Calculate confidence score for a pattern match.
246
+ */
247
+ function calculateConfidence(patternName, hasValidator, validatorPassed, text, matchStart, matchEnd) {
248
+ // Start with base confidence
249
+ let confidence = exports.BASE_CONFIDENCE[patternName] ?? exports.DEFAULT_BASE_CONFIDENCE;
250
+ // If has validator and passed, boost to at least 0.95
251
+ if (hasValidator && validatorPassed) {
252
+ confidence = Math.max(confidence, 0.95);
253
+ }
254
+ // Check context words
255
+ const contextWords = exports.CONTEXT_WORDS[patternName];
256
+ if (contextWords && hasContextWords(text, matchStart, matchEnd, contextWords)) {
257
+ confidence = Math.min(1.0, confidence + exports.CONTEXT_BOOST);
258
+ }
259
+ return Math.round(confidence * 100) / 100;
260
+ }
@@ -0,0 +1,17 @@
1
+ import { IVault } from './vault';
2
+ import { RedactionContext, RedactionHit, RedactionReport } from './types';
3
+ /**
4
+ * Main redaction engine - recursively walks JSON and applies redaction.
5
+ * Uses BOTH semantic field-name detection AND regex pattern matching.
6
+ */
7
+ export declare function redactValue(value: unknown, ctx: RedactionContext, vault: IVault, sessionId: string, hits: RedactionHit[], itemIndex: number, currentPath?: string, siblingKeys?: string[]): unknown;
8
+ /**
9
+ * Restore redacted tokens back to original values.
10
+ * Uses single-pass replacement to avoid infinite loops.
11
+ */
12
+ export declare function restoreValue(value: unknown, vault: IVault, sessionId: string): unknown;
13
+ /**
14
+ * Build a redaction audit report from collected hits.
15
+ * SECURITY: Original PII values are NEVER included in the report.
16
+ */
17
+ export declare function buildReport(sessionId: string, hits: RedactionHit[]): RedactionReport;