@memberjunction/encryption 0.0.1 → 2.130.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.
Files changed (46) hide show
  1. package/README.md +391 -28
  2. package/dist/EncryptionEngine.d.ts +351 -0
  3. package/dist/EncryptionEngine.d.ts.map +1 -0
  4. package/dist/EncryptionEngine.js +683 -0
  5. package/dist/EncryptionEngine.js.map +1 -0
  6. package/dist/EncryptionKeySourceBase.d.ts +203 -0
  7. package/dist/EncryptionKeySourceBase.d.ts.map +1 -0
  8. package/dist/EncryptionKeySourceBase.js +133 -0
  9. package/dist/EncryptionKeySourceBase.js.map +1 -0
  10. package/dist/actions/EnableFieldEncryptionAction.d.ts +87 -0
  11. package/dist/actions/EnableFieldEncryptionAction.d.ts.map +1 -0
  12. package/dist/actions/EnableFieldEncryptionAction.js +308 -0
  13. package/dist/actions/EnableFieldEncryptionAction.js.map +1 -0
  14. package/dist/actions/RotateEncryptionKeyAction.d.ts +79 -0
  15. package/dist/actions/RotateEncryptionKeyAction.d.ts.map +1 -0
  16. package/dist/actions/RotateEncryptionKeyAction.js +343 -0
  17. package/dist/actions/RotateEncryptionKeyAction.js.map +1 -0
  18. package/dist/actions/index.d.ts +12 -0
  19. package/dist/actions/index.d.ts.map +1 -0
  20. package/dist/actions/index.js +17 -0
  21. package/dist/actions/index.js.map +1 -0
  22. package/dist/index.d.ts +66 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +81 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/interfaces.d.ts +216 -0
  27. package/dist/interfaces.d.ts.map +1 -0
  28. package/dist/interfaces.js +15 -0
  29. package/dist/interfaces.js.map +1 -0
  30. package/dist/providers/AWSKMSKeySource.d.ts +110 -0
  31. package/dist/providers/AWSKMSKeySource.d.ts.map +1 -0
  32. package/dist/providers/AWSKMSKeySource.js +245 -0
  33. package/dist/providers/AWSKMSKeySource.js.map +1 -0
  34. package/dist/providers/AzureKeyVaultKeySource.d.ts +109 -0
  35. package/dist/providers/AzureKeyVaultKeySource.d.ts.map +1 -0
  36. package/dist/providers/AzureKeyVaultKeySource.js +268 -0
  37. package/dist/providers/AzureKeyVaultKeySource.js.map +1 -0
  38. package/dist/providers/ConfigFileKeySource.d.ts +173 -0
  39. package/dist/providers/ConfigFileKeySource.d.ts.map +1 -0
  40. package/dist/providers/ConfigFileKeySource.js +310 -0
  41. package/dist/providers/ConfigFileKeySource.js.map +1 -0
  42. package/dist/providers/EnvVarKeySource.d.ts +152 -0
  43. package/dist/providers/EnvVarKeySource.d.ts.map +1 -0
  44. package/dist/providers/EnvVarKeySource.js +251 -0
  45. package/dist/providers/EnvVarKeySource.js.map +1 -0
  46. package/package.json +65 -6
