@forklaunch/core 1.5.20 → 1.6.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.
@@ -10,17 +10,125 @@ export declare class EncryptionRequiredError extends Error {
10
10
  readonly name: 'EncryptionRequiredError';
11
11
  constructor(message?: string);
12
12
  }
13
+ /**
14
+ * Ciphertext envelopes the encryptor reads. Only `v3` names its key.
15
+ *
16
+ * v1:{iv}:{tag}:{data} random IV (legacy)
17
+ * v2:{iv}:{tag}:{data} deterministic IV
18
+ * v3:{keyId}:{iv}:{tag}:{data} deterministic IV, stamped with the key fingerprint
19
+ */
20
+ export declare const ENCRYPTED_PREFIXES: readonly ['v1:', 'v2:', 'v3:'];
21
+ /** True when the string carries one of the encryptor's envelopes. */
22
+ export declare function isEncryptedCiphertext(value: unknown): value is string;
23
+ /**
24
+ * Which envelope new values are written in.
25
+ *
26
+ * 'v2' unstamped. Default. Byte-compatible with every existing row, so
27
+ * equality lookups keep matching rows written before the ring existed.
28
+ * 'v3' stamped with the writing key's fingerprint. Reads resolve the key
29
+ * directly, a missing key fails by name, and the rows still under a
30
+ * key can be counted with a LIKE. Switch to it only after a rotation
31
+ * sweep has rewritten every row: a v3 write does not byte-match a v2
32
+ * row of the same plaintext, so lookups miss until the sweep is done.
33
+ */
34
+ export type CiphertextFormat = 'v2' | 'v3';
35
+ /** Environment variable holding the key new values are written with. */
36
+ export declare const ENCRYPTION_KEY_ENV = "ENCRYPTION_KEY";
37
+ /** Environment variable holding every previous key, comma separated. */
38
+ export declare const LEGACY_ENCRYPTION_KEYS_ENV = "LEGACY_ENCRYPTION_KEYS";
39
+ /** Older single-key spelling of {@link LEGACY_ENCRYPTION_KEYS_ENV}; still honoured. */
40
+ export declare const LEGACY_ENCRYPTION_KEY_ENV = "LEGACY_ENCRYPTION_KEY";
41
+ /** Environment variable selecting the write format, `v2` (default) or `v3`. */
42
+ export declare const ENCRYPTION_FORMAT_ENV = "ENCRYPTION_FORMAT";
43
+ /**
44
+ * Split a key list as it appears in an environment variable: comma,
45
+ * semicolon or whitespace separated, optionally quoted. Blanks and
46
+ * duplicates are dropped, order is kept.
47
+ */
48
+ export declare function parseEncryptionKeyList(...sources: (string | undefined | null)[]): string[];
49
+ /**
50
+ * A short, non-reversible fingerprint of a master key, for logs, reports
51
+ * and the `v3` envelope. Two deployments with the same key get the same
52
+ * id; the id reveals nothing about the key.
53
+ */
54
+ export declare function encryptionKeyId(masterKey: string): string;
55
+ /**
56
+ * The key fingerprint a stored value is stamped with, or null for `v1`/`v2`
57
+ * values, which name no key.
58
+ */
59
+ export declare function stampedKeyId(ciphertext: string): string | null;
60
+ /** SQL LIKE pattern matching every value stamped with `keyId`. */
61
+ export declare function stampedPrefix(keyId: string): string;
62
+ export interface FieldEncryptorOptions {
63
+ /**
64
+ * Keys that data may still be encrypted under, newest first. Values are
65
+ * never written with these; they are only tried when the current key
66
+ * cannot open a ciphertext. Keep a key here until a rotation sweep
67
+ * (`reencryptEncryptedColumns`) reports nothing left under it.
68
+ */
69
+ previousKeys?: readonly string[];
70
+ /** Envelope for new values. See {@link CiphertextFormat}. Default `v2`. */
71
+ format?: CiphertextFormat;
72
+ }
73
+ /** What {@link FieldEncryptor.open} learned about a ciphertext. */
74
+ export interface OpenedCiphertext {
75
+ plaintext: string;
76
+ /** Fingerprint of the key that opened it; see {@link encryptionKeyId}. */
77
+ keyId: string;
78
+ /** True when the current key opened it. */
79
+ current: boolean;
80
+ /** Envelope the value was stored in. */
81
+ version: 'v1' | 'v2' | 'v3';
82
+ /**
83
+ * True when a rewrite would change the stored bytes: the value is under
84
+ * a previous key, or it is unstamped while the encryptor writes `v3`.
85
+ */
86
+ stale: boolean;
87
+ }
88
+ /**
89
+ * AES-256-GCM field encryption with per-tenant keys derived by HKDF from a
90
+ * master key, and a key ring for rotation.
91
+ *
92
+ * The ring has one current key and any number of previous keys. Every
93
+ * write uses the current key. A `v3` value names its key, so a read looks
94
+ * it up directly and a missing key fails by name. A `v1`/`v2` value names
95
+ * nothing, so a read tries the current key and then each previous key in
96
+ * order; AES-GCM's authentication tag makes "this key opens it" a real
97
+ * check rather than a guess. Either way the master key can change without
98
+ * a downtime window: add the old key to `previousKeys`, deploy, run the
99
+ * rotation sweep, then drop the old key.
100
+ */
13
101
  export declare class FieldEncryptor {
14
- private readonly masterKey;
15
- constructor(masterKey: string);
102
+ private readonly ring;
103
+ private readonly byId;
104
+ private readonly derived;
105
+ readonly format: CiphertextFormat;
106
+ constructor(masterKey: string, options?: FieldEncryptorOptions);
107
+ /**
108
+ * Build the ring from the environment: `ENCRYPTION_KEY` plus
109
+ * `LEGACY_ENCRYPTION_KEYS` (comma separated) and the older
110
+ * `LEGACY_ENCRYPTION_KEY`; `ENCRYPTION_FORMAT` selects the envelope.
111
+ */
112
+ static fromEnv(env?: NodeJS.ProcessEnv): FieldEncryptor;
113
+ /** Fingerprints of the ring, current first. Safe to log. */
114
+ get keyIds(): {
115
+ current: string;
116
+ previous: string[];
117
+ };
118
+ /** A copy of this encryptor with a different set of previous keys. */
119
+ withPreviousKeys(previousKeys: readonly string[]): FieldEncryptor;
120
+ /** A copy of this encryptor writing a different envelope. */
121
+ withFormat(format: CiphertextFormat): FieldEncryptor;
16
122
  /**
17
- * Derive a per-tenant 32-byte key using HKDF-SHA256.
18
- * The master key is used as input key material and the tenantId as info context.
123
+ * Derive a per-tenant 32-byte key using HKDF-SHA256 from the CURRENT
124
+ * master key. The master key is the input key material and the tenantId
125
+ * the info context.
19
126
  */
20
127
  deriveKey(tenantId: string): Buffer;
128
+ private deriveKeyFor;
21
129
  /**
22
130
  * Derive a deterministic IV from the key and plaintext using HMAC-SHA256,
23
- * truncated to IV_BYTES. Same plaintext + same key → same IV → same
131
+ * truncated to IV_BYTES. Same plaintext + same key -> same IV -> same
24
132
  * ciphertext. This enables WHERE clause matching on encrypted columns
25
133
  * while maintaining AES-256-GCM authenticated encryption.
26
134
  *
@@ -28,21 +136,41 @@ export declare class FieldEncryptor {
28
136
  */
29
137
  private deriveDeterministicIv;
30
138
  /**
31
- * Encrypt a plaintext string.
139
+ * Encrypt a plaintext string under the current key.
32
140
  *
33
141
  * Uses deterministic encryption (HMAC-derived IV) so the same plaintext
34
142
  * always produces the same ciphertext. This enables database WHERE clause
35
143
  * matching and UNIQUE constraints on encrypted columns.
36
144
  *
37
- * @returns Format: `v2:{base64(iv)}:{base64(authTag)}:{base64(ciphertext)}`
145
+ * @returns `v2:{iv}:{tag}:{data}`, or `v3:{keyId}:{iv}:{tag}:{data}` when
146
+ * the encryptor's format is `v3`. All parts base64.
38
147
  */
39
148
  encrypt(plaintext: string | null): string | null;
40
149
  encrypt(plaintext: string | null, tenantId: string): string | null;
41
150
  /**
42
- * Decrypt a ciphertext string produced by {@link encrypt}.
43
- * Supports both v1 (random IV) and v2 (deterministic IV) formats.
151
+ * Decrypt a ciphertext string produced by {@link encrypt}, in any
152
+ * envelope: `v3` by its stamped key, `v1`/`v2` by trying every key in
153
+ * the ring.
44
154
  */
45
155
  decrypt(ciphertext: string | null): string | null;
46
156
  decrypt(ciphertext: string | null, tenantId: string): string | null;
157
+ /**
158
+ * Decrypt and report which key opened the value and whether a rewrite
159
+ * would change it. Throws {@link DecryptionError} when no key in the
160
+ * ring does.
161
+ */
162
+ open(ciphertext: string, tenantId?: string): OpenedCiphertext;
163
+ /**
164
+ * True when a rewrite would change the stored bytes: the value is under
165
+ * a previous key, or unstamped while this encryptor writes `v3`. Throws
166
+ * when no key opens it.
167
+ */
168
+ needsRotation(ciphertext: string, tenantId?: string): boolean;
169
+ /**
170
+ * Rewrite a value under the current key in the current format. Returns
171
+ * the input unchanged when nothing would change, so callers can compare
172
+ * to detect writes.
173
+ */
174
+ rotate(ciphertext: string | null, tenantId?: string): string | null;
47
175
  }
