mask-privacy 4.0.0 → 4.2.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.
package/dist/index.d.mts CHANGED
@@ -1,11 +1,13 @@
1
1
  /** Interface every vault backend must implement. */
2
2
  declare abstract class BaseVault {
3
- /** Persist a token → plaintext mapping with a TTL. Optionally save a reverse lookup hash. */
4
- abstract store(token: string, plaintext: string, ttlSeconds: number, ptHash?: string | null): Promise<void>;
3
+ /** Persist a token → encrypted plaintext mapping with a TTL and optional compliance metadata. */
4
+ abstract store(token: string, plaintext: string, ttlSeconds: number, ptHash?: string | null, metadata?: Record<string, string> | null): Promise<void>;
5
5
  /** Return the existing unexpired token for a given plaintext hash, or null. */
6
6
  abstract getTokenByPlaintextHash(ptHash: string): Promise<string | null>;
7
7
  /** Return the plaintext for token, or null if missing/expired. */
8
8
  abstract retrieve(token: string): Promise<string | null>;
9
+ /** Return the plaintext hash stored for this token (used for collision detection), or null. */
10
+ abstract getPtHashForToken(token: string): Promise<string | null>;
9
11
  /** Delete a token and its reverse mapping. */
10
12
  abstract delete(token: string): Promise<void>;
11
13
  }
@@ -15,6 +17,7 @@ type EncodeOptions = {
15
17
  searchBuckets?: ('year' | 'month' | 'day' | 'numeric')[];
16
18
  searchBucketSize?: number;
17
19
  entityType?: string;
20
+ metadata?: Record<string, string> | null;
18
21
  };
19
22
  /**
20
23
  * Tokenise rawText, encrypt it, store in vault, return the FPE token.
@@ -41,18 +44,11 @@ declare const adetokenizeText: typeof detokenizeText;
41
44
  declare function looksLikeToken(value: string | any): boolean;
42
45
 
43
46
  /**
44
- * Format-Preserving Encryption (FPE) token generation.
45
- *
46
- * Generates structurally valid, **deterministic** tokens that preserve the
47
- * format of the original data type so downstream tools, schemas, and
48
- * validators continue to work without modification.
47
+ * Deterministic Pseudonymization (DP) token generation using NIST SP 800-38G FF1.
49
48
  */
50
- /** Clear the cached master key. Useful in tests. */
51
49
  declare function resetMasterKey(): void;
52
- /**
53
- * Return a **deterministic**, format-preserving token for rawText using its entityType.
54
- */
55
- declare function generateFPEToken(rawText: string, entityType?: string): Promise<string>;
50
+ declare function generateDPToken(rawText: string, entityType?: string): Promise<string>;
51
+ declare const generateFPEToken: typeof generateDPToken;
56
52
 
57
53
  /**
58
54
  * Span Resolution Engine — Sweep-Line Overlap Resolver (TypeScript).
@@ -184,44 +180,43 @@ declare class MaskSecurityError extends MaskError {
184
180
  /**
185
181
  * Core cryptography engine for Mask SDK.
186
182
  *
187
- * Provides a CryptoEngine singleton that handles Envelope Encryption,
188
- * ensuring that plaintext PII is encrypted locally before being
189
- * transmitted and stored in distributed vaults (Redis/Memcached/DynamoDB).
183
+ * Supports a JSON-based Keyring for transparent key rotation:
184
+ * MASK_KEYRING='{"v1":"oldkey...","v2":"newkey..."}'
185
+ * The *last* key in the JSON object is the active encryption key.
186
+ * All keys in the keyring are available for decryption (zero-downtime rotation).
190
187
  *
191
- * Uses AES-256-GCM (authenticated encryption) via native Node.js crypto.
192
- * Includes a compatibility layer to decrypt legacy Fernet-format tokens.
188
+ * Legacy single-key mode (MASK_ENCRYPTION_KEY) is fully mapped to key ID "default".
193
189
  *
194
- * Requires MASK_ENCRYPTION_KEY to be set in the environment.
190
+ * Ciphertext envelope format: aes:v2:{keyId}:{base64(iv+authTag+ciphertext)}
191
+ *
192
+ * Uses AES-256-GCM via native Node.js crypto and Argon2id for key derivation.
195
193
  */