@@ -0,0 +1,351 @@
1
+ /**
2
+ * @fileoverview Core encryption engine for MemberJunction field-level encryption.
3
+ *
4
+ * The EncryptionEngine is the central class for all encryption and decryption
5
+ * operations. It provides:
6
+ *
7
+ * - AES-256-GCM/CBC encryption with authenticated encryption support
8
+ * - Pluggable key sources via the ClassFactory pattern
9
+ * - Multi-level caching for performance (inherited from EncryptionEngineBase)
10
+ * - Self-describing encrypted value format
11
+ * - Key rotation support with explicit lookup overrides
12
+ *
13
+ * ## Usage
14
+ *
15
+ * ```typescript
16
+ * import { EncryptionEngine } from '@memberjunction/encryption';
17
+ *
18
+ * // First, configure the engine to load metadata
19
+ * await EncryptionEngine.Instance.Config(false, contextUser);
20
+ *
21
+ * // Encrypt a value
22
+ * const encrypted = await EncryptionEngine.Instance.Encrypt(
23
+ * 'sensitive-data',
24
+ * encryptionKeyId,
25
+ * contextUser
26
+ * );
27
+ *
28
+ * // Decrypt a value
29
+ * const decrypted = await EncryptionEngine.Instance.Decrypt(encrypted, contextUser);
30
+ *
31
+ * // Check if a value is encrypted
32
+ * if (EncryptionEngine.Instance.IsEncrypted(someValue)) {
33
+ * // Handle encrypted value
34
+ * }
35
+ * ```
36
+ *
37
+ * ## Security Design
38
+ *
39
+ * - Keys are never stored in memory longer than needed
40
+ * - Authenticated encryption (GCM) prevents tampering
41
+ * - Random IVs for each encryption operation
42
+ * - Self-describing format enables proper key lookup
43
+ * - Secure defaults (fail-safe on errors)
44
+ *
45
+ * @module @memberjunction/encryption
46
+ */
47
+ /// <reference types="node" />
48
+ import { IMetadataProvider, UserInfo } from '@memberjunction/core';
49
+ import { EncryptionEngineBase } from '@memberjunction/core-entities';
50
+ import { EncryptedValueParts } from './interfaces';
51
+ /**
52
+ * Core encryption engine for field-level encryption operations.
53
+ *
54
+ * This class extends EncryptionEngineBase to inherit metadata caching for
55
+ * encryption keys, algorithms, and key sources. It adds the actual
56
+ * encryption/decryption operations using Node.js crypto.
57
+ *
58
+ * Use `EncryptionEngine.Instance` to access the singleton.
59
+ *
60
+ * ## Thread Safety
61
+ *
62
+ * The engine is designed to be safe for concurrent use in async contexts.
63
+ * Cache operations are atomic Map operations and crypto operations
64
+ * use per-call state.
65
+ *
66
+ * ## Error Handling
67
+ *
68
+ * The engine throws descriptive errors for:
69
+ * - Missing keys or configurations
70
+ * - Invalid encrypted value format
71
+ * - Decryption failures (including auth tag mismatch)
72
+ * - Key length mismatches
73
+ *
74
+ * Callers should catch and handle errors appropriately.
75
+ */
76
+ export declare class EncryptionEngine extends EncryptionEngineBase {
77
+ /**
78
+ * Cache for decrypted key material.
79
+ * Maps 'keyId:version' to Buffer.
80
+ * This is separate from the base class caches since key material
81
+ * is sensitive and needs different handling.
82
+ *
83
+ * @private
84
+ */
85
+ private _keyMaterialCache;
86
+ /**
87
+ * Cache for initialized key source instances.
88
+ * Maps driver class name to provider instance.
89
+ *
90
+ * @private
91
+ */
92
+ private _keySourceCache;
93
+ /**
94
+ * Cache TTL for key material in milliseconds.
95
+ * Can be configured for testing or specific deployment needs.
96
+ *
97
+ * @private
98
+ */
99
+ private readonly _keyMaterialCacheTtlMs;
100
+ /**
101
+ * Gets the singleton instance of the encryption engine.
102
+ *
103
+ * The instance is created on first access and reused thereafter.
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const engine = EncryptionEngine.Instance;
108
+ * await engine.Config(false, contextUser);
109
+ * const encrypted = await engine.Encrypt(data, keyId, contextUser);
110
+ * ```
111
+ */
112
+ static get Instance(): EncryptionEngine;
113
+ /**
114
+ * Configures the engine by loading encryption metadata from the database.
115
+ *
116
+ * This overrides the base Config to ensure proper initialization.
117
+ * Must be called before performing encryption/decryption operations.
118
+ *
119
+ * @param forceRefresh - If true, reloads data even if already loaded
120
+ * @param contextUser - User context for database access (required server-side)
121
+ * @param provider - Optional metadata provider override
122
+ */
123
+ Config(forceRefresh?: boolean, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<void>;
124
+ /**
125
+ * Encrypts a value using the specified encryption key.
126
+ *
127
+ * The method:
128
+ * 1. Gets the key configuration from cached metadata
129
+ * 2. Retrieves key material from the configured source (cached)
130
+ * 3. Generates a random IV
131
+ * 4. Encrypts the data using the configured algorithm
132
+ * 5. Returns a self-describing encrypted string
133
+ *
134
+ * ## Encrypted Format
135
+ *
136
+ * The result format is:
137
+ * `$ENC$<keyId>$<algorithm>$<iv>$<ciphertext>[$<authTag>]`
138
+ *
139
+ * This format contains all information needed for decryption.
140
+ *
141
+ * @param plaintext - The value to encrypt (string or Buffer)
142
+ * @param encryptionKeyId - UUID of the encryption key to use
143
+ * @param contextUser - User context for database access
144
+ * @returns The encrypted value as a string
145
+ *
146
+ * @throws Error if the key cannot be found or is invalid
147
+ * @throws Error if key material retrieval fails
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const encrypted = await engine.Encrypt(
152
+ * 'secret-api-key',
153
+ * '550e8400-e29b-41d4-a716-446655440000',
154
+ * currentUser
155
+ * );
156
+ * // Returns: $ENC$550e8400-....$AES-256-GCM$<iv>$<ciphertext>$<authTag>
157
+ * ```
158
+ */
159
+ Encrypt(plaintext: string | Buffer, encryptionKeyId: string, contextUser?: UserInfo): Promise<string>;
160
+ /**
161
+ * Decrypts an encrypted value.
162
+ *
163
+ * If the value is not encrypted (doesn't start with marker), returns it unchanged.
164
+ *
165
+ * The method:
166
+ * 1. Parses the encrypted value to extract key ID and parameters
167
+ * 2. Gets the key configuration from cached metadata
168
+ * 3. Retrieves key material from the configured source (cached)
169
+ * 4. Decrypts using the algorithm and IV from the encrypted value
170
+ * 5. Verifies the auth tag for AEAD algorithms
171
+ *
172
+ * @param value - The value to decrypt (may or may not be encrypted)
173
+ * @param contextUser - User context for database access
174
+ * @returns The decrypted plaintext, or original value if not encrypted
175
+ *
176
+ * @throws Error if decryption fails (invalid key, corrupted data, auth tag mismatch)
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * // Decrypt an encrypted value
181
+ * const plaintext = await engine.Decrypt(encryptedValue, contextUser);
182
+ *
183
+ * // Non-encrypted values pass through unchanged
184
+ * const same = await engine.Decrypt('plain-text', contextUser);
185
+ * // Returns: 'plain-text'
186
+ * ```
187
+ */
188
+ Decrypt(value: string, contextUser?: UserInfo): Promise<string>;
189
+ /**
190
+ * Checks if a value is encrypted.
191
+ *
192
+ * Encrypted values start with the marker prefix (default: '$ENC$').
193
+ * This also checks for the encrypted sentinel value.
194
+ * This is a fast, synchronous check that doesn't require database access.
195
+ *
196
+ * @param value - The value to check
197
+ * @param encryptionMarker - Optional custom marker to check for (defaults to '$ENC$')
198
+ * @returns `true` if the value appears to be encrypted or is the sentinel value
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * if (engine.IsEncrypted(fieldValue)) {
203
+ * const decrypted = await engine.Decrypt(fieldValue, user);
204
+ * }
205
+ *
206
+ * // With custom marker from key
207
+ * const key = engine.GetKeyByID(keyId);
208
+ * if (engine.IsEncrypted(fieldValue, key?.Marker)) {
209
+ * const decrypted = await engine.Decrypt(fieldValue, user);
210
+ * }
211
+ * ```
212
+ */
213
+ IsEncrypted(value: unknown, encryptionMarker?: string): boolean;
214
+ /**
215
+ * Parses an encrypted value string into its component parts.
216
+ *
217
+ * Use this when you need to inspect the encrypted value without decrypting.
218
+ *
219
+ * @param value - The encrypted value string
220
+ * @returns Parsed components (marker, keyId, algorithm, iv, ciphertext, authTag)
221
+ *
222
+ * @throws Error if the format is invalid
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * const parts = engine.ParseEncryptedValue(encryptedValue);
227
+ * console.log(`Encrypted with key: ${parts.keyId}`);
228
+ * console.log(`Algorithm: ${parts.algorithm}`);
229
+ * ```
230
+ */
231
+ ParseEncryptedValue(value: string): EncryptedValueParts;
232
+ /**
233
+ * Validates that key material is accessible at a given lookup value.
234
+ *
235
+ * Used before key rotation to verify the new key exists and is valid.
236
+ * This prevents starting a rotation that would fail mid-way.
237
+ *
238
+ * @param lookupValue - The key source lookup value to validate
239
+ * @param encryptionKeyId - The key ID (to get source configuration)
240
+ * @param contextUser - User context for database access
241
+ *
242
+ * @throws Error if the key material cannot be accessed or is invalid
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * // Before rotation, validate the new key is ready
247
+ * await engine.ValidateKeyMaterial(
248
+ * 'MJ_ENCRYPTION_KEY_PII_NEW',
249
+ * existingKeyId,
250
+ * contextUser
251
+ * );
252
+ * // If no error, safe to proceed with rotation
253
+ * ```
254
+ */
255
+ ValidateKeyMaterial(lookupValue: string, encryptionKeyId: string, contextUser?: UserInfo): Promise<void>;
256
+ /**
257
+ * Encrypts a value using a specific key lookup (for key rotation).
258
+ *
259
+ * During key rotation, we need to encrypt with the new key material
260
+ * before updating the key metadata. This method allows specifying
261
+ * an alternate lookup value for the key material.
262
+ *
263
+ * @param plaintext - The value to encrypt
264
+ * @param encryptionKeyId - The key ID (for algorithm/marker config)
265
+ * @param keyLookupValue - Alternate lookup value for key material
266
+ * @param contextUser - User context for database access
267
+ * @returns The encrypted value string
268
+ *
269
+ * @example
270
+ * ```typescript
271
+ * // During rotation, encrypt with new key before metadata update
272
+ * const newEncrypted = await engine.EncryptWithLookup(
273
+ * decryptedData,
274
+ * keyId,
275
+ * 'MJ_ENCRYPTION_KEY_PII_NEW',
276
+ * contextUser
277
+ * );
278
+ * ```
279
+ */
280
+ EncryptWithLookup(plaintext: string | Buffer, encryptionKeyId: string, keyLookupValue: string, contextUser?: UserInfo): Promise<string>;
281
+ /**
282
+ * Clears key material and source caches.
283
+ *
284
+ * Call after key rotation or configuration changes to ensure
285
+ * fresh data is loaded. The base class metadata caches are
286
+ * handled separately via RefreshAllItems().
287
+ */
288
+ ClearCaches(): void;
289
+ /**
290
+ * Clears all caches including base class metadata caches.
291
+ *
292
+ * This is more aggressive than ClearCaches() and should be used
293
+ * when you need to completely refresh all cached data.
294
+ */
295
+ ClearAllCaches(): Promise<void>;
296
+ /**
297
+ * Ensures the engine is configured before operations.
298
+ *
299
+ * @private
300
+ */
301
+ private ensureConfigured;
302
+ /**
303
+ * Builds a KeyConfiguration object from the cached metadata.
304
+ *
305
+ * @private
306
+ */
307
+ private buildKeyConfiguration;
308
+ /**
309
+ * Performs the actual encryption operation.
310
+ *
311
+ * @private
312
+ */
313
+ private performEncryption;
314
+ /**
315
+ * Performs the actual decryption operation.
316
+ *
317
+ * @private
318
+ */
319
+ private performDecryption;
320
+ /**
321
+ * Gets key material from cache or source.
322
+ *
323
+ * @private
324
+ */
325
+ private getKeyMaterial;
326
+ /**
327
+ * Gets key material using an overridden lookup value (for rotation).
328
+ *
329
+ * @private
330
+ */
331
+ private getKeyMaterialWithLookup;
332
+ /**
333
+ * Gets or creates a key source instance.
334
+ *
335
+ * @private
336
+ */
337
+ private getOrCreateKeySource;
338
+ /**
339
+ * Validates that key material has the correct length for the algorithm.
340
+ *
341
+ * @private
342
+ */
343
+ private validateKeyLength;
344
+ /**
345
+ * Validates that a string is a valid UUID.
346
+ *
347
+ * @private
348
+ */
349
+ private isValidUUID;
350
+ }
351
+ //# sourceMappingURL=EncryptionEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EncryptionEngine.d.ts","sourceRoot":"","sources":["../src/EncryptionEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;;AAIH,OAAO,EAAE,iBAAiB,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EACH,mBAAmB,EAEtB,MAAM,cAAc,CAAC;AAkBtB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,gBAAiB,SAAQ,oBAAoB;IACtD;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB,CAA8C;IAEvE;;;;;OAKG;IACH,OAAO,CAAC,eAAe,CAAmD;IAE1E;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA6C;IAEpF;;;;;;;;;;;OAWG;IACH,WAA2B,QAAQ,IAAI,gBAAgB,CAEtD;IAED;;;;;;;;;OASG;IACmB,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACG,OAAO,CACT,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,eAAe,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,MAAM,CAAC;IA2BlB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,OAAO,CACT,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO;IAI/D;;;;;;;;;;;;;;;;OAgBG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB;IA2CvD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,mBAAmB,CACrB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,iBAAiB,CACnB,SAAS,EAAE,MAAM,GAAG,MAAM,EAC1B,eAAe,EAAE,MAAM,EACvB,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;;;;OAMG;IACH,WAAW,IAAI,IAAI;IAKnB;;;;;OAKG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IASrC;;;;OAIG;YACW,gBAAgB;IAM9B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IA0D7B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAiDzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAuEzB;;;;OAIG;YACW,cAAc;IA8B5B;;;;OAIG;YACW,wBAAwB;IActC;;;;OAIG;YACW,oBAAoB;IAmDlC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAazB;;;;OAIG;IACH,OAAO,CAAC,WAAW;CAStB"}