n8n-nodes-redactor 3.0.1

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.
Files changed (61) hide show
  1. package/LICENSE +42 -0
  2. package/README.dev.md +153 -0
  3. package/README.md +443 -0
  4. package/README.npm.md +443 -0
  5. package/dist/nodes/PiiRedactor/PiiRedactor.node.d.ts +5 -0
  6. package/dist/nodes/PiiRedactor/PiiRedactor.node.js +1093 -0
  7. package/dist/nodes/PiiRedactor/__tests__/encryption.test.d.ts +1 -0
  8. package/dist/nodes/PiiRedactor/__tests__/encryption.test.js +200 -0
  9. package/dist/nodes/PiiRedactor/__tests__/engine.test.d.ts +1 -0
  10. package/dist/nodes/PiiRedactor/__tests__/engine.test.js +524 -0
  11. package/dist/nodes/PiiRedactor/__tests__/operations.test.d.ts +1 -0
  12. package/dist/nodes/PiiRedactor/__tests__/operations.test.js +316 -0
  13. package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.d.ts +1 -0
  14. package/dist/nodes/PiiRedactor/__tests__/patterns-global.test.js +427 -0
  15. package/dist/nodes/PiiRedactor/__tests__/patterns.test.d.ts +1 -0
  16. package/dist/nodes/PiiRedactor/__tests__/patterns.test.js +481 -0
  17. package/dist/nodes/PiiRedactor/__tests__/phase1.test.d.ts +1 -0
  18. package/dist/nodes/PiiRedactor/__tests__/phase1.test.js +343 -0
  19. package/dist/nodes/PiiRedactor/__tests__/phase3.test.d.ts +1 -0
  20. package/dist/nodes/PiiRedactor/__tests__/phase3.test.js +275 -0
  21. package/dist/nodes/PiiRedactor/__tests__/phase4.test.d.ts +1 -0
  22. package/dist/nodes/PiiRedactor/__tests__/phase4.test.js +184 -0
  23. package/dist/nodes/PiiRedactor/__tests__/presidio.test.d.ts +1 -0
  24. package/dist/nodes/PiiRedactor/__tests__/presidio.test.js +170 -0
  25. package/dist/nodes/PiiRedactor/__tests__/security.test.d.ts +1 -0
  26. package/dist/nodes/PiiRedactor/__tests__/security.test.js +178 -0
  27. package/dist/nodes/PiiRedactor/__tests__/semantic.test.d.ts +1 -0
  28. package/dist/nodes/PiiRedactor/__tests__/semantic.test.js +319 -0
  29. package/dist/nodes/PiiRedactor/__tests__/vault.test.d.ts +1 -0
  30. package/dist/nodes/PiiRedactor/__tests__/vault.test.js +247 -0
  31. package/dist/nodes/PiiRedactor/audit.d.ts +48 -0
  32. package/dist/nodes/PiiRedactor/audit.js +192 -0
  33. package/dist/nodes/PiiRedactor/classification.d.ts +33 -0
  34. package/dist/nodes/PiiRedactor/classification.js +118 -0
  35. package/dist/nodes/PiiRedactor/context.d.ts +57 -0
  36. package/dist/nodes/PiiRedactor/context.js +260 -0
  37. package/dist/nodes/PiiRedactor/encryption.d.ts +45 -0
  38. package/dist/nodes/PiiRedactor/encryption.js +158 -0
  39. package/dist/nodes/PiiRedactor/engine.d.ts +23 -0
  40. package/dist/nodes/PiiRedactor/engine.js +888 -0
  41. package/dist/nodes/PiiRedactor/injection.d.ts +46 -0
  42. package/dist/nodes/PiiRedactor/injection.js +425 -0
  43. package/dist/nodes/PiiRedactor/names.d.ts +25 -0
  44. package/dist/nodes/PiiRedactor/names.js +188 -0
  45. package/dist/nodes/PiiRedactor/patterns.d.ts +17 -0
  46. package/dist/nodes/PiiRedactor/patterns.js +1742 -0
  47. package/dist/nodes/PiiRedactor/presidio.d.ts +77 -0
  48. package/dist/nodes/PiiRedactor/presidio.js +264 -0
  49. package/dist/nodes/PiiRedactor/profiles.d.ts +47 -0
  50. package/dist/nodes/PiiRedactor/profiles.js +139 -0
  51. package/dist/nodes/PiiRedactor/pseudonymize.d.ts +20 -0
  52. package/dist/nodes/PiiRedactor/pseudonymize.js +203 -0
  53. package/dist/nodes/PiiRedactor/redact.png +0 -0
  54. package/dist/nodes/PiiRedactor/redact.svg +3 -0
  55. package/dist/nodes/PiiRedactor/ropa.d.ts +63 -0
  56. package/dist/nodes/PiiRedactor/ropa.js +70 -0
  57. package/dist/nodes/PiiRedactor/types.d.ts +82 -0
  58. package/dist/nodes/PiiRedactor/types.js +3 -0
  59. package/dist/nodes/PiiRedactor/vault.d.ts +61 -0
  60. package/dist/nodes/PiiRedactor/vault.js +352 -0
  61. package/package.json +87 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Vault Encryption Engine (AES-256-GCM)
