@elizaos/vault 2.0.0-alpha.537
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 +159 -0
- package/dist/audit.d.ts +14 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +27 -0
- package/dist/audit.js.map +1 -0
- package/dist/credentials.d.ts +58 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +157 -0
- package/dist/credentials.js.map +1 -0
- package/dist/crypto.d.ts +18 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +67 -0
- package/dist/crypto.js.map +1 -0
- package/dist/external-credentials.d.ts +62 -0
- package/dist/external-credentials.d.ts.map +1 -0
- package/dist/external-credentials.js +335 -0
- package/dist/external-credentials.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +70 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +163 -0
- package/dist/install.js.map +1 -0
- package/dist/inventory.d.ts +140 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +319 -0
- package/dist/inventory.js.map +1 -0
- package/dist/manager.d.ts +161 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +466 -0
- package/dist/manager.js.map +1 -0
- package/dist/master-key.d.ts +86 -0
- package/dist/master-key.d.ts.map +1 -0
- package/dist/master-key.js +247 -0
- package/dist/master-key.js.map +1 -0
- package/dist/password-managers.d.ts +17 -0
- package/dist/password-managers.d.ts.map +1 -0
- package/dist/password-managers.js +59 -0
- package/dist/password-managers.js.map +1 -0
- package/dist/profiles.d.ts +68 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +189 -0
- package/dist/profiles.js.map +1 -0
- package/dist/store.d.ts +22 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +137 -0
- package/dist/store.js.map +1 -0
- package/dist/testing.d.ts +32 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +70 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/vault.d.ts +77 -0
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +269 -0
- package/dist/vault.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the encryption master key lives.
|
|
3
|
+
*
|
|
4
|
+
* Resolvers, ordered by preference for `defaultMasterKey()`:
|
|
5
|
+
*
|
|
6
|
+
* 1. **OS keychain** — cross-platform via @napi-rs/keyring (macOS
|
|
7
|
+
* Keychain, Windows Credential Manager, Linux Secret Service /
|
|
8
|
+
* libsecret). The default on machines with a desktop session.
|
|
9
|
+
* 2. **Passphrase** — scrypt-derived 32-byte key from `ELIZA_VAULT_PASSPHRASE`
|
|
10
|
+
* with a per-service salt. Use this on headless Linux servers, in
|
|
11
|
+
* Docker containers, or in CI where the OS keychain isn't reachable.
|
|
12
|
+
* Operator opts in by setting the env var; we never derive from a
|
|
13
|
+
* hard-coded fallback.
|
|
14
|
+
* 3. **In-memory** — `inMemoryMasterKey(buffer)`. Tests only.
|
|
15
|
+
*
|
|
16
|
+
* `defaultMasterKey()` walks 1 → 2 and throws a single
|
|
17
|
+
* `MasterKeyUnavailableError` with both paths' diagnostic messages when
|
|
18
|
+
* neither is available. Operators see a single line that names every
|
|
19
|
+
* remediation option.
|
|
20
|
+
*/
|
|
21
|
+
export interface MasterKeyResolver {
|
|
22
|
+
load(): Promise<Buffer>;
|
|
23
|
+
describe(): string;
|
|
24
|
+
}
|
|
25
|
+
export declare class MasterKeyUnavailableError extends Error {
|
|
26
|
+
constructor(message: string);
|
|
27
|
+
}
|
|
28
|
+
export declare function inMemoryMasterKey(key: Buffer): MasterKeyResolver;
|
|
29
|
+
export interface OsKeychainOptions {
|
|
30
|
+
/** Service name shown in the OS keychain UI. Default: "eliza". */
|
|
31
|
+
readonly service?: string;
|
|
32
|
+
/** Account/account name within the service. Default: "vault.masterKey". */
|
|
33
|
+
readonly account?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface PassphraseOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Passphrase string. Typically read from `process.env.ELIZA_VAULT_PASSPHRASE`.
|
|
38
|
+
* Must be at least 12 characters; shorter passphrases are rejected to
|
|
39
|
+
* push operators away from trivially-brute-forceable keys.
|
|
40
|
+
*/
|
|
41
|
+
readonly passphrase: string;
|
|
42
|
+
/**
|
|
43
|
+
* Salt for the scrypt KDF. Default: derived from the service identifier
|
|
44
|
+
* so two distinct services on the same host with the same passphrase
|
|
45
|
+
* still produce different keys. Override only if you know what you're
|
|
46
|
+
* doing — changing the salt invalidates every value already in the
|
|
47
|
+
* vault.
|
|
48
|
+
*/
|
|
49
|
+
readonly salt?: string;
|
|
50
|
+
/**
|
|
51
|
+
* scrypt cost. Default 2^15 = 32_768 — same order of magnitude as 1Password's
|
|
52
|
+
* recommendation for a master password derivation, comfortably below the
|
|
53
|
+
* default 64MB memory cap on Node's scrypt. Override for tests if needed.
|
|
54
|
+
*/
|
|
55
|
+
readonly cost?: number;
|
|
56
|
+
/** Service identifier used as the default salt prefix. Default `"eliza"`. */
|
|
57
|
+
readonly service?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Master key derived from a passphrase via scrypt. Use this when no OS
|
|
61
|
+
* keychain is available — typically headless Linux servers or containers.
|
|
62
|
+
*
|
|
63
|
+
* The same passphrase + salt + cost always produces the same key, so
|
|
64
|
+
* operators MUST keep their passphrase stable across restarts (otherwise
|
|
65
|
+
* existing ciphertext can no longer be decrypted).
|
|
66
|
+
*/
|
|
67
|
+
export declare function passphraseMasterKey(opts: PassphraseOptions): MasterKeyResolver;
|
|
68
|
+
/**
|
|
69
|
+
* Construct a passphrase resolver from `ELIZA_VAULT_PASSPHRASE` env. Returns
|
|
70
|
+
* `null` when the env var is absent or empty so callers can fall through
|
|
71
|
+
* to the next strategy without a try/catch dance.
|
|
72
|
+
*/
|
|
73
|
+
export declare function passphraseMasterKeyFromEnv(service?: string): MasterKeyResolver | null;
|
|
74
|
+
/**
|
|
75
|
+
* Default resolver: try the OS keychain first, then a passphrase-derived
|
|
76
|
+
* key from `ELIZA_VAULT_PASSPHRASE`. If both fail, throws a single
|
|
77
|
+
* `MasterKeyUnavailableError` whose message lists every remediation
|
|
78
|
+
* option so operators on a fresh headless box see one actionable line.
|
|
79
|
+
*
|
|
80
|
+
* Tests should NOT use this — pass `inMemoryMasterKey(...)` to
|
|
81
|
+
* `createVault()` directly. Production paths that already inject a
|
|
82
|
+
* resolver are unaffected.
|
|
83
|
+
*/
|
|
84
|
+
export declare function defaultMasterKey(opts?: OsKeychainOptions): MasterKeyResolver;
|
|
85
|
+
export declare function osKeychainMasterKey(opts?: OsKeychainOptions): MasterKeyResolver;
|
|
86
|
+
//# sourceMappingURL=master-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"master-key.d.ts","sourceRoot":"","sources":["../src/master-key.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAchE;AAED,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAOD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,iBAAiB,GACtB,iBAAiB,CAgDnB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,CAAC,EAAE,MAAM,GACf,iBAAiB,GAAG,IAAI,CAO1B;AAyCD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,GAAE,iBAAsB,GAC3B,iBAAiB,CA0DnB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,GAAE,iBAAsB,GAC3B,iBAAiB,CAqEnB"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { scryptSync } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { generateMasterKey, KEY_BYTES } from "./crypto.js";
|
|
5
|
+
export class MasterKeyUnavailableError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "MasterKeyUnavailableError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function inMemoryMasterKey(key) {
|
|
12
|
+
if (key.length !== KEY_BYTES) {
|
|
13
|
+
throw new MasterKeyUnavailableError(`inMemoryMasterKey: expected ${KEY_BYTES} bytes, got ${key.length}`);
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
async load() {
|
|
17
|
+
return key;
|
|
18
|
+
},
|
|
19
|
+
describe() {
|
|
20
|
+
return "inMemory";
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const PASSPHRASE_MIN_LENGTH = 12;
|
|
25
|
+
const DEFAULT_SCRYPT_COST = 1 << 15;
|
|
26
|
+
const DEFAULT_SCRYPT_BLOCK_SIZE = 8;
|
|
27
|
+
const DEFAULT_SCRYPT_PARALLELIZATION = 1;
|
|
28
|
+
/**
|
|
29
|
+
* Master key derived from a passphrase via scrypt. Use this when no OS
|
|
30
|
+
* keychain is available — typically headless Linux servers or containers.
|
|
31
|
+
*
|
|
32
|
+
* The same passphrase + salt + cost always produces the same key, so
|
|
33
|
+
* operators MUST keep their passphrase stable across restarts (otherwise
|
|
34
|
+
* existing ciphertext can no longer be decrypted).
|
|
35
|
+
*/
|
|
36
|
+
export function passphraseMasterKey(opts) {
|
|
37
|
+
if (typeof opts.passphrase !== "string") {
|
|
38
|
+
throw new MasterKeyUnavailableError("passphraseMasterKey: passphrase must be a string");
|
|
39
|
+
}
|
|
40
|
+
if (opts.passphrase.length < PASSPHRASE_MIN_LENGTH) {
|
|
41
|
+
throw new MasterKeyUnavailableError(`passphraseMasterKey: passphrase must be at least ${PASSPHRASE_MIN_LENGTH} characters`);
|
|
42
|
+
}
|
|
43
|
+
const service = opts.service ?? "eliza";
|
|
44
|
+
const salt = opts.salt ?? `${service}.vault.masterKey.v1`;
|
|
45
|
+
const cost = opts.cost ?? DEFAULT_SCRYPT_COST;
|
|
46
|
+
return {
|
|
47
|
+
async load() {
|
|
48
|
+
// scryptSync is intentional: this runs once per process at vault
|
|
49
|
+
// construction. Using the async variant adds noise without
|
|
50
|
+
// measurable benefit on a one-shot derivation.
|
|
51
|
+
try {
|
|
52
|
+
// N=32_768 r=8 needs ~32MB, exactly Node's default `maxmem` cap, which
|
|
53
|
+
// OpenSSL rejects with MEMORY_LIMIT_EXCEEDED. Raise the cap to 64MB so
|
|
54
|
+
// the default cost works on every platform.
|
|
55
|
+
const derived = scryptSync(opts.passphrase, salt, KEY_BYTES, {
|
|
56
|
+
N: cost,
|
|
57
|
+
r: DEFAULT_SCRYPT_BLOCK_SIZE,
|
|
58
|
+
p: DEFAULT_SCRYPT_PARALLELIZATION,
|
|
59
|
+
maxmem: 64 * 1024 * 1024,
|
|
60
|
+
});
|
|
61
|
+
if (derived.length !== KEY_BYTES) {
|
|
62
|
+
throw new MasterKeyUnavailableError(`passphraseMasterKey: scrypt returned ${derived.length} bytes, expected ${KEY_BYTES}`);
|
|
63
|
+
}
|
|
64
|
+
return derived;
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
if (err instanceof MasterKeyUnavailableError)
|
|
68
|
+
throw err;
|
|
69
|
+
throw new MasterKeyUnavailableError(`passphraseMasterKey: scrypt derivation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
describe() {
|
|
73
|
+
return `passphrase://${service}`;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Construct a passphrase resolver from `ELIZA_VAULT_PASSPHRASE` env. Returns
|
|
79
|
+
* `null` when the env var is absent or empty so callers can fall through
|
|
80
|
+
* to the next strategy without a try/catch dance.
|
|
81
|
+
*/
|
|
82
|
+
export function passphraseMasterKeyFromEnv(service) {
|
|
83
|
+
const raw = process.env.ELIZA_VAULT_PASSPHRASE;
|
|
84
|
+
if (!raw || raw.length === 0)
|
|
85
|
+
return null;
|
|
86
|
+
return passphraseMasterKey({
|
|
87
|
+
passphrase: raw,
|
|
88
|
+
...(service ? { service } : {}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Detects hosts where invoking `@napi-rs/keyring` is known to crash the
|
|
93
|
+
* process at the native level instead of throwing a catchable JS error:
|
|
94
|
+
*
|
|
95
|
+
* - explicit opt-out via `ELIZA_VAULT_DISABLE_KEYCHAIN=1`
|
|
96
|
+
* - headless Linux with no reachable D-Bus session (the libsecret
|
|
97
|
+
* backend aborts at the C level when it can't reach the Secret
|
|
98
|
+
* Service)
|
|
99
|
+
*
|
|
100
|
+
* D-Bus reachability on Linux is checked two ways:
|
|
101
|
+
*
|
|
102
|
+
* 1. `DBUS_SESSION_BUS_ADDRESS` env var — the classical signal,
|
|
103
|
+
* reliably set by desktop session startup and `dbus-launch`.
|
|
104
|
+
* 2. `$XDG_RUNTIME_DIR/bus` socket — modern systemd user sessions
|
|
105
|
+
* socket-activate D-Bus and don't always export the env var
|
|
106
|
+
* (notably SSH sessions without env forwarding, and Fedora /
|
|
107
|
+
* Arch / Ubuntu 22+ desktops). Treat the socket file's presence
|
|
108
|
+
* as equivalent to the env var.
|
|
109
|
+
*
|
|
110
|
+
* This is intentionally a heuristic: it never returns `false` (safe)
|
|
111
|
+
* for a host that would actually crash, and may return `false` (safe)
|
|
112
|
+
* for a host where the keychain ultimately fails with a regular JS
|
|
113
|
+
* error. That's the desired direction — we'd rather attempt the
|
|
114
|
+
* keychain and let the existing try/catch handle a JS-level failure
|
|
115
|
+
* than refuse on a host where it would have worked.
|
|
116
|
+
*/
|
|
117
|
+
function isKeychainUnsafe() {
|
|
118
|
+
if (process.env.ELIZA_VAULT_DISABLE_KEYCHAIN === "1")
|
|
119
|
+
return true;
|
|
120
|
+
if (process.platform !== "linux")
|
|
121
|
+
return false;
|
|
122
|
+
if (process.env.DBUS_SESSION_BUS_ADDRESS)
|
|
123
|
+
return false;
|
|
124
|
+
const xdgRuntime = process.env.XDG_RUNTIME_DIR;
|
|
125
|
+
if (xdgRuntime && existsSync(join(xdgRuntime, "bus")))
|
|
126
|
+
return false;
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
function keychainUnsafeMessage(prefix) {
|
|
130
|
+
return `${prefix}OS keychain is unsafe on this host (headless Linux with no reachable D-Bus session, or ELIZA_VAULT_DISABLE_KEYCHAIN=1). Set ELIZA_VAULT_PASSPHRASE (≥${PASSPHRASE_MIN_LENGTH} chars) to enable a passphrase-derived master key, or pass an inMemoryMasterKey.`;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Default resolver: try the OS keychain first, then a passphrase-derived
|
|
134
|
+
* key from `ELIZA_VAULT_PASSPHRASE`. If both fail, throws a single
|
|
135
|
+
* `MasterKeyUnavailableError` whose message lists every remediation
|
|
136
|
+
* option so operators on a fresh headless box see one actionable line.
|
|
137
|
+
*
|
|
138
|
+
* Tests should NOT use this — pass `inMemoryMasterKey(...)` to
|
|
139
|
+
* `createVault()` directly. Production paths that already inject a
|
|
140
|
+
* resolver are unaffected.
|
|
141
|
+
*/
|
|
142
|
+
export function defaultMasterKey(opts = {}) {
|
|
143
|
+
const keychain = osKeychainMasterKey(opts);
|
|
144
|
+
return {
|
|
145
|
+
async load() {
|
|
146
|
+
// Skip the OS keychain on hosts where @napi-rs/keyring is known to
|
|
147
|
+
// segfault the process instead of throwing a catchable JS error.
|
|
148
|
+
// The defensive try/catch around keychain.load() can't help once
|
|
149
|
+
// the native crash fires.
|
|
150
|
+
if (isKeychainUnsafe()) {
|
|
151
|
+
const passphrase = passphraseMasterKeyFromEnv(opts.service);
|
|
152
|
+
if (passphrase)
|
|
153
|
+
return passphrase.load();
|
|
154
|
+
throw new MasterKeyUnavailableError(keychainUnsafeMessage("vault: "));
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
return await keychain.load();
|
|
158
|
+
}
|
|
159
|
+
catch (keychainErr) {
|
|
160
|
+
const passphrase = passphraseMasterKeyFromEnv(opts.service);
|
|
161
|
+
if (passphrase) {
|
|
162
|
+
try {
|
|
163
|
+
return await passphrase.load();
|
|
164
|
+
}
|
|
165
|
+
catch (passphraseErr) {
|
|
166
|
+
throw new MasterKeyUnavailableError(`vault master key unavailable. Keychain: ${keychainErr instanceof Error
|
|
167
|
+
? keychainErr.message
|
|
168
|
+
: String(keychainErr)}. Passphrase: ${passphraseErr instanceof Error
|
|
169
|
+
? passphraseErr.message
|
|
170
|
+
: String(passphraseErr)}.`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
throw new MasterKeyUnavailableError(`vault master key unavailable. ${keychainErr instanceof Error
|
|
174
|
+
? keychainErr.message
|
|
175
|
+
: String(keychainErr)} To use a passphrase-derived key on a headless host, set ELIZA_VAULT_PASSPHRASE (≥${PASSPHRASE_MIN_LENGTH} chars) and restart.`);
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
describe() {
|
|
179
|
+
// describe() reflects the runtime-selected path. On hosts where
|
|
180
|
+
// the keychain is bypassed, surfacing `keychain://...` would
|
|
181
|
+
// misrepresent which resolver actually ran.
|
|
182
|
+
const passphrase = passphraseMasterKeyFromEnv(opts.service);
|
|
183
|
+
if (isKeychainUnsafe()) {
|
|
184
|
+
return passphrase
|
|
185
|
+
? `${passphrase.describe()} (keychain bypassed: host unsafe)`
|
|
186
|
+
: `unavailable (keychain bypassed: host unsafe; no ELIZA_VAULT_PASSPHRASE set)`;
|
|
187
|
+
}
|
|
188
|
+
return passphrase
|
|
189
|
+
? `${keychain.describe()} (fallback: ${passphrase.describe()})`
|
|
190
|
+
: keychain.describe();
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
export function osKeychainMasterKey(opts = {}) {
|
|
195
|
+
const service = opts.service ?? "eliza";
|
|
196
|
+
const account = opts.account ?? "vault.masterKey";
|
|
197
|
+
return {
|
|
198
|
+
async load() {
|
|
199
|
+
// Refuse to invoke the native binding on hosts where it crashes
|
|
200
|
+
// the process. Direct callers of `osKeychainMasterKey` (plugins,
|
|
201
|
+
// integrations) get the same protection as `defaultMasterKey`.
|
|
202
|
+
if (isKeychainUnsafe()) {
|
|
203
|
+
throw new MasterKeyUnavailableError(keychainUnsafeMessage(`OS keychain (${service}/${account}): `));
|
|
204
|
+
}
|
|
205
|
+
let Entry;
|
|
206
|
+
try {
|
|
207
|
+
({ Entry } = await import("@napi-rs/keyring"));
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
throw new MasterKeyUnavailableError(`OS keychain binding unavailable (${service}/${account}): ${err instanceof Error ? err.message : String(err)}`);
|
|
211
|
+
}
|
|
212
|
+
let entry;
|
|
213
|
+
try {
|
|
214
|
+
entry = new Entry(service, account);
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
throw new MasterKeyUnavailableError(`OS keychain entry construction failed (${service}/${account}): ${err instanceof Error ? err.message : String(err)}`);
|
|
218
|
+
}
|
|
219
|
+
let existing = null;
|
|
220
|
+
try {
|
|
221
|
+
existing = entry.getPassword();
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
throw new MasterKeyUnavailableError(`OS keychain read failed (${service}/${account}): ${err instanceof Error ? err.message : String(err)}. On Linux, ensure libsecret + a Secret Service agent (gnome-keyring / kwallet) is running, or pass an inMemoryMasterKey.`);
|
|
225
|
+
}
|
|
226
|
+
if (existing && existing.length > 0) {
|
|
227
|
+
const buf = Buffer.from(existing, "base64");
|
|
228
|
+
if (buf.length !== KEY_BYTES) {
|
|
229
|
+
throw new MasterKeyUnavailableError(`OS keychain entry ${service}/${account} is not a ${KEY_BYTES}-byte key`);
|
|
230
|
+
}
|
|
231
|
+
return buf;
|
|
232
|
+
}
|
|
233
|
+
const created = generateMasterKey();
|
|
234
|
+
try {
|
|
235
|
+
entry.setPassword(created.toString("base64"));
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
throw new MasterKeyUnavailableError(`OS keychain write failed (${service}/${account}): ${err instanceof Error ? err.message : String(err)}`);
|
|
239
|
+
}
|
|
240
|
+
return created;
|
|
241
|
+
},
|
|
242
|
+
describe() {
|
|
243
|
+
return `keychain://${service}/${account}`;
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=master-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"master-key.js","sourceRoot":"","sources":["../src/master-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PasswordManagerReference } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a password-manager reference at use time.
|
|
4
|
+
*
|
|
5
|
+
* 1Password: shells out to `op read op://<vault>/<item>/<field>`.
|
|
6
|
+
* Proton Pass: scaffolded; the vendor's CLI/SDK isn't stable enough
|
|
7
|
+
* to wire in v1.
|
|
8
|
+
*
|
|
9
|
+
* The reference contents are never copied to disk by the vault; only
|
|
10
|
+
* the reference itself (`{ source, path }`) is stored.
|
|
11
|
+
*/
|
|
12
|
+
export declare class PasswordManagerError extends Error {
|
|
13
|
+
readonly source: PasswordManagerReference["source"];
|
|
14
|
+
constructor(source: PasswordManagerReference["source"], message: string);
|
|
15
|
+
}
|
|
16
|
+
export declare function resolveReference(ref: PasswordManagerReference): Promise<string>;
|
|
17
|
+
//# sourceMappingURL=password-managers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-managers.d.ts","sourceRoot":"","sources":["../src/password-managers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAI3D;;;;;;;;;GASG;AAEH,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC,QAAQ,CAAC;gBAA1C,MAAM,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EACnD,OAAO,EAAE,MAAM;CAKlB;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,wBAAwB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAIjB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const exec = promisify(execFile);
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a password-manager reference at use time.
|
|
6
|
+
*
|
|
7
|
+
* 1Password: shells out to `op read op://<vault>/<item>/<field>`.
|
|
8
|
+
* Proton Pass: scaffolded; the vendor's CLI/SDK isn't stable enough
|
|
9
|
+
* to wire in v1.
|
|
10
|
+
*
|
|
11
|
+
* The reference contents are never copied to disk by the vault; only
|
|
12
|
+
* the reference itself (`{ source, path }`) is stored.
|
|
13
|
+
*/
|
|
14
|
+
export class PasswordManagerError extends Error {
|
|
15
|
+
source;
|
|
16
|
+
constructor(source, message) {
|
|
17
|
+
super(`[${source}] ${message}`);
|
|
18
|
+
this.source = source;
|
|
19
|
+
this.name = "PasswordManagerError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function resolveReference(ref) {
|
|
23
|
+
if (ref.source === "1password")
|
|
24
|
+
return resolve1Password(ref.path);
|
|
25
|
+
if (ref.source === "protonpass")
|
|
26
|
+
return resolveProtonPass(ref.path);
|
|
27
|
+
throw new PasswordManagerError(ref.source, "unsupported source");
|
|
28
|
+
}
|
|
29
|
+
async function resolve1Password(path) {
|
|
30
|
+
const uri = path.startsWith("op://") ? path : `op://${path}`;
|
|
31
|
+
try {
|
|
32
|
+
const { stdout } = await exec("op", ["read", uri], {
|
|
33
|
+
encoding: "utf8",
|
|
34
|
+
timeout: 5000,
|
|
35
|
+
});
|
|
36
|
+
const value = stdout.trim();
|
|
37
|
+
if (value.length === 0) {
|
|
38
|
+
throw new PasswordManagerError("1password", `${uri} is empty`);
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
const e = err;
|
|
44
|
+
if (e.code === "ENOENT") {
|
|
45
|
+
throw new PasswordManagerError("1password", "`op` CLI not found. Install from https://developer.1password.com/docs/cli, then sign in (`eval $(op signin)`).");
|
|
46
|
+
}
|
|
47
|
+
if (err instanceof PasswordManagerError)
|
|
48
|
+
throw err;
|
|
49
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
50
|
+
if (/not signed in|not authenticated/i.test(msg)) {
|
|
51
|
+
throw new PasswordManagerError("1password", "`op` is not signed in. Unlock the 1Password desktop app or run `eval $(op signin)`.");
|
|
52
|
+
}
|
|
53
|
+
throw new PasswordManagerError("1password", msg);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function resolveProtonPass(_path) {
|
|
57
|
+
throw new PasswordManagerError("protonpass", "Proton Pass integration is scaffolded; vendor CLI / SDK is not yet stable. File a request to prioritize.");
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=password-managers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-managers.js","sourceRoot":"","sources":["../src/password-managers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAEjC;;;;;;;;;GASG;AAEH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAElC;IADX,YACW,MAA0C,EACnD,OAAe;QAEf,KAAK,CAAC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC;QAHvB,WAAM,GAAN,MAAM,CAAoC;QAInD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAA6B;IAE7B,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClE,IAAI,GAAG,CAAC,MAAM,KAAK,YAAY;QAAE,OAAO,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,IAAI,oBAAoB,CAAC,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AACnE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;YACjD,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,oBAAoB,CAAC,WAAW,EAAE,GAAG,GAAG,WAAW,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,GAA4B,CAAC;QACvC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,oBAAoB,CAC5B,WAAW,EACX,gHAAgH,CACjH,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,YAAY,oBAAoB;YAAE,MAAM,GAAG,CAAC;QACnD,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,kCAAkC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,oBAAoB,CAC5B,WAAW,EACX,qFAAqF,CACtF,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,oBAAoB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,KAAa;IAC5C,MAAM,IAAI,oBAAoB,CAC5B,YAAY,EACZ,0GAA0G,CAC3G,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile resolution + per-context routing on top of `Vault`.
|
|
3
|
+
*
|
|
4
|
+
* Two layers:
|
|
5
|
+
*
|
|
6
|
+
* 1. Per-key active profile.
|
|
7
|
+
* A key K can have multiple named profiles (e.g. work, personal,
|
|
8
|
+
* throwaway). Each profile's value lives at `K.profile.<profileId>`;
|
|
9
|
+
* the meta blob (`_meta.K`) tracks the profile list and which one
|
|
10
|
+
* is currently active for bare reads. When no meta is present the
|
|
11
|
+
* legacy storage path is used (the value lives at K itself).
|
|
12
|
+
*
|
|
13
|
+
* 2. Per-context routing rules.
|
|
14
|
+
* A user can declare "for OPENROUTER_API_KEY, when agentId=X use the
|
|
15
|
+
* work profile". Rules are walked in order; the first match wins.
|
|
16
|
+
* Falls back to the key's `activeProfile`, then to the global
|
|
17
|
+
* `defaultProfile`, then to the legacy bare-key value.
|
|
18
|
+
*
|
|
19
|
+
* The vault stays dumb: every read goes through `Vault.get/has`. The
|
|
20
|
+
* only routing logic lives here so the vault contract is unchanged.
|
|
21
|
+
*/
|
|
22
|
+
import type { Vault } from "./vault.js";
|
|
23
|
+
export type RoutingScopeKind = "agent" | "app" | "skill";
|
|
24
|
+
export interface RoutingScope {
|
|
25
|
+
readonly kind: RoutingScopeKind;
|
|
26
|
+
readonly agentId?: string;
|
|
27
|
+
readonly appName?: string;
|
|
28
|
+
readonly skillId?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface RoutingRule {
|
|
31
|
+
/** Exact-match against the vault key (e.g. "OPENROUTER_API_KEY"). */
|
|
32
|
+
readonly keyPattern: string;
|
|
33
|
+
readonly scope: RoutingScope;
|
|
34
|
+
readonly profileId: string;
|
|
35
|
+
}
|
|
36
|
+
export interface RoutingConfig {
|
|
37
|
+
readonly rules: ReadonlyArray<RoutingRule>;
|
|
38
|
+
/**
|
|
39
|
+
* Profile id used when no rule matches and the key's own
|
|
40
|
+
* `activeProfile` is unset. Acts as the global default for keys
|
|
41
|
+
* that have profiles enabled.
|
|
42
|
+
*/
|
|
43
|
+
readonly defaultProfile?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ResolutionContext {
|
|
46
|
+
readonly agentId?: string;
|
|
47
|
+
readonly appName?: string;
|
|
48
|
+
readonly skillId?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve `key` against (a) per-context routing rules, (b) the key's
|
|
52
|
+
* `activeProfile`, (c) the global `defaultProfile`, then (d) the bare
|
|
53
|
+
* key value.
|
|
54
|
+
*
|
|
55
|
+
* Throws when none of the above resolves to a stored value — callers
|
|
56
|
+
* decide how to surface the miss (e.g. inventory routes return 404,
|
|
57
|
+
* runtime callers fall back to env var).
|
|
58
|
+
*/
|
|
59
|
+
export declare function resolveActiveValue(vault: Vault, key: string, ctx?: ResolutionContext): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Read the routing config blob from the vault. Missing or malformed
|
|
62
|
+
* entries return `EMPTY_ROUTING` — routing is best-effort overlay,
|
|
63
|
+
* not a load-bearing contract.
|
|
64
|
+
*/
|
|
65
|
+
export declare function readRoutingConfig(vault: Vault): Promise<RoutingConfig>;
|
|
66
|
+
/** Persist the routing config blob. Caller-validated input. */
|
|
67
|
+
export declare function writeRoutingConfig(vault: Vault, config: RoutingConfig): Promise<void>;
|
|
68
|
+
//# sourceMappingURL=profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../src/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAQH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAID,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,CAI5E;AAED,+DAA+D;AAC/D,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAGf"}
|