196
194
  declare class CryptoEngine {
197
195
  private static _instance;
198
- private _aesKey;
196
+ private _keyring;
197
+ private _activeKeyId;
199
198
  private _indexSecret;
200
199
  private constructor();
201
200
  /**
202
201
  * Return the singleton instance, initialising it if necessary.
203
- * This is asynchronous because key providers (KMS, etc.) might be async.
202
+ * Async because Argon2id key derivation is async.
204
203
  */
205
204
  static getInstanceAsync(): Promise<CryptoEngine>;
206
205
  /** Legacy synchronous accessor — will throw if not already initialised. */
207
206
  static getInstance(): CryptoEngine;
208
- /** Clear the singleton instance to force re-initialization (useful for key rotation). */
207
+ /** Clear the singleton (useful for key rotation / tests). */
209
208
  static reset(): void;
209
+ private _deriveAesKey;
210
210
  private _init;
211
211
  /** Return the secret used for HMAC-based blind indexing. */
212
212
  getIndexSecret(): Promise<Buffer>;
213
+ /** Encrypt plaintext using the active keyring key.
214
+ * Envelope format: aes:v2:{keyId}:{base64(iv+authTag+ciphertext)}
215
+ */
213
216
  encrypt(plaintext: string): string;
217
+ /** Decrypt ciphertext. Supports all historical envelope formats. */
214
218
  decrypt(ciphertext: string): string;
215
- /** Decrypt an AES-256-GCM token (base64 encoded). */
216
219
  private _decryptAesGcm;
217
- /**
218
- * Attempt to decrypt a legacy Fernet-format token.
219
- *
220
- * Fernet format: Version (1) || Timestamp (8) || IV (16) || Ciphertext (var) || HMAC (32)
221
- * All base64url-encoded.
222
- *
223
- * We try to use the `fernet` npm package if available, otherwise throw.
224
- */
225
220
  private _decryptLegacyFernet;
226
221
  }
227
222
 
@@ -236,13 +231,24 @@ declare class AuditLogger {
236
231
  private _strictMode;
237
232
  private _bufferFullWarned;
238
233
  private _shutdownRegistered;
234
+ private _signingKey;
235
+ private _prevSig;
236
+ private _instanceId;
239
237
  private constructor();
240
238
  static getInstance(): AuditLogger;
239
+ private _getOverflowPath;
240
+ private _writeOverflow;
241
+ private _consumeOverflow;
241
242
  log(action: string, token: string, dataType?: string, agent?: string, tool?: string, extra?: Record<string, any>): void;
242
243
  start(): void;
243
244
  stop(): Promise<void>;
244
245
  private _flush;
245
- /** Synchronous flush for use in signal handlers where async is unreliable. */
246
+ /** Synchronous flush for use in signal handlers where async is unreliable.
247
+ *
248
+ * Computes HMAC signatures to maintain chain integrity and writes to the
249
+ * secure ndjson audit file (MASK_SECURE_AUDIT_LOG_DIR) if configured,
250
+ * ensuring SOC 2 tamper-evidence guarantees hold through process shutdown.
251
+ */
246
252
  private _flushSync;
247
253
  }
248
254
 
package/dist/index.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  /** Interface every vault backend must implement. */
2
2
  declare abstract class BaseVault {
3
- /** Persist a token → plaintext mapping with a TTL. Optionally save a reverse lookup hash. */
4
- abstract store(token: string, plaintext: string, ttlSeconds: number, ptHash?: string | null): Promise<void>;
3
+ /** Persist a token → encrypted plaintext mapping with a TTL and optional compliance metadata. */
4
+ abstract store(token: string, plaintext: string, ttlSeconds: number, ptHash?: string | null, metadata?: Record<string, string> | null): Promise<void>;
5
5
  /** Return the existing unexpired token for a given plaintext hash, or null. */
6
6
  abstract getTokenByPlaintextHash(ptHash: string): Promise<string | null>;
7
7
  /** Return the plaintext for token, or null if missing/expired. */
8
8
  abstract retrieve(token: string): Promise<string | null>;
9
+ /** Return the plaintext hash stored for this token (used for collision detection), or null. */
10
+ abstract getPtHashForToken(token: string): Promise<string | null>;
9
11
  /** Delete a token and its reverse mapping. */
10
12
  abstract delete(token: string): Promise<void>;
11
13
  }
@@ -15,6 +17,7 @@ type EncodeOptions = {
15
17
  searchBuckets?: ('year' | 'month' | 'day' | 'numeric')[];
16
18
  searchBucketSize?: number;
17
19
  entityType?: string;
20
+ metadata?: Record<string, string> | null;
18
21
  };
19
22
  /**
20
23
  * Tokenise rawText, encrypt it, store in vault, return the FPE token.
@@ -41,18 +44,11 @@ declare const adetokenizeText: typeof detokenizeText;
41
44
  declare function looksLikeToken(value: string | any): boolean;
42
45
 
43
46
  /**
44
- * Format-Preserving Encryption (FPE) token generation.
45
- *
46
- * Generates structurally valid, **deterministic** tokens that preserve the
47
- * format of the original data type so downstream tools, schemas, and
48
- * validators continue to work without modification.
47
+ * Deterministic Pseudonymization (DP) token generation using NIST SP 800-38G FF1.
49
48
  */
50
- /** Clear the cached master key. Useful in tests. */
51
49
  declare function resetMasterKey(): void;