3
+ *
4
+ * Encrypts vault files at rest so that even if someone accesses the
5
+ * filesystem, they cannot read the PII mapping data without the passphrase.
6
+ *
7
+ * Security properties:
8
+ * - AES-256-GCM: Authenticated encryption (confidentiality + integrity)
9
+ * - scrypt key derivation: Memory-hard, resists GPU/ASIC brute-force
10
+ * - Unique salt per file: Same passphrase produces different keys per file
11
+ * - Unique IV per encryption: Same data produces different ciphertext
12
+ * - Auth tag: Detects tampering or wrong passphrase
13
+ *
14
+ * File format:
15
+ * [1 byte: version 0x01]
16
+ * [16 bytes: salt]
17
+ * [12 bytes: IV]
18
+ * [16 bytes: GCM auth tag]
19
+ * [N bytes: ciphertext]
20
+ *
21
+ * Backward compatible:
22
+ * - Files starting with '{' (0x7B) are read as plaintext JSON
23
+ * - Files starting with 0x01 are decrypted
24
+ * - Unencrypted files are auto-migrated to encrypted on next save
25
+ */
26
+ /**
27
+ * Encrypt a JSON string using AES-256-GCM.
28
+ * Returns a Buffer in the encrypted file format.
29
+ */
30
+ export declare function encryptVaultData(jsonData: string, passphrase: string): Buffer;
31
+ /**
32
+ * Decrypt vault data from the encrypted file format.
33
+ * Returns the decrypted JSON string.
34
+ * Throws on wrong passphrase, corrupted data, or tampered file.
35
+ */
36
+ export declare function decryptVaultData(data: Buffer, passphrase: string): string;
37
+ /**
38
+ * Check if a buffer contains encrypted vault data (starts with version byte).
39
+ * If it starts with '{' (0x7B), it's plaintext JSON.
40
+ */
41
+ export declare function isEncryptedVault(data: Buffer): boolean;
42
+ /**
43
+ * Check if a buffer contains plaintext JSON vault data.
44
+ */
45
+ export declare function isPlaintextVault(data: Buffer): boolean;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * Vault Encryption Engine (AES-256-GCM)
4
+ *
5
+ * Encrypts vault files at rest so that even if someone accesses the
6
+ * filesystem, they cannot read the PII mapping data without the passphrase.
7
+ *
8
+ * Security properties:
9
+ * - AES-256-GCM: Authenticated encryption (confidentiality + integrity)
10
+ * - scrypt key derivation: Memory-hard, resists GPU/ASIC brute-force
11
+ * - Unique salt per file: Same passphrase produces different keys per file
12
+ * - Unique IV per encryption: Same data produces different ciphertext
13
+ * - Auth tag: Detects tampering or wrong passphrase
14
+ *
15
+ * File format:
16
+ * [1 byte: version 0x01]
17
+ * [16 bytes: salt]
18
+ * [12 bytes: IV]
19
+ * [16 bytes: GCM auth tag]
20
+ * [N bytes: ciphertext]
21
+ *
22
+ * Backward compatible:
23
+ * - Files starting with '{' (0x7B) are read as plaintext JSON
24
+ * - Files starting with 0x01 are decrypted
25
+ * - Unencrypted files are auto-migrated to encrypted on next save
26
+ */
27
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ var desc = Object.getOwnPropertyDescriptor(m, k);
30
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
31
+ desc = { enumerable: true, get: function() { return m[k]; } };
32
+ }
33
+ Object.defineProperty(o, k2, desc);
34
+ }) : (function(o, m, k, k2) {
35
+ if (k2 === undefined) k2 = k;
36
+ o[k2] = m[k];
37
+ }));
38
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
39
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
40
+ }) : function(o, v) {
41
+ o["default"] = v;
42
+ });
43
+ var __importStar = (this && this.__importStar) || (function () {
44
+ var ownKeys = function(o) {
45
+ ownKeys = Object.getOwnPropertyNames || function (o) {
46
+ var ar = [];
47
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
48
+ return ar;
49
+ };
50
+ return ownKeys(o);
51
+ };
52
+ return function (mod) {
53
+ if (mod && mod.__esModule) return mod;
54
+ var result = {};
55
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
56
+ __setModuleDefault(result, mod);
57
+ return result;
58
+ };
59
+ })();
60
+ Object.defineProperty(exports, "__esModule", { value: true });
61
+ exports.encryptVaultData = encryptVaultData;
62
+ exports.decryptVaultData = decryptVaultData;
63
+ exports.isEncryptedVault = isEncryptedVault;
64
+ exports.isPlaintextVault = isPlaintextVault;
65
+ const crypto = __importStar(require("crypto"));
66
+ const VERSION_BYTE = 0x01;
67
+ const SALT_LENGTH = 16;
68
+ const IV_LENGTH = 12;
69
+ const AUTH_TAG_LENGTH = 16;
70
+ const KEY_LENGTH = 32; // AES-256
71
+ const SCRYPT_N = 2 ** 14; // 16384 — fast and secure for file encryption
72
+ const SCRYPT_R = 8;
73
+ const SCRYPT_P = 1;
74
+ /**
75
+ * Derive a 256-bit encryption key from a passphrase using scrypt.
76
+ */
77
+ function deriveKey(passphrase, salt) {
78
+ return crypto.scryptSync(passphrase, salt, KEY_LENGTH, {
79
+ N: SCRYPT_N,
80
+ r: SCRYPT_R,
81
+ p: SCRYPT_P,
82
+ });
83
+ }
84
+ /**
85
+ * Encrypt a JSON string using AES-256-GCM.
86
+ * Returns a Buffer in the encrypted file format.
87
+ */
88
+ function encryptVaultData(jsonData, passphrase) {
89
+ const salt = crypto.randomBytes(SALT_LENGTH);
90
+ const iv = crypto.randomBytes(IV_LENGTH);
91
+ const key = deriveKey(passphrase, salt);
92
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
93
+ const encrypted = Buffer.concat([
94
+ cipher.update(jsonData, 'utf-8'),
95
+ cipher.final(),
96
+ ]);
97
+ const authTag = cipher.getAuthTag();
98
+ // Assemble: [version][salt][iv][authTag][ciphertext]
99
+ return Buffer.concat([
100
+ Buffer.from([VERSION_BYTE]),
101
+ salt,
102
+ iv,
103
+ authTag,
104
+ encrypted,
105
+ ]);
106
+ }
107
+ /**
108
+ * Decrypt vault data from the encrypted file format.
109
+ * Returns the decrypted JSON string.
110
+ * Throws on wrong passphrase, corrupted data, or tampered file.
111
+ */
112
+ function decryptVaultData(data, passphrase) {
113
+ if (data.length < 1 + SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH + 1) {
114
+ throw new Error('Encrypted vault file is too short or corrupted.');
115
+ }
116
+ const version = data[0];
117
+ if (version !== VERSION_BYTE) {
118
+ throw new Error(`Unsupported vault encryption version: ${version}`);
119
+ }
120
+ let offset = 1;
121
+ const salt = data.subarray(offset, offset + SALT_LENGTH);
122
+ offset += SALT_LENGTH;
123
+ const iv = data.subarray(offset, offset + IV_LENGTH);
124
+ offset += IV_LENGTH;
125
+ const authTag = data.subarray(offset, offset + AUTH_TAG_LENGTH);
126
+ offset += AUTH_TAG_LENGTH;
127
+ const ciphertext = data.subarray(offset);
128
+ const key = deriveKey(passphrase, salt);
129
+ try {
130
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
131
+ decipher.setAuthTag(authTag);
132
+ const decrypted = Buffer.concat([
133
+ decipher.update(ciphertext),
134
+ decipher.final(),
135
+ ]);
136
+ return decrypted.toString('utf-8');
137
+ }
138
+ catch {
139
+ throw new Error('Vault decryption failed: wrong passphrase or corrupted file.');
140
+ }
141
+ }
142
+ /**
143
+ * Check if a buffer contains encrypted vault data (starts with version byte).
144
+ * If it starts with '{' (0x7B), it's plaintext JSON.
145
+ */
146
+ function isEncryptedVault(data) {
147
+ if (data.length === 0)
148
+ return false;
149
+ return data[0] === VERSION_BYTE;
150
+ }
151
+ /**
152
+ * Check if a buffer contains plaintext JSON vault data.
153
+ */
154
+ function isPlaintextVault(data) {
155
+ if (data.length === 0)
156
+ return false;
157
+ return data[0] === 0x7B; // '{'
158
+ }
@@ -0,0 +1,23 @@
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
+ * Run Presidio NLP analysis on all string values in an item,
15
+ * then redact the detected entities. Called AFTER regex-based redaction.
16
+ * This catches entities that regex missed (especially PERSON names in free text).
17
+ */
18
+ export declare function enhanceWithPresidio(data: Record<string, unknown>, ctx: RedactionContext, vault: IVault, sessionId: string, hits: RedactionHit[], itemIndex: number): Promise<Record<string, unknown>>;
19
+ /**
20
+ * Build a redaction audit report from collected hits.
21
+ * SECURITY: Original PII values are NEVER included in the report.
22
+ */
23
+ export declare function buildReport(sessionId: string, hits: RedactionHit[]): RedactionReport;