48
176
  //# sourceMappingURL=fieldEncryptor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fieldEncryptor.d.ts","sourceRoot":"","sources":["../../src/persistence/fieldEncryptor.ts"],"names":[],"mappings":"AAMA,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,IAAI,EAAG,2BAA2B,CAAU;IACrD,YAAY,OAAO,SAA2C,EAE7D;CACF;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAU;IAC3C,YACE,OAAO,SAAyE,EAGjF;CACF;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAG,yBAAyB,CAAU;IACnD,YACE,OAAO,SAAmE,EAG3E;CACF;AAgBD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,SAAS,EAAE,MAAM,EAK5B;IAED;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIlC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;IACjD,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAwBnE;;;OAGG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;IAClD,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CA+BrE"}
1
+ {"version":3,"file":"fieldEncryptor.d.ts","sourceRoot":"","sources":["../../src/persistence/fieldEncryptor.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@ export { fp } from './compliancePropertyBuilder';
5
5
  export { defineComplianceEntity } from './defineComplianceEntity';
6
6
  export { wrapEmWithNativeQueryBlocking } from './complianceEventSubscriber';
7
7
  export { EncryptedType, registerEncryptor, setEncryptionTenantId, withEncryptionContext, getCurrentTenantId } from './encryptedType';
8
- export { FieldEncryptor, MissingEncryptionKeyError, DecryptionError, EncryptionRequiredError } from './fieldEncryptor';
8
+ export { FieldEncryptor, MissingEncryptionKeyError, DecryptionError, EncryptionRequiredError, parseEncryptionKeyList, encryptionKeyId, stampedKeyId, stampedPrefix, isEncryptedCiphertext, ENCRYPTED_PREFIXES, ENCRYPTION_FORMAT_ENV, ENCRYPTION_KEY_ENV, LEGACY_ENCRYPTION_KEYS_ENV, LEGACY_ENCRYPTION_KEY_ENV, type FieldEncryptorOptions, type OpenedCiphertext, type CiphertextFormat } from './fieldEncryptor';
9
+ export { reencryptEncryptedColumns, classifyEncryptedValue, collectFallbackTenantIds, defaultTenantIdsFor, entityMetadataList, rotationTotals, countValuesByKeyId, isEncryptedValue, type ReencryptOptions, type RotationOutcome, type RotationTableReport, type SqlExecute, type EntityMetadataLike } from './keyRotation';
9
10
  export { setupTenantFilter, getSuperAdminContext, createTenantFilterDef, TENANT_FILTER_NAME } from './tenantFilter';
10
11
  export { setupRls, RlsEventSubscriber, type RlsConfig } from './rls';
11
12
  export type { AnyMikroORM, ResolvedEntity } from './mikroOrm.types';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/persistence/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,KAAK,eAAe,IAAI,mBAAmB,EAC3C,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EAExB,eAAe,EACf,KAAK,eAAe,IAAI,mBAAmB,EAC3C,KAAK,eAAe,EACpB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,yBAAyB,EAC9B,KAAK,+BAA+B,EACrC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,6BAA6B,EAC7B,KAAK,yBAAyB,EAC/B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,+BAA+B,EACrC,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAC;AAGjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAG5E,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,cAAc,EACd,yBAAyB,EACzB,eAAe,EACf,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAErE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/persistence/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,KAAK,eAAe,IAAI,mBAAmB,EAC3C,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EAExB,eAAe,EACf,KAAK,eAAe,IAAI,mBAAmB,EAC3C,KAAK,eAAe,EACpB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,KAAK,cAAc,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,yBAAyB,EAC9B,KAAK,+BAA+B,EACrC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,6BAA6B,EAC7B,KAAK,yBAAyB,EAC/B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,+BAA+B,EACrC,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAC;AAGjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAG5E,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,cAAc,EACd,yBAAyB,EACzB,eAAe,EACf,uBAAuB,EACvB,sBAAsB,EACtB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,0BAA0B,EAC1B,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACxB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAErE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}