52
- /**
53
- * Return a **deterministic**, format-preserving token for rawText using its entityType.
54
- */
55
- declare function generateFPEToken(rawText: string, entityType?: string): Promise<string>;
50
+ declare function generateDPToken(rawText: string, entityType?: string): Promise<string>;
51
+ declare const generateFPEToken: typeof generateDPToken;
56
52
 
57
53
  /**
58
54
  * Span Resolution Engine — Sweep-Line Overlap Resolver (TypeScript).
@@ -184,44 +180,43 @@ declare class MaskSecurityError extends MaskError {
184
180
  /**
185
181
  * Core cryptography engine for Mask SDK.
186
182
  *
187
- * Provides a CryptoEngine singleton that handles Envelope Encryption,
188
- * ensuring that plaintext PII is encrypted locally before being
189
- * transmitted and stored in distributed vaults (Redis/Memcached/DynamoDB).
183
+ * Supports a JSON-based Keyring for transparent key rotation:
184
+ * MASK_KEYRING='{"v1":"oldkey...","v2":"newkey..."}'
185
+ * The *last* key in the JSON object is the active encryption key.
186
+ * All keys in the keyring are available for decryption (zero-downtime rotation).
190
187
  *
191
- * Uses AES-256-GCM (authenticated encryption) via native Node.js crypto.
192
- * Includes a compatibility layer to decrypt legacy Fernet-format tokens.
188
+ * Legacy single-key mode (MASK_ENCRYPTION_KEY) is fully mapped to key ID "default".
193
189
  *
194
- * Requires MASK_ENCRYPTION_KEY to be set in the environment.
190
+ * Ciphertext envelope format: aes:v2:{keyId}:{base64(iv+authTag+ciphertext)}
191
+ *
192
+ * Uses AES-256-GCM via native Node.js crypto and Argon2id for key derivation.
195
193
  */
196
194
  declare class CryptoEngine {
197
195
  private static _instance;
198
- private _aesKey;
196
+ private _keyring;
197
+ private _activeKeyId;
199
198
  private _indexSecret;
200
199
  private constructor();
201
200
  /**
202
201
  * Return the singleton instance, initialising it if necessary.
203
- * This is asynchronous because key providers (KMS, etc.) might be async.
202
+ * Async because Argon2id key derivation is async.
204
203
  */
205
204
  static getInstanceAsync(): Promise<CryptoEngine>;
206
205
  /** Legacy synchronous accessor — will throw if not already initialised. */
207
206
  static getInstance(): CryptoEngine;
208
- /** Clear the singleton instance to force re-initialization (useful for key rotation). */
207
+ /** Clear the singleton (useful for key rotation / tests). */
209
208
  static reset(): void;
209
+ private _deriveAesKey;
210
210
  private _init;
211
211
  /** Return the secret used for HMAC-based blind indexing. */
212
212
  getIndexSecret(): Promise<Buffer>;
213
+ /** Encrypt plaintext using the active keyring key.
214
+ * Envelope format: aes:v2:{keyId}:{base64(iv+authTag+ciphertext)}
215
+ */
213
216
  encrypt(plaintext: string): string;
217
+ /** Decrypt ciphertext. Supports all historical envelope formats. */
214
218
  decrypt(ciphertext: string): string;
215
- /** Decrypt an AES-256-GCM token (base64 encoded). */
216
219
  private _decryptAesGcm;
217
- /**
218
- * Attempt to decrypt a legacy Fernet-format token.
219
- *
220
- * Fernet format: Version (1) || Timestamp (8) || IV (16) || Ciphertext (var) || HMAC (32)
221
- * All base64url-encoded.
222
- *
223
- * We try to use the `fernet` npm package if available, otherwise throw.
224
- */
225
220
  private _decryptLegacyFernet;
226
221
  }
227
222
 
@@ -236,13 +231,24 @@ declare class AuditLogger {
236
231
  private _strictMode;
237
232
  private _bufferFullWarned;
238
233
  private _shutdownRegistered;
234
+ private _signingKey;
235
+ private _prevSig;
236
+ private _instanceId;
239
237
  private constructor();
240
238
  static getInstance(): AuditLogger;
239
+ private _getOverflowPath;
240
+ private _writeOverflow;
241
+ private _consumeOverflow;
241
242
  log(action: string, token: string, dataType?: string, agent?: string, tool?: string, extra?: Record<string, any>): void;
242
243
  start(): void;
243
244
  stop(): Promise<void>;
244
245
  private _flush;
245
- /** Synchronous flush for use in signal handlers where async is unreliable. */
246
+ /** Synchronous flush for use in signal handlers where async is unreliable.
247
+ *
248
+ * Computes HMAC signatures to maintain chain integrity and writes to the
249
+ * secure ndjson audit file (MASK_SECURE_AUDIT_LOG_DIR) if configured,
250
+ * ensuring SOC 2 tamper-evidence guarantees hold through process shutdown.
251
+ */
246
252
  private _flushSync;
247
253
  }
248
254