@nodetool-ai/security 0.7.0-rc.23 → 0.8.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.
- package/README.md +42 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +17 -7
- package/dist/crypto.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/master-key.d.ts +19 -22
- package/dist/master-key.d.ts.map +1 -1
- package/dist/master-key.js +61 -73
- package/dist/master-key.js.map +1 -1
- package/package.json +25 -7
- package/dist/startup-checks.d.ts +0 -12
- package/dist/startup-checks.d.ts.map +0 -1
- package/dist/startup-checks.js +0 -45
- package/dist/startup-checks.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @nodetool-ai/security
|
|
2
|
+
|
|
3
|
+
Secret storage and encryption for [NodeTool](https://nodetool.ai) — master-key management and crypto helpers.
|
|
4
|
+
|
|
5
|
+
This package owns encryption at rest for the NodeTool backend. It derives and stores a master key (OS keychain via keytar or environment variable) and encrypts and decrypts secrets, including Fernet-compatible payloads.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @nodetool-ai/security
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Exported symbols
|
|
14
|
+
|
|
15
|
+
| Symbol | Kind | Description |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `generateMasterKey` | function | Generate a new random master key |
|
|
18
|
+
| `deriveKey` | function | Derive an encryption key from a passphrase |
|
|
19
|
+
| `encrypt` / `decrypt` | function | Encrypt and decrypt payloads with the master key |
|
|
20
|
+
| `encryptFernet` / `decryptFernet` | function | Fernet-compatible encryption for cross-runtime secrets |
|
|
21
|
+
| `isValidMasterKey` | function | Validate a master-key string |
|
|
22
|
+
| `getMasterKey` / `initMasterKey` | function | Read or initialize the active master key |
|
|
23
|
+
| `setMasterKey` / `setMasterKeyPersistent` / `deleteMasterKey` | function | Set (optionally persist to keychain) or delete the master key |
|
|
24
|
+
| `clearMasterKeyCache` | function | Clear the in-memory key cache |
|
|
25
|
+
| `isUsingEnvKey` | function | Report whether the env var supplies the key |
|
|
26
|
+
| `setKeytarLoader` / `resetKeytarLoader` | function | Override the keytar loader (for tests) |
|
|
27
|
+
| `KeychainAccessError` | class | Error thrown when the OS keychain is unreachable |
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { initMasterKey, encrypt, decrypt } from "@nodetool-ai/security";
|
|
33
|
+
|
|
34
|
+
await initMasterKey();
|
|
35
|
+
const sealed = encrypt("sk-secret-value");
|
|
36
|
+
const plain = decrypt(sealed);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Links
|
|
40
|
+
|
|
41
|
+
- [NodeTool](https://nodetool.ai)
|
|
42
|
+
- [GitHub](https://github.com/nodetool-ai/nodetool)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2026-09-28T09:19:03.160Z
|
package/dist/crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuBH;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAInE;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAeR;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,MAAM,CA+BR;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,MAAM,CAoDR;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAiDR;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,EAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAOT"}
|
package/dist/crypto.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { randomBytes, pbkdf2Sync, createCipheriv, createDecipheriv, createHmac, timingSafeEqual } from "node:crypto";
|
|
11
11
|
import { createLogger } from "@nodetool-ai/config";
|
|
12
|
+
// Stryker disable next-line StringLiteral: logger name is diagnostic, not behavior
|
|
12
13
|
const log = createLogger("nodetool.security.crypto");
|
|
13
14
|
// Fernet token version byte
|
|
14
15
|
const FERNET_VERSION = 0x80;
|
|
@@ -35,6 +36,7 @@ export function generateMasterKey() {
|
|
|
35
36
|
* @returns A 32-byte derived key as a Buffer.
|
|
36
37
|
*/
|
|
37
38
|
export function deriveKey(masterKey, userId) {
|
|
39
|
+
// Stryker disable next-line StringLiteral: encoding arg — Node decodes "" as utf-8, so this mutant is behaviorally equivalent
|
|
38
40
|
const salt = Buffer.from(userId, "utf-8");
|
|
39
41
|
return pbkdf2Sync(masterKey, salt, PBKDF2_ITERATIONS, KEY_LENGTH, "sha256");
|
|
40
42
|
}
|
|
@@ -53,6 +55,7 @@ export function encrypt(masterKey, userId, plaintext) {
|
|
|
53
55
|
const iv = randomBytes(IV_LENGTH);
|
|
54
56
|
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
55
57
|
const encrypted = Buffer.concat([
|
|
58
|
+
// Stryker disable next-line StringLiteral: encoding arg — Node decodes "" as utf-8, so this mutant is behaviorally equivalent
|
|
56
59
|
cipher.update(plaintext, "utf-8"),
|
|
57
60
|
cipher.final()
|
|
58
61
|
]);
|
|
@@ -89,6 +92,7 @@ export function decrypt(masterKey, userId, encryptedValue) {
|
|
|
89
92
|
return decrypted.toString("utf-8");
|
|
90
93
|
}
|
|
91
94
|
catch (err) {
|
|
95
|
+
// Stryker disable next-line all: diagnostic log, not behavior
|
|
92
96
|
log.debug("AES-GCM decryption failed (may fall back to Fernet)", {
|
|
93
97
|
error: String(err)
|
|
94
98
|
});
|
|
@@ -107,7 +111,9 @@ export function decrypt(masterKey, userId, encryptedValue) {
|
|
|
107
111
|
*/
|
|
108
112
|
export function decryptFernet(masterKey, userId, encryptedValue) {
|
|
109
113
|
// Python uses master_key.encode() — the UTF-8 bytes of the base64 string itself as PBKDF2 password
|
|
114
|
+
// Stryker disable next-line StringLiteral: encoding arg — Node decodes "" as utf-8, so this mutant is behaviorally equivalent
|
|
110
115
|
const masterKeyBytes = Buffer.from(masterKey, "utf-8");
|
|
116
|
+
// Stryker disable next-line StringLiteral: encoding arg — Node decodes "" as utf-8, so this mutant is behaviorally equivalent
|
|
111
117
|
const salt = Buffer.from(userId, "utf-8");
|
|
112
118
|
const derived = pbkdf2Sync(masterKeyBytes, salt, PBKDF2_ITERATIONS, 32, "sha256");
|
|
113
119
|
// Fernet splits the 32-byte derived key: first 16 = HMAC key, last 16 = AES-128 key
|
|
@@ -115,7 +121,9 @@ export function decryptFernet(masterKey, userId, encryptedValue) {
|
|
|
115
121
|
const aesKey = derived.subarray(16, 32);
|
|
116
122
|
// Decode Fernet token from base64url
|
|
117
123
|
const b64token = encryptedValue.replace(/-/g, "+").replace(/_/g, "/");
|
|
118
|
-
const token = Buffer.from(
|
|
124
|
+
const token = Buffer.from(
|
|
125
|
+
// Stryker disable next-line StringLiteral,ArithmeticOperator: re-padding is a no-op — Node's base64 decoder ignores +/- padding, so these mutants are equivalent
|
|
126
|
+
b64token + "=".repeat((4 - (b64token.length % 4)) % 4), "base64");
|
|
119
127
|
// Token layout: version(1) + timestamp(8) + iv(16) + ciphertext(N) + hmac(32)
|
|
120
128
|
if (token.length < 1 + 8 + 16 + 32) {
|
|
121
129
|
throw new Error("Invalid Fernet token: too short");
|
|
@@ -151,7 +159,9 @@ export function decryptFernet(masterKey, userId, encryptedValue) {
|
|
|
151
159
|
* @param plaintext - The plaintext to encrypt.
|
|
152
160
|
*/
|
|
153
161
|
export function encryptFernet(masterKey, userId, plaintext) {
|
|
162
|
+
// Stryker disable next-line StringLiteral: encoding arg — Node decodes "" as utf-8, so this mutant is behaviorally equivalent
|
|
154
163
|
const masterKeyBytes = Buffer.from(masterKey, "utf-8");
|
|
164
|
+
// Stryker disable next-line StringLiteral: encoding arg — Node decodes "" as utf-8, so this mutant is behaviorally equivalent
|
|
155
165
|
const salt = Buffer.from(userId, "utf-8");
|
|
156
166
|
const derived = pbkdf2Sync(masterKeyBytes, salt, PBKDF2_ITERATIONS, 32, "sha256");
|
|
157
167
|
const hmacKey = derived.subarray(0, 16);
|
|
@@ -162,6 +172,7 @@ export function encryptFernet(masterKey, userId, plaintext) {
|
|
|
162
172
|
const tsBuf = Buffer.alloc(8);
|
|
163
173
|
tsBuf.writeBigUInt64BE(timestamp);
|
|
164
174
|
// Pad plaintext to 16-byte boundary (PKCS7)
|
|
175
|
+
// Stryker disable next-line StringLiteral: encoding arg — Node decodes "" as utf-8, so this mutant is behaviorally equivalent
|
|
165
176
|
const plaintextBuf = Buffer.from(plaintext, "utf-8");
|
|
166
177
|
const padLen = 16 - (plaintextBuf.length % 16);
|
|
167
178
|
const padded = Buffer.concat([plaintextBuf, Buffer.alloc(padLen, padLen)]);
|
|
@@ -178,12 +189,11 @@ export function encryptFernet(masterKey, userId, plaintext) {
|
|
|
178
189
|
// HMAC-SHA256 over body
|
|
179
190
|
const hmac = createHmac("sha256", hmacKey).update(body).digest();
|
|
180
191
|
const token = Buffer.concat([body, hmac]);
|
|
181
|
-
// Encode as base64url
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
.replace(/=/g, "");
|
|
192
|
+
// Encode as base64url *with* padding. Python's cryptography.Fernet decodes
|
|
193
|
+
// tokens with base64.urlsafe_b64decode, which rejects unpadded input
|
|
194
|
+
// ("Incorrect padding" -> InvalidToken), so the "=" padding must be kept for
|
|
195
|
+
// cross-runtime compatibility.
|
|
196
|
+
return token.toString("base64").replace(/\+/g, "-").replace(/\//g, "_");
|
|
187
197
|
}
|
|
188
198
|
/**
|
|
189
199
|
* Check if a master key is valid by attempting to decrypt a test value.
|
package/dist/crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
export { generateMasterKey, deriveKey, encrypt, decrypt, decryptFernet, encryptFernet, isValidMasterKey } from "./crypto.js";
|
|
2
|
-
export { getMasterKey, initMasterKey, clearMasterKeyCache, setMasterKey, setMasterKeyPersistent, deleteMasterKey, isUsingEnvKey,
|
|
3
|
-
export { runStartupChecks, type StartupCheckResult } from "./startup-checks.js";
|
|
2
|
+
export { getMasterKey, initMasterKey, clearMasterKeyCache, setMasterKey, setMasterKeyPersistent, deleteMasterKey, isUsingEnvKey, setKeytarLoader, resetKeytarLoader, KeychainAccessError } from "./master-key.js";
|
|
4
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
export { generateMasterKey, deriveKey, encrypt, decrypt, decryptFernet, encryptFernet, isValidMasterKey } from "./crypto.js";
|
|
2
|
-
export { getMasterKey, initMasterKey, clearMasterKeyCache, setMasterKey, setMasterKeyPersistent, deleteMasterKey, isUsingEnvKey,
|
|
3
|
-
export { runStartupChecks } from "./startup-checks.js";
|
|
2
|
+
export { getMasterKey, initMasterKey, clearMasterKeyCache, setMasterKey, setMasterKeyPersistent, deleteMasterKey, isUsingEnvKey, setKeytarLoader, resetKeytarLoader, KeychainAccessError } from "./master-key.js";
|
|
4
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,OAAO,EACP,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,YAAY,EACZ,sBAAsB,EACtB,eAAe,EACf,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC"}
|
package/dist/master-key.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Master key management with keychain
|
|
2
|
+
* Master key management with keychain support.
|
|
3
3
|
*
|
|
4
4
|
* This module manages the master encryption key for secrets, storing it securely
|
|
5
|
-
* in the system keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service)
|
|
6
|
-
* or AWS Secrets Manager.
|
|
5
|
+
* in the system keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service).
|
|
7
6
|
*
|
|
8
7
|
* Key sources (in order of precedence):
|
|
9
8
|
* 1. SECRETS_MASTER_KEY environment variable
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
12
|
-
* 4. Auto-generated key (persisted to keychain when available)
|
|
9
|
+
* 2. System keychain via keytar
|
|
10
|
+
* 3. Auto-generated key (persisted to keychain when available)
|
|
13
11
|
*
|
|
14
12
|
* NOTE on encryption compatibility: TS uses AES-256-GCM while Python uses Fernet.
|
|
15
13
|
* Secrets encrypted in one runtime cannot be decrypted in the other.
|
|
@@ -41,27 +39,32 @@ export declare function resetKeytarLoader(): void;
|
|
|
41
39
|
* Get the master encryption key (synchronous).
|
|
42
40
|
*
|
|
43
41
|
* Checks sources in order:
|
|
44
|
-
* 1. Cached key (
|
|
45
|
-
*
|
|
46
|
-
*
|
|
42
|
+
* 1. Cached key (set previously by initMasterKey, setMasterKey, or a prior
|
|
43
|
+
* getMasterKey hit on SECRETS_MASTER_KEY).
|
|
44
|
+
* 2. SECRETS_MASTER_KEY environment variable.
|
|
47
45
|
*
|
|
48
|
-
*
|
|
46
|
+
* Throws if neither is available. Callers MUST call {@link initMasterKey}
|
|
47
|
+
* once at process startup (which loads from keychain / env and
|
|
48
|
+
* persists a fresh key on first run) before the first sync access.
|
|
49
|
+
* Auto-generating an ephemeral key here would silently encrypt secrets
|
|
50
|
+
* with a value that disappears on exit — making them undecryptable on
|
|
51
|
+
* the next launch — so we surface the missing-init explicitly instead.
|
|
49
52
|
*
|
|
50
53
|
* @returns The master key as a base64-encoded string.
|
|
54
|
+
* @throws If the key has not been initialized.
|
|
51
55
|
*/
|
|
52
56
|
export declare function getMasterKey(): string;
|
|
53
57
|
/**
|
|
54
58
|
* Initialize the master key from all available sources (async).
|
|
55
59
|
*
|
|
56
60
|
* Should be called once at application startup to resolve the master key
|
|
57
|
-
* from keychain
|
|
58
|
-
*
|
|
61
|
+
* from the keychain. After this call, getMasterKey() will return the
|
|
62
|
+
* resolved key synchronously.
|
|
59
63
|
*
|
|
60
64
|
* Resolution order:
|
|
61
65
|
* 1. SECRETS_MASTER_KEY environment variable
|
|
62
|
-
* 2.
|
|
63
|
-
* 3.
|
|
64
|
-
* 4. Auto-generate and persist to keychain
|
|
66
|
+
* 2. System keychain via keytar
|
|
67
|
+
* 3. Auto-generate and persist to keychain
|
|
65
68
|
*
|
|
66
69
|
* @returns The master key as a base64-encoded string.
|
|
67
70
|
*/
|
|
@@ -70,7 +73,7 @@ export declare function initMasterKey(): Promise<string>;
|
|
|
70
73
|
* Clear the cached master key.
|
|
71
74
|
*
|
|
72
75
|
* Forces the next call to getMasterKey() or initMasterKey() to
|
|
73
|
-
* re-read from environment
|
|
76
|
+
* re-read from environment or keychain.
|
|
74
77
|
*/
|
|
75
78
|
export declare function clearMasterKeyCache(): void;
|
|
76
79
|
/**
|
|
@@ -101,11 +104,5 @@ export declare function deleteMasterKey(): Promise<boolean>;
|
|
|
101
104
|
* @returns True if SECRETS_MASTER_KEY environment variable is set.
|
|
102
105
|
*/
|
|
103
106
|
export declare function isUsingEnvKey(): boolean;
|
|
104
|
-
/**
|
|
105
|
-
* Check if the master key should be sourced from AWS Secrets Manager.
|
|
106
|
-
*
|
|
107
|
-
* @returns True if AWS_SECRETS_MASTER_KEY_NAME environment variable is set.
|
|
108
|
-
*/
|
|
109
|
-
export declare function isUsingAwsKey(): boolean;
|
|
110
107
|
export {};
|
|
111
108
|
//# sourceMappingURL=master-key.d.ts.map
|
package/dist/master-key.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-key.d.ts","sourceRoot":"","sources":["../src/master-key.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"master-key.d.ts","sourceRoot":"","sources":["../src/master-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,uDAAuD;AACvD,UAAU,YAAY;IACpB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtE,WAAW,CACT,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpE;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAoCD;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,YAAY,GAAG,IAAI,CAG9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAmBrC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAmBrD;AA0DD;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7E;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAQxD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC"}
|
package/dist/master-key.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Master key management with keychain
|
|
2
|
+
* Master key management with keychain support.
|
|
3
3
|
*
|
|
4
4
|
* This module manages the master encryption key for secrets, storing it securely
|
|
5
|
-
* in the system keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service)
|
|
6
|
-
* or AWS Secrets Manager.
|
|
5
|
+
* in the system keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service).
|
|
7
6
|
*
|
|
8
7
|
* Key sources (in order of precedence):
|
|
9
8
|
* 1. SECRETS_MASTER_KEY environment variable
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
12
|
-
* 4. Auto-generated key (persisted to keychain when available)
|
|
9
|
+
* 2. System keychain via keytar
|
|
10
|
+
* 3. Auto-generated key (persisted to keychain when available)
|
|
13
11
|
*
|
|
14
12
|
* NOTE on encryption compatibility: TS uses AES-256-GCM while Python uses Fernet.
|
|
15
13
|
* Secrets encrypted in one runtime cannot be decrypted in the other.
|
|
16
14
|
* New secrets must be created via the appropriate runtime's endpoints.
|
|
17
15
|
*/
|
|
18
|
-
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
|
|
19
16
|
import { generateMasterKey } from "./crypto.js";
|
|
20
17
|
import { createLogger } from "@nodetool-ai/config";
|
|
18
|
+
// Stryker disable next-line StringLiteral: logger name is diagnostic, not behavior
|
|
21
19
|
const log = createLogger("nodetool.security.master-key");
|
|
22
20
|
const KEYRING_SERVICE = "nodetool";
|
|
23
21
|
const KEYRING_ACCOUNT = "secrets_master_key";
|
|
24
22
|
let cachedMasterKey = null;
|
|
23
|
+
/** In-flight resolution promise, used to de-duplicate concurrent first-run inits. */
|
|
24
|
+
let initInFlight = null;
|
|
25
25
|
/**
|
|
26
26
|
* Thrown when the system keychain cannot be accessed. Callers can detect this
|
|
27
27
|
* specifically (vs other startup failures) to decide whether re-prompting the
|
|
@@ -39,6 +39,7 @@ function keychainAccessError(message) {
|
|
|
39
39
|
/** Lazy-load keytar. Keychain failures are fatal: no generated fallback key. */
|
|
40
40
|
let _keytarResolved = null;
|
|
41
41
|
async function loadKeytar() {
|
|
42
|
+
// Stryker disable next-line ConditionalExpression,BlockStatement: cache fast-path — re-importing yields the same module, so this mutant is behaviorally equivalent
|
|
42
43
|
if (_keytarResolved) {
|
|
43
44
|
return _keytarResolved;
|
|
44
45
|
}
|
|
@@ -49,10 +50,11 @@ async function loadKeytar() {
|
|
|
49
50
|
}
|
|
50
51
|
catch (err) {
|
|
51
52
|
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
// Stryker disable all: diagnostic log, not behavior
|
|
52
54
|
log.error("keytar native module failed to load. For headless deployments " +
|
|
53
55
|
"(Docker, CI, Linux servers without libsecret) set the SECRETS_MASTER_KEY " +
|
|
54
|
-
"environment variable to a base64-encoded 32-byte key,
|
|
55
|
-
|
|
56
|
+
"environment variable to a base64-encoded 32-byte key.", { error: message });
|
|
57
|
+
// Stryker restore all
|
|
56
58
|
throw keychainAccessError(`Unable to load system keychain backend: ${message}`);
|
|
57
59
|
}
|
|
58
60
|
}
|
|
@@ -72,104 +74,97 @@ export function resetKeytarLoader() {
|
|
|
72
74
|
_keytar = null;
|
|
73
75
|
_keytarResolved = null;
|
|
74
76
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Retrieve master key from AWS Secrets Manager.
|
|
77
|
-
*
|
|
78
|
-
* Only attempted if AWS_SECRETS_MASTER_KEY_NAME environment variable is set.
|
|
79
|
-
*/
|
|
80
|
-
async function getFromAwsSecrets(secretName) {
|
|
81
|
-
try {
|
|
82
|
-
const region = process.env["AWS_REGION"] ?? "us-east-1";
|
|
83
|
-
const client = new SecretsManagerClient({ region });
|
|
84
|
-
const response = await client.send(new GetSecretValueCommand({ SecretId: secretName }));
|
|
85
|
-
if (response.SecretString) {
|
|
86
|
-
return response.SecretString;
|
|
87
|
-
}
|
|
88
|
-
if (response.SecretBinary) {
|
|
89
|
-
return Buffer.from(response.SecretBinary).toString("utf-8");
|
|
90
|
-
}
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
catch (err) {
|
|
94
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
95
|
-
log.warn("Master key source failed, trying next", {
|
|
96
|
-
source: "aws",
|
|
97
|
-
error: message
|
|
98
|
-
});
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
77
|
/**
|
|
103
78
|
* Get the master encryption key (synchronous).
|
|
104
79
|
*
|
|
105
80
|
* Checks sources in order:
|
|
106
|
-
* 1. Cached key (
|
|
107
|
-
*
|
|
108
|
-
*
|
|
81
|
+
* 1. Cached key (set previously by initMasterKey, setMasterKey, or a prior
|
|
82
|
+
* getMasterKey hit on SECRETS_MASTER_KEY).
|
|
83
|
+
* 2. SECRETS_MASTER_KEY environment variable.
|
|
109
84
|
*
|
|
110
|
-
*
|
|
85
|
+
* Throws if neither is available. Callers MUST call {@link initMasterKey}
|
|
86
|
+
* once at process startup (which loads from keychain / env and
|
|
87
|
+
* persists a fresh key on first run) before the first sync access.
|
|
88
|
+
* Auto-generating an ephemeral key here would silently encrypt secrets
|
|
89
|
+
* with a value that disappears on exit — making them undecryptable on
|
|
90
|
+
* the next launch — so we surface the missing-init explicitly instead.
|
|
111
91
|
*
|
|
112
92
|
* @returns The master key as a base64-encoded string.
|
|
93
|
+
* @throws If the key has not been initialized.
|
|
113
94
|
*/
|
|
114
95
|
export function getMasterKey() {
|
|
115
96
|
if (cachedMasterKey !== null) {
|
|
116
97
|
return cachedMasterKey;
|
|
117
98
|
}
|
|
118
|
-
// 1. Check environment variable
|
|
119
99
|
const envKey = process.env["SECRETS_MASTER_KEY"];
|
|
120
100
|
if (envKey) {
|
|
101
|
+
// Stryker disable next-line all: diagnostic log, not behavior
|
|
121
102
|
log.debug("Master key source", { source: "env" });
|
|
122
103
|
cachedMasterKey = envKey;
|
|
123
104
|
return envKey;
|
|
124
105
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return newKey;
|
|
106
|
+
throw new Error("Master key is not initialized. Call `initMasterKey()` once at startup " +
|
|
107
|
+
"(loads from system keychain / SECRETS_MASTER_KEY) " +
|
|
108
|
+
"before any synchronous secret access. Auto-generating a key here would " +
|
|
109
|
+
"silently encrypt secrets with a value that disappears on process exit.");
|
|
130
110
|
}
|
|
131
111
|
/**
|
|
132
112
|
* Initialize the master key from all available sources (async).
|
|
133
113
|
*
|
|
134
114
|
* Should be called once at application startup to resolve the master key
|
|
135
|
-
* from keychain
|
|
136
|
-
*
|
|
115
|
+
* from the keychain. After this call, getMasterKey() will return the
|
|
116
|
+
* resolved key synchronously.
|
|
137
117
|
*
|
|
138
118
|
* Resolution order:
|
|
139
119
|
* 1. SECRETS_MASTER_KEY environment variable
|
|
140
|
-
* 2.
|
|
141
|
-
* 3.
|
|
142
|
-
* 4. Auto-generate and persist to keychain
|
|
120
|
+
* 2. System keychain via keytar
|
|
121
|
+
* 3. Auto-generate and persist to keychain
|
|
143
122
|
*
|
|
144
123
|
* @returns The master key as a base64-encoded string.
|
|
145
124
|
*/
|
|
146
125
|
export async function initMasterKey() {
|
|
147
|
-
// Return cached key if available
|
|
148
126
|
if (cachedMasterKey !== null) {
|
|
149
127
|
return cachedMasterKey;
|
|
150
128
|
}
|
|
129
|
+
// Single-flight: concurrent first-run callers share one resolution. Without
|
|
130
|
+
// this, each would independently generate a *different* key and race to
|
|
131
|
+
// persist it, leaving the cache and keychain inconsistent and orphaning any
|
|
132
|
+
// secrets encrypted under the losing key.
|
|
133
|
+
if (initInFlight !== null) {
|
|
134
|
+
return initInFlight;
|
|
135
|
+
}
|
|
136
|
+
initInFlight = resolveMasterKey();
|
|
137
|
+
try {
|
|
138
|
+
return await initInFlight;
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
initInFlight = null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Resolve the master key from all sources. See {@link initMasterKey}. */
|
|
145
|
+
async function resolveMasterKey() {
|
|
151
146
|
// 1. Check environment variable
|
|
152
147
|
const envKey = process.env["SECRETS_MASTER_KEY"];
|
|
153
148
|
if (envKey) {
|
|
149
|
+
// Stryker disable next-line all: diagnostic log, not behavior
|
|
154
150
|
log.debug("Master key source", { source: "env" });
|
|
155
151
|
cachedMasterKey = envKey;
|
|
156
152
|
return envKey;
|
|
157
153
|
}
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return awsKey;
|
|
166
|
-
}
|
|
154
|
+
// AWS Secrets Manager support was removed. Fail fast instead of silently
|
|
155
|
+
// ignoring the variable: falling through to a generated key would orphan
|
|
156
|
+
// every secret encrypted under the AWS-sourced key.
|
|
157
|
+
if (process.env["AWS_SECRETS_MASTER_KEY_NAME"]) {
|
|
158
|
+
throw new Error("AWS_SECRETS_MASTER_KEY_NAME is set, but AWS Secrets Manager support " +
|
|
159
|
+
"has been removed. Set SECRETS_MASTER_KEY to the key value that was " +
|
|
160
|
+
"stored in AWS Secrets Manager, then unset AWS_SECRETS_MASTER_KEY_NAME.");
|
|
167
161
|
}
|
|
168
|
-
//
|
|
169
|
-
const keytar = _keytar ?? await loadKeytar();
|
|
162
|
+
// 2. Try system keychain via keytar
|
|
163
|
+
const keytar = _keytar ?? (await loadKeytar());
|
|
170
164
|
try {
|
|
171
165
|
const storedKey = await keytar.getPassword(KEYRING_SERVICE, KEYRING_ACCOUNT);
|
|
172
166
|
if (storedKey) {
|
|
167
|
+
// Stryker disable next-line all: diagnostic log, not behavior
|
|
173
168
|
log.debug("Master key source", { source: "keychain" });
|
|
174
169
|
cachedMasterKey = storedKey;
|
|
175
170
|
return storedKey;
|
|
@@ -179,12 +174,13 @@ export async function initMasterKey() {
|
|
|
179
174
|
const message = err instanceof Error ? err.message : String(err);
|
|
180
175
|
throw keychainAccessError(`Unable to read master key from system keychain: ${message}`);
|
|
181
176
|
}
|
|
182
|
-
//
|
|
177
|
+
// 3. Auto-generate and persist to keychain. Persisting is mandatory; using
|
|
183
178
|
// an unpersisted generated key would make encrypted secrets unrecoverable on
|
|
184
179
|
// the next launch.
|
|
185
180
|
const newKey = generateMasterKey();
|
|
186
181
|
try {
|
|
187
182
|
await keytar.setPassword(KEYRING_SERVICE, KEYRING_ACCOUNT, newKey);
|
|
183
|
+
// Stryker disable next-line all: diagnostic log, not behavior
|
|
188
184
|
log.info("Master key generated and stored");
|
|
189
185
|
}
|
|
190
186
|
catch (err) {
|
|
@@ -198,7 +194,7 @@ export async function initMasterKey() {
|
|
|
198
194
|
* Clear the cached master key.
|
|
199
195
|
*
|
|
200
196
|
* Forces the next call to getMasterKey() or initMasterKey() to
|
|
201
|
-
* re-read from environment
|
|
197
|
+
* re-read from environment or keychain.
|
|
202
198
|
*/
|
|
203
199
|
export function clearMasterKeyCache() {
|
|
204
200
|
cachedMasterKey = null;
|
|
@@ -244,12 +240,4 @@ export async function deleteMasterKey() {
|
|
|
244
240
|
export function isUsingEnvKey() {
|
|
245
241
|
return process.env["SECRETS_MASTER_KEY"] !== undefined;
|
|
246
242
|
}
|
|
247
|
-
/**
|
|
248
|
-
* Check if the master key should be sourced from AWS Secrets Manager.
|
|
249
|
-
*
|
|
250
|
-
* @returns True if AWS_SECRETS_MASTER_KEY_NAME environment variable is set.
|
|
251
|
-
*/
|
|
252
|
-
export function isUsingAwsKey() {
|
|
253
|
-
return process.env["AWS_SECRETS_MASTER_KEY_NAME"] !== undefined;
|
|
254
|
-
}
|
|
255
243
|
//# sourceMappingURL=master-key.js.map
|
package/dist/master-key.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"master-key.js","sourceRoot":"","sources":["../src/master-key.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"master-key.js","sourceRoot":"","sources":["../src/master-key.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodetool-ai/security",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=22.0.0"
|
|
7
|
+
},
|
|
5
8
|
"main": "dist/index.js",
|
|
6
9
|
"types": "dist/index.d.ts",
|
|
7
10
|
"scripts": {
|
|
8
11
|
"build": "node ../../scripts/build-typescript-workspace.mjs",
|
|
9
|
-
"test": "vitest run",
|
|
10
|
-
"
|
|
12
|
+
"test": "node ../../scripts/run-vitest.mjs run",
|
|
13
|
+
"test:mutation": "stryker run",
|
|
14
|
+
"lint": "node ../../scripts/run-tsc.mjs --noEmit"
|
|
11
15
|
},
|
|
12
16
|
"dependencies": {
|
|
13
|
-
"@nodetool-ai/config": "^0.
|
|
14
|
-
"@aws-sdk/client-secrets-manager": "^3.1029.0",
|
|
17
|
+
"@nodetool-ai/config": "^0.8.1",
|
|
15
18
|
"keytar": "^7.9.0"
|
|
16
19
|
},
|
|
17
20
|
"devDependencies": {
|
|
18
|
-
"
|
|
19
|
-
"
|
|
21
|
+
"@stryker-mutator/core": "^9.6.1",
|
|
22
|
+
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
23
|
+
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
24
|
+
"vitest": "^5.0.1"
|
|
20
25
|
},
|
|
21
26
|
"exports": {
|
|
22
27
|
".": {
|
|
@@ -42,5 +47,18 @@
|
|
|
42
47
|
"files": [
|
|
43
48
|
"dist",
|
|
44
49
|
"README.md"
|
|
50
|
+
],
|
|
51
|
+
"description": "Secret storage and encryption for NodeTool — master-key management, crypto helpers, and startup security checks",
|
|
52
|
+
"keywords": [
|
|
53
|
+
"nodetool",
|
|
54
|
+
"ai",
|
|
55
|
+
"workflow",
|
|
56
|
+
"workflow-automation",
|
|
57
|
+
"typescript",
|
|
58
|
+
"encryption",
|
|
59
|
+
"secrets",
|
|
60
|
+
"secret-storage",
|
|
61
|
+
"crypto",
|
|
62
|
+
"security"
|
|
45
63
|
]
|
|
46
64
|
}
|
package/dist/startup-checks.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export interface StartupCheckResult {
|
|
2
|
-
errors: string[];
|
|
3
|
-
warnings: string[];
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Run startup health checks.
|
|
7
|
-
*
|
|
8
|
-
* - Checks that the master encryption key is loadable.
|
|
9
|
-
* - Warns about missing optional API keys.
|
|
10
|
-
*/
|
|
11
|
-
export declare function runStartupChecks(): Promise<StartupCheckResult>;
|
|
12
|
-
//# sourceMappingURL=startup-checks.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"startup-checks.d.ts","sourceRoot":"","sources":["../src/startup-checks.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAaD;;;;;GAKG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAyBpE"}
|
package/dist/startup-checks.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Startup checks — T-SEC-8.
|
|
3
|
-
*
|
|
4
|
-
* Validates that the system is properly configured before accepting requests.
|
|
5
|
-
*/
|
|
6
|
-
import { getMasterKey } from "./master-key.js";
|
|
7
|
-
/** Well-known optional API keys that should be configured for full functionality. */
|
|
8
|
-
const OPTIONAL_API_KEYS = [
|
|
9
|
-
"OPENAI_API_KEY",
|
|
10
|
-
"ANTHROPIC_API_KEY",
|
|
11
|
-
"GEMINI_API_KEY",
|
|
12
|
-
"REPLICATE_API_TOKEN",
|
|
13
|
-
"HF_TOKEN",
|
|
14
|
-
"ELEVENLABS_API_KEY",
|
|
15
|
-
"FAL_API_KEY"
|
|
16
|
-
];
|
|
17
|
-
/**
|
|
18
|
-
* Run startup health checks.
|
|
19
|
-
*
|
|
20
|
-
* - Checks that the master encryption key is loadable.
|
|
21
|
-
* - Warns about missing optional API keys.
|
|
22
|
-
*/
|
|
23
|
-
export async function runStartupChecks() {
|
|
24
|
-
const errors = [];
|
|
25
|
-
const warnings = [];
|
|
26
|
-
// Check master key
|
|
27
|
-
try {
|
|
28
|
-
const key = getMasterKey();
|
|
29
|
-
if (!key) {
|
|
30
|
-
errors.push("Master encryption key could not be loaded");
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
35
|
-
errors.push(`Master key initialization failed: ${msg}`);
|
|
36
|
-
}
|
|
37
|
-
// Check optional API keys
|
|
38
|
-
for (const envVar of OPTIONAL_API_KEYS) {
|
|
39
|
-
if (!process.env[envVar]) {
|
|
40
|
-
warnings.push(`${envVar} is not set — related features will be unavailable`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return { errors, warnings };
|
|
44
|
-
}
|
|
45
|
-
//# sourceMappingURL=startup-checks.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"startup-checks.js","sourceRoot":"","sources":["../src/startup-checks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAO/C,qFAAqF;AACrF,MAAM,iBAAiB,GAAG;IACxB,gBAAgB;IAChB,mBAAmB;IACnB,gBAAgB;IAChB,qBAAqB;IACrB,UAAU;IACV,oBAAoB;IACpB,aAAa;CACd,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,mBAAmB;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,0BAA0B;IAC1B,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;QACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CACX,GAAG,MAAM,oDAAoD,CAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC"}
|