@getaegis/cli 0.8.0 → 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.
Files changed (210) hide show
  1. package/README.md +5 -0
  2. package/dist/agent/agent.d.ts +98 -0
  3. package/dist/agent/agent.d.ts.map +1 -0
  4. package/dist/agent/agent.js +212 -0
  5. package/dist/agent/agent.js.map +1 -0
  6. package/dist/agent/index.d.ts +3 -0
  7. package/dist/agent/index.d.ts.map +1 -0
  8. package/dist/agent/index.js +2 -0
  9. package/dist/agent/index.js.map +1 -0
  10. package/dist/cli/auth.d.ts +19 -0
  11. package/dist/cli/auth.d.ts.map +1 -0
  12. package/dist/cli/auth.js +44 -0
  13. package/dist/cli/auth.js.map +1 -0
  14. package/dist/cli/commands/agent.d.ts +6 -0
  15. package/dist/cli/commands/agent.d.ts.map +1 -0
  16. package/dist/cli/commands/agent.js +241 -0
  17. package/dist/cli/commands/agent.js.map +1 -0
  18. package/dist/cli/commands/config.d.ts +6 -0
  19. package/dist/cli/commands/config.d.ts.map +1 -0
  20. package/dist/cli/commands/config.js +125 -0
  21. package/dist/cli/commands/config.js.map +1 -0
  22. package/dist/cli/commands/dashboard.d.ts +6 -0
  23. package/dist/cli/commands/dashboard.d.ts.map +1 -0
  24. package/dist/cli/commands/dashboard.js +189 -0
  25. package/dist/cli/commands/dashboard.js.map +1 -0
  26. package/dist/cli/commands/doctor.d.ts +6 -0
  27. package/dist/cli/commands/doctor.d.ts.map +1 -0
  28. package/dist/cli/commands/doctor.js +39 -0
  29. package/dist/cli/commands/doctor.js.map +1 -0
  30. package/dist/cli/commands/gate.d.ts +6 -0
  31. package/dist/cli/commands/gate.d.ts.map +1 -0
  32. package/dist/cli/commands/gate.js +196 -0
  33. package/dist/cli/commands/gate.js.map +1 -0
  34. package/dist/cli/commands/init.d.ts +6 -0
  35. package/dist/cli/commands/init.d.ts.map +1 -0
  36. package/dist/cli/commands/init.js +109 -0
  37. package/dist/cli/commands/init.js.map +1 -0
  38. package/dist/cli/commands/ledger.d.ts +6 -0
  39. package/dist/cli/commands/ledger.d.ts.map +1 -0
  40. package/dist/cli/commands/ledger.js +140 -0
  41. package/dist/cli/commands/ledger.js.map +1 -0
  42. package/dist/cli/commands/mcp.d.ts +6 -0
  43. package/dist/cli/commands/mcp.d.ts.map +1 -0
  44. package/dist/cli/commands/mcp.js +224 -0
  45. package/dist/cli/commands/mcp.js.map +1 -0
  46. package/dist/cli/commands/policy.d.ts +6 -0
  47. package/dist/cli/commands/policy.d.ts.map +1 -0
  48. package/dist/cli/commands/policy.js +126 -0
  49. package/dist/cli/commands/policy.js.map +1 -0
  50. package/dist/cli/commands/user.d.ts +6 -0
  51. package/dist/cli/commands/user.d.ts.map +1 -0
  52. package/dist/cli/commands/user.js +150 -0
  53. package/dist/cli/commands/user.js.map +1 -0
  54. package/dist/cli/commands/vault-manager.d.ts +6 -0
  55. package/dist/cli/commands/vault-manager.d.ts.map +1 -0
  56. package/dist/cli/commands/vault-manager.js +240 -0
  57. package/dist/cli/commands/vault-manager.js.map +1 -0
  58. package/dist/cli/commands/vault.d.ts +6 -0
  59. package/dist/cli/commands/vault.d.ts.map +1 -0
  60. package/dist/cli/commands/vault.js +241 -0
  61. package/dist/cli/commands/vault.js.map +1 -0
  62. package/dist/cli/commands/webhook.d.ts +6 -0
  63. package/dist/cli/commands/webhook.d.ts.map +1 -0
  64. package/dist/cli/commands/webhook.js +151 -0
  65. package/dist/cli/commands/webhook.js.map +1 -0
  66. package/dist/cli/helpers.d.ts +12 -0
  67. package/dist/cli/helpers.d.ts.map +1 -0
  68. package/dist/cli/helpers.js +61 -0
  69. package/dist/cli/helpers.js.map +1 -0
  70. package/dist/cli/index.d.ts +17 -0
  71. package/dist/cli/index.d.ts.map +1 -0
  72. package/dist/cli/index.js +17 -0
  73. package/dist/cli/index.js.map +1 -0
  74. package/dist/cli/validation.d.ts +37 -0
  75. package/dist/cli/validation.d.ts.map +1 -0
  76. package/dist/cli/validation.js +104 -0
  77. package/dist/cli/validation.js.map +1 -0
  78. package/dist/cli.d.ts +3 -0
  79. package/dist/cli.d.ts.map +1 -0
  80. package/dist/cli.js +30 -0
  81. package/dist/cli.js.map +1 -0
  82. package/dist/config.d.ts +108 -0
  83. package/dist/config.d.ts.map +1 -0
  84. package/dist/config.js +355 -0
  85. package/dist/config.js.map +1 -0
  86. package/dist/dashboard/dashboard-server.d.ts +95 -0
  87. package/dist/dashboard/dashboard-server.d.ts.map +1 -0
  88. package/dist/dashboard/dashboard-server.js +329 -0
  89. package/dist/dashboard/dashboard-server.js.map +1 -0
  90. package/dist/dashboard/index.d.ts +3 -0
  91. package/dist/dashboard/index.d.ts.map +1 -0
  92. package/dist/dashboard/index.js +2 -0
  93. package/dist/dashboard/index.js.map +1 -0
  94. package/dist/dashboard/public/assets/index-CpMruPNh.css +1 -0
  95. package/dist/dashboard/public/assets/index-DkHiw9_f.js +148 -0
  96. package/dist/dashboard/public/favicon.svg +6 -0
  97. package/dist/dashboard/public/index.html +14 -0
  98. package/dist/db.d.ts +15 -0
  99. package/dist/db.d.ts.map +1 -0
  100. package/dist/db.js +190 -0
  101. package/dist/db.js.map +1 -0
  102. package/dist/doctor.d.ts +37 -0
  103. package/dist/doctor.d.ts.map +1 -0
  104. package/dist/doctor.js +196 -0
  105. package/dist/doctor.js.map +1 -0
  106. package/dist/gate/body-inspector.d.ts +31 -0
  107. package/dist/gate/body-inspector.d.ts.map +1 -0
  108. package/dist/gate/body-inspector.js +193 -0
  109. package/dist/gate/body-inspector.js.map +1 -0
  110. package/dist/gate/gate.d.ts +168 -0
  111. package/dist/gate/gate.d.ts.map +1 -0
  112. package/dist/gate/gate.js +1016 -0
  113. package/dist/gate/gate.js.map +1 -0
  114. package/dist/gate/index.d.ts +7 -0
  115. package/dist/gate/index.d.ts.map +1 -0
  116. package/dist/gate/index.js +4 -0
  117. package/dist/gate/index.js.map +1 -0
  118. package/dist/gate/rate-limiter.d.ts +59 -0
  119. package/dist/gate/rate-limiter.d.ts.map +1 -0
  120. package/dist/gate/rate-limiter.js +120 -0
  121. package/dist/gate/rate-limiter.js.map +1 -0
  122. package/dist/index.d.ts +26 -0
  123. package/dist/index.d.ts.map +1 -0
  124. package/dist/index.js +16 -0
  125. package/dist/index.js.map +1 -0
  126. package/dist/ledger/index.d.ts +3 -0
  127. package/dist/ledger/index.d.ts.map +1 -0
  128. package/dist/ledger/index.js +2 -0
  129. package/dist/ledger/index.js.map +1 -0
  130. package/dist/ledger/ledger.d.ts +98 -0
  131. package/dist/ledger/ledger.d.ts.map +1 -0
  132. package/dist/ledger/ledger.js +145 -0
  133. package/dist/ledger/ledger.js.map +1 -0
  134. package/dist/logger/index.d.ts +3 -0
  135. package/dist/logger/index.d.ts.map +1 -0
  136. package/dist/logger/index.js +2 -0
  137. package/dist/logger/index.js.map +1 -0
  138. package/dist/logger/logger.d.ts +58 -0
  139. package/dist/logger/logger.d.ts.map +1 -0
  140. package/dist/logger/logger.js +201 -0
  141. package/dist/logger/logger.js.map +1 -0
  142. package/dist/mcp/index.d.ts +3 -0
  143. package/dist/mcp/index.d.ts.map +1 -0
  144. package/dist/mcp/index.js +2 -0
  145. package/dist/mcp/index.js.map +1 -0
  146. package/dist/mcp/mcp-server.d.ts +130 -0
  147. package/dist/mcp/mcp-server.d.ts.map +1 -0
  148. package/dist/mcp/mcp-server.js +775 -0
  149. package/dist/mcp/mcp-server.js.map +1 -0
  150. package/dist/metrics/index.d.ts +3 -0
  151. package/dist/metrics/index.d.ts.map +1 -0
  152. package/dist/metrics/index.js +2 -0
  153. package/dist/metrics/index.js.map +1 -0
  154. package/dist/metrics/metrics.d.ts +88 -0
  155. package/dist/metrics/metrics.d.ts.map +1 -0
  156. package/dist/metrics/metrics.js +179 -0
  157. package/dist/metrics/metrics.js.map +1 -0
  158. package/dist/policy/index.d.ts +3 -0
  159. package/dist/policy/index.d.ts.map +1 -0
  160. package/dist/policy/index.js +2 -0
  161. package/dist/policy/index.js.map +1 -0
  162. package/dist/policy/policy.d.ts +119 -0
  163. package/dist/policy/policy.d.ts.map +1 -0
  164. package/dist/policy/policy.js +426 -0
  165. package/dist/policy/policy.js.map +1 -0
  166. package/dist/user/index.d.ts +3 -0
  167. package/dist/user/index.d.ts.map +1 -0
  168. package/dist/user/index.js +2 -0
  169. package/dist/user/index.js.map +1 -0
  170. package/dist/user/user.d.ts +102 -0
  171. package/dist/user/user.d.ts.map +1 -0
  172. package/dist/user/user.js +216 -0
  173. package/dist/user/user.js.map +1 -0
  174. package/dist/vault/crypto.d.ts +28 -0
  175. package/dist/vault/crypto.d.ts.map +1 -0
  176. package/dist/vault/crypto.js +44 -0
  177. package/dist/vault/crypto.js.map +1 -0
  178. package/dist/vault/index.d.ts +10 -0
  179. package/dist/vault/index.d.ts.map +1 -0
  180. package/dist/vault/index.js +6 -0
  181. package/dist/vault/index.js.map +1 -0
  182. package/dist/vault/seal.d.ts +68 -0
  183. package/dist/vault/seal.d.ts.map +1 -0
  184. package/dist/vault/seal.js +110 -0
  185. package/dist/vault/seal.js.map +1 -0
  186. package/dist/vault/shamir.d.ts +33 -0
  187. package/dist/vault/shamir.d.ts.map +1 -0
  188. package/dist/vault/shamir.js +174 -0
  189. package/dist/vault/shamir.js.map +1 -0
  190. package/dist/vault/vault-manager.d.ts +62 -0
  191. package/dist/vault/vault-manager.d.ts.map +1 -0
  192. package/dist/vault/vault-manager.js +141 -0
  193. package/dist/vault/vault-manager.js.map +1 -0
  194. package/dist/vault/vault.d.ts +104 -0
  195. package/dist/vault/vault.d.ts.map +1 -0
  196. package/dist/vault/vault.js +259 -0
  197. package/dist/vault/vault.js.map +1 -0
  198. package/dist/version.d.ts +3 -0
  199. package/dist/version.d.ts.map +1 -0
  200. package/dist/version.js +18 -0
  201. package/dist/version.js.map +1 -0
  202. package/dist/webhook/index.d.ts +3 -0
  203. package/dist/webhook/index.d.ts.map +1 -0
  204. package/dist/webhook/index.js +2 -0
  205. package/dist/webhook/index.js.map +1 -0
  206. package/dist/webhook/webhook.d.ts +114 -0
  207. package/dist/webhook/webhook.d.ts.map +1 -0
  208. package/dist/webhook/webhook.js +269 -0
  209. package/dist/webhook/webhook.js.map +1 -0
  210. package/package.json +7 -3
@@ -0,0 +1,216 @@
1
+ import * as crypto from 'node:crypto';
2
+ export const VALID_ROLES = ['admin', 'operator', 'viewer'];
3
+ /**
4
+ * Role → permission mapping.
5
+ * More privileged roles include all permissions from less privileged ones.
6
+ */
7
+ const ROLE_PERMISSIONS = {
8
+ admin: new Set([
9
+ 'vault:read',
10
+ 'vault:write',
11
+ 'vault:manage',
12
+ 'agent:read',
13
+ 'agent:write',
14
+ 'ledger:read',
15
+ 'ledger:export',
16
+ 'gate:start',
17
+ 'policy:read',
18
+ 'policy:write',
19
+ 'webhook:read',
20
+ 'webhook:write',
21
+ 'user:read',
22
+ 'user:write',
23
+ 'dashboard:view',
24
+ 'doctor:run',
25
+ ]),
26
+ operator: new Set([
27
+ 'vault:read',
28
+ 'agent:read',
29
+ 'agent:write',
30
+ 'ledger:read',
31
+ 'ledger:export',
32
+ 'gate:start',
33
+ 'policy:read',
34
+ 'webhook:read',
35
+ 'dashboard:view',
36
+ 'doctor:run',
37
+ ]),
38
+ viewer: new Set(['vault:read', 'ledger:read', 'dashboard:view', 'doctor:run']),
39
+ };
40
+ /**
41
+ * Check if a role has a specific permission.
42
+ */
43
+ export function hasPermission(role, permission) {
44
+ return ROLE_PERMISSIONS[role].has(permission);
45
+ }
46
+ /**
47
+ * Get all permissions for a role.
48
+ */
49
+ export function getPermissions(role) {
50
+ return ROLE_PERMISSIONS[role];
51
+ }
52
+ // ─── User Registry ──────────────────────────────────────────────
53
+ /**
54
+ * User Registry — manages user identities, authentication, and role-based access control.
55
+ *
56
+ * Users are authenticated via API keys (same pattern as agent tokens):
57
+ * - Token format: aegis_user_{uuid}_{hmac_prefix}
58
+ * - Tokens are SHA-256 hashed for fast lookup — hash-only, no recovery
59
+ * - Prefixed (first 17 chars: "aegis_user_" + 6) for safe logging
60
+ *
61
+ * Security: Same hash-only storage as agent tokens. If a token is lost,
62
+ * use regenerateToken() to issue a new one.
63
+ */
64
+ export class UserRegistry {
65
+ db;
66
+ derivedKey;
67
+ constructor(db, derivedKey) {
68
+ this.db = db;
69
+ this.derivedKey = derivedKey;
70
+ }
71
+ /**
72
+ * Register a new user. Returns the user with their API key (shown once).
73
+ *
74
+ * Token format: aegis_user_{uuid}_{hmac_prefix}
75
+ */
76
+ add(params) {
77
+ if (!VALID_ROLES.includes(params.role)) {
78
+ throw new Error(`Invalid role "${params.role}". Must be one of: ${VALID_ROLES.join(', ')}`);
79
+ }
80
+ const id = crypto.randomUUID();
81
+ const uuid = crypto.randomUUID();
82
+ // Create HMAC of the UUID using the derived key for token integrity
83
+ const hmac = crypto
84
+ .createHmac('sha256', this.derivedKey)
85
+ .update(uuid)
86
+ .digest('hex')
87
+ .slice(0, 16);
88
+ const token = `aegis_user_${uuid}_${hmac}`;
89
+ // Hash the full token for fast lookup (hash-only — no recovery, only regeneration)
90
+ const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
91
+ const tokenPrefix = token.slice(0, 17); // "aegis_user_" + 6 chars
92
+ this.db
93
+ .prepare(`INSERT INTO users (id, name, role, token_hash, token_prefix)
94
+ VALUES (?, ?, ?, ?, ?)`)
95
+ .run(id, params.name, params.role, tokenHash, tokenPrefix);
96
+ return {
97
+ id,
98
+ name: params.name,
99
+ role: params.role,
100
+ tokenPrefix,
101
+ token,
102
+ createdAt: new Date().toISOString(),
103
+ updatedAt: new Date().toISOString(),
104
+ };
105
+ }
106
+ /**
107
+ * List all registered users (without tokens).
108
+ */
109
+ list() {
110
+ const rows = this.db.prepare('SELECT * FROM users ORDER BY created_at DESC').all();
111
+ return rows.map((row) => this.rowToUser(row));
112
+ }
113
+ /**
114
+ * Get a user by name (without token).
115
+ */
116
+ getByName(name) {
117
+ const row = this.db.prepare('SELECT * FROM users WHERE name = ?').get(name);
118
+ return row ? this.rowToUser(row) : null;
119
+ }
120
+ /**
121
+ * Validate a user API key. Returns the user if the token is valid, null otherwise.
122
+ *
123
+ * Uses SHA-256 hash comparison for O(1) lookup.
124
+ */
125
+ validateToken(token) {
126
+ const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
127
+ const row = this.db.prepare('SELECT * FROM users WHERE token_hash = ?').get(tokenHash);
128
+ return row ? this.rowToUser(row) : null;
129
+ }
130
+ /**
131
+ * Remove a user by name.
132
+ */
133
+ remove(name) {
134
+ const result = this.db.prepare('DELETE FROM users WHERE name = ?').run(name);
135
+ return result.changes > 0;
136
+ }
137
+ /**
138
+ * Update a user's role.
139
+ */
140
+ updateRole(params) {
141
+ if (!VALID_ROLES.includes(params.role)) {
142
+ throw new Error(`Invalid role "${params.role}". Must be one of: ${VALID_ROLES.join(', ')}`);
143
+ }
144
+ const user = this.getByName(params.name);
145
+ if (!user) {
146
+ throw new Error(`No user found with name "${params.name}"`);
147
+ }
148
+ this.db
149
+ .prepare("UPDATE users SET role = ?, updated_at = datetime('now') WHERE name = ?")
150
+ .run(params.role, params.name);
151
+ return {
152
+ ...user,
153
+ role: params.role,
154
+ updatedAt: new Date().toISOString(),
155
+ };
156
+ }
157
+ /**
158
+ * Regenerate a user's token. Issues a new token, invalidates the old one.
159
+ *
160
+ * The user keeps their identity (id, name, role).
161
+ * Only the token changes.
162
+ *
163
+ * Returns the user with the new token (shown once), or null if not found.
164
+ */
165
+ regenerateToken(name) {
166
+ const user = this.getByName(name);
167
+ if (!user)
168
+ return null;
169
+ const uuid = crypto.randomUUID();
170
+ const hmac = crypto
171
+ .createHmac('sha256', this.derivedKey)
172
+ .update(uuid)
173
+ .digest('hex')
174
+ .slice(0, 16);
175
+ const token = `aegis_user_${uuid}_${hmac}`;
176
+ const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
177
+ const tokenPrefix = token.slice(0, 17);
178
+ this.db
179
+ .prepare(`UPDATE users SET token_hash = ?, token_prefix = ?, updated_at = datetime('now') WHERE id = ?`)
180
+ .run(tokenHash, tokenPrefix, user.id);
181
+ return {
182
+ ...user,
183
+ tokenPrefix,
184
+ token,
185
+ updatedAt: new Date().toISOString(),
186
+ };
187
+ }
188
+ /**
189
+ * Check if a user has a specific permission.
190
+ */
191
+ checkPermission(name, permission) {
192
+ const user = this.getByName(name);
193
+ if (!user)
194
+ return false;
195
+ return hasPermission(user.role, permission);
196
+ }
197
+ /**
198
+ * Count users. Used by init to determine if initial admin setup is needed.
199
+ */
200
+ count() {
201
+ const row = this.db.prepare('SELECT COUNT(*) as count FROM users').get();
202
+ return row.count;
203
+ }
204
+ // ─── Internal ───────────────────────────────────────────────────
205
+ rowToUser(row) {
206
+ return {
207
+ id: row.id,
208
+ name: row.name,
209
+ role: row.role,
210
+ tokenPrefix: row.token_prefix,
211
+ createdAt: row.created_at,
212
+ updatedAt: row.updated_at,
213
+ };
214
+ }
215
+ }
216
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/user/user.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Generate a cryptographically random salt for PBKDF2 key derivation.
3
+ * Should be called once during `aegis init` and persisted alongside the master key.
4
+ */
5
+ export declare function generateSalt(): string;
6
+ /**
7
+ * Derives a 256-bit encryption key from the master key using PBKDF2.
8
+ *
9
+ * @param masterKey High-entropy master secret
10
+ * @param salt Per-deployment salt (use {@link generateSalt} to create one)
11
+ */
12
+ export declare function deriveKey(masterKey: string, salt?: Buffer | string): Buffer;
13
+ export interface EncryptedData {
14
+ encrypted: Buffer;
15
+ iv: Buffer;
16
+ authTag: Buffer;
17
+ }
18
+ /**
19
+ * Encrypts a plaintext credential using AES-256-GCM.
20
+ * Accepts a pre-derived key so callers can cache the expensive PBKDF2 result.
21
+ */
22
+ export declare function encrypt(plaintext: string, key: Buffer): EncryptedData;
23
+ /**
24
+ * Decrypts an AES-256-GCM encrypted credential.
25
+ * Accepts a pre-derived key so callers can cache the expensive PBKDF2 result.
26
+ */
27
+ export declare function decrypt(data: EncryptedData, key: Buffer): string;
28
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/vault/crypto.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,MAAqB,GAAG,MAAM,CAEzF;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAQrE;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhE"}
@@ -0,0 +1,44 @@
1
+ import * as crypto from 'node:crypto';
2
+ const ALGORITHM = 'aes-256-gcm';
3
+ const KEY_LENGTH = 32;
4
+ const IV_LENGTH = 16;
5
+ /** Default salt kept for backward-compatibility with pre-v0.2 vaults. */
6
+ const DEFAULT_SALT = 'aegis-vault-v1';
7
+ /**
8
+ * Generate a cryptographically random salt for PBKDF2 key derivation.
9
+ * Should be called once during `aegis init` and persisted alongside the master key.
10
+ */
11
+ export function generateSalt() {
12
+ return crypto.randomBytes(32).toString('hex');
13
+ }
14
+ /**
15
+ * Derives a 256-bit encryption key from the master key using PBKDF2.
16
+ *
17
+ * @param masterKey High-entropy master secret
18
+ * @param salt Per-deployment salt (use {@link generateSalt} to create one)
19
+ */
20
+ export function deriveKey(masterKey, salt = DEFAULT_SALT) {
21
+ return crypto.pbkdf2Sync(masterKey, salt, 100_000, KEY_LENGTH, 'sha512');
22
+ }
23
+ /**
24
+ * Encrypts a plaintext credential using AES-256-GCM.
25
+ * Accepts a pre-derived key so callers can cache the expensive PBKDF2 result.
26
+ */
27
+ export function encrypt(plaintext, key) {
28
+ const iv = crypto.randomBytes(IV_LENGTH);
29
+ const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
30
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);
31
+ const authTag = cipher.getAuthTag();
32
+ return { encrypted, iv, authTag };
33
+ }
34
+ /**
35
+ * Decrypts an AES-256-GCM encrypted credential.
36
+ * Accepts a pre-derived key so callers can cache the expensive PBKDF2 result.
37
+ */
38
+ export function decrypt(data, key) {
39
+ const decipher = crypto.createDecipheriv(ALGORITHM, key, data.iv);
40
+ decipher.setAuthTag(data.authTag);
41
+ const decrypted = Buffer.concat([decipher.update(data.encrypted), decipher.final()]);
42
+ return decrypted.toString('utf-8');
43
+ }
44
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/vault/crypto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,MAAM,SAAS,GAAG,aAAa,CAAC;AAChC,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,yEAAyE;AACzE,MAAM,YAAY,GAAG,gBAAgB,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,OAAwB,YAAY;IAC/E,OAAO,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;AAC3E,CAAC;AAQD;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,SAAiB,EAAE,GAAW;IACpD,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAEzD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACrF,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAEpC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,IAAmB,EAAE,GAAW;IACtD,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAClE,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACrF,OAAO,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { decrypt, deriveKey, encrypt, generateSalt } from './crypto.js';
2
+ export type { SealConfig } from './seal.js';
3
+ export { SealManager } from './seal.js';
4
+ export type { ShamirShare } from './shamir.js';
5
+ export { combine, decodeShare, encodeShare, split } from './shamir.js';
6
+ export type { AuthType, Credential, CredentialWithSecret, } from './vault.js';
7
+ export { Vault } from './vault.js';
8
+ export type { VaultInfo } from './vault-manager.js';
9
+ export { VaultManager } from './vault-manager.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vault/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EACV,QAAQ,EACR,UAAU,EACV,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { decrypt, deriveKey, encrypt, generateSalt } from './crypto.js';
2
+ export { SealManager } from './seal.js';
3
+ export { combine, decodeShare, encodeShare, split } from './shamir.js';
4
+ export { Vault } from './vault.js';
5
+ export { VaultManager } from './vault-manager.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vault/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAExE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAMvE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Persistent seal configuration (stored in .aegis/.seal-config.json).
3
+ * Tracks threshold, total share count, and a key hash for verification.
4
+ * Never stores the master key or shares.
5
+ */
6
+ export interface SealConfig {
7
+ /** Minimum shares required to reconstruct the master key. */
8
+ threshold: number;
9
+ /** Total shares that were generated. */
10
+ totalShares: number;
11
+ /** SHA-256 hash of the master key (hex) — used to verify reconstruction. */
12
+ keyHash: string;
13
+ /** ISO timestamp of when key splitting was configured. */
14
+ createdAt: string;
15
+ }
16
+ /**
17
+ * Manages vault seal state — key splitting configuration, unseal key
18
+ * storage, and sealed/unsealed transitions.
19
+ *
20
+ * Modelled after HashiCorp Vault's seal/unseal mechanism, adapted for
21
+ * CLI (non-daemon) usage: the reconstructed key is persisted to a
22
+ * restricted file instead of held in memory.
23
+ *
24
+ * Files managed:
25
+ * .aegis/.seal-config.json — threshold, share count, key hash
26
+ * .aegis/.unseal-key — reconstructed master key (mode 0600)
27
+ */
28
+ export declare class SealManager {
29
+ private dataDir;
30
+ private configPath;
31
+ private unsealKeyPath;
32
+ constructor(dataDir: string);
33
+ /**
34
+ * Enable key splitting — stores threshold, share count, and a SHA-256
35
+ * hash of the master key for post-reconstruction verification.
36
+ */
37
+ enableSplit(threshold: number, totalShares: number, masterKey: string): void;
38
+ /** Read seal configuration, or null if key splitting is not configured. */
39
+ getSealConfig(): SealConfig | null;
40
+ /** Whether key splitting has been configured for this deployment. */
41
+ isSplitEnabled(): boolean;
42
+ /**
43
+ * Verify a reconstructed master key against the stored hash.
44
+ * Uses timing-safe comparison to prevent side-channel leaks.
45
+ */
46
+ verifyKey(masterKey: string): boolean;
47
+ /**
48
+ * Write the reconstructed master key to the unseal key file.
49
+ * File is created with mode 0600 (owner read/write only).
50
+ */
51
+ writeUnsealKey(masterKey: string): void;
52
+ /** Read the unseal key, or null if the vault is sealed. */
53
+ readUnsealKey(): string | null;
54
+ /** Whether the vault is currently unsealed (unseal key file exists). */
55
+ isUnsealed(): boolean;
56
+ /**
57
+ * Seal the vault — securely remove the unseal key file.
58
+ * Overwrites the file with zeros before unlinking (defense in depth
59
+ * against filesystem journal recovery).
60
+ */
61
+ seal(): void;
62
+ /**
63
+ * Remove seal configuration entirely — reverts to standard master key mode.
64
+ * Also removes any existing unseal key.
65
+ */
66
+ removeSealConfig(): void;
67
+ }
68
+ //# sourceMappingURL=seal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../src/vault/seal.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,WAAW;IAIV,OAAO,CAAC,OAAO;IAH3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;gBAEV,OAAO,EAAE,MAAM;IAKnC;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAiB5E,2EAA2E;IAC3E,aAAa,IAAI,UAAU,GAAG,IAAI;IAMlC,qEAAqE;IACrE,cAAc,IAAI,OAAO;IAIzB;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAOrC;;;OAGG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAOvC,2DAA2D;IAC3D,aAAa,IAAI,MAAM,GAAG,IAAI;IAK9B,wEAAwE;IACxE,UAAU,IAAI,OAAO;IAIrB;;;;OAIG;IACH,IAAI,IAAI,IAAI;IAQZ;;;OAGG;IACH,gBAAgB,IAAI,IAAI;CAMzB"}
@@ -0,0 +1,110 @@
1
+ import * as crypto from 'node:crypto';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ /**
5
+ * Manages vault seal state — key splitting configuration, unseal key
6
+ * storage, and sealed/unsealed transitions.
7
+ *
8
+ * Modelled after HashiCorp Vault's seal/unseal mechanism, adapted for
9
+ * CLI (non-daemon) usage: the reconstructed key is persisted to a
10
+ * restricted file instead of held in memory.
11
+ *
12
+ * Files managed:
13
+ * .aegis/.seal-config.json — threshold, share count, key hash
14
+ * .aegis/.unseal-key — reconstructed master key (mode 0600)
15
+ */
16
+ export class SealManager {
17
+ dataDir;
18
+ configPath;
19
+ unsealKeyPath;
20
+ constructor(dataDir) {
21
+ this.dataDir = dataDir;
22
+ this.configPath = path.join(dataDir, '.seal-config.json');
23
+ this.unsealKeyPath = path.join(dataDir, '.unseal-key');
24
+ }
25
+ /**
26
+ * Enable key splitting — stores threshold, share count, and a SHA-256
27
+ * hash of the master key for post-reconstruction verification.
28
+ */
29
+ enableSplit(threshold, totalShares, masterKey) {
30
+ if (threshold < 2)
31
+ throw new Error('Threshold must be at least 2.');
32
+ if (totalShares < threshold)
33
+ throw new Error('Total shares must be ≥ threshold.');
34
+ const config = {
35
+ threshold,
36
+ totalShares,
37
+ keyHash: crypto.createHash('sha256').update(masterKey).digest('hex'),
38
+ createdAt: new Date().toISOString(),
39
+ };
40
+ if (!fs.existsSync(this.dataDir)) {
41
+ fs.mkdirSync(this.dataDir, { recursive: true });
42
+ }
43
+ fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2), { mode: 0o600 });
44
+ }
45
+ /** Read seal configuration, or null if key splitting is not configured. */
46
+ getSealConfig() {
47
+ if (!fs.existsSync(this.configPath))
48
+ return null;
49
+ const content = fs.readFileSync(this.configPath, 'utf-8');
50
+ return JSON.parse(content);
51
+ }
52
+ /** Whether key splitting has been configured for this deployment. */
53
+ isSplitEnabled() {
54
+ return this.getSealConfig() !== null;
55
+ }
56
+ /**
57
+ * Verify a reconstructed master key against the stored hash.
58
+ * Uses timing-safe comparison to prevent side-channel leaks.
59
+ */
60
+ verifyKey(masterKey) {
61
+ const config = this.getSealConfig();
62
+ if (!config)
63
+ return false;
64
+ const hash = crypto.createHash('sha256').update(masterKey).digest('hex');
65
+ return crypto.timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(config.keyHash, 'hex'));
66
+ }
67
+ /**
68
+ * Write the reconstructed master key to the unseal key file.
69
+ * File is created with mode 0600 (owner read/write only).
70
+ */
71
+ writeUnsealKey(masterKey) {
72
+ if (!fs.existsSync(this.dataDir)) {
73
+ fs.mkdirSync(this.dataDir, { recursive: true });
74
+ }
75
+ fs.writeFileSync(this.unsealKeyPath, masterKey, { mode: 0o600 });
76
+ }
77
+ /** Read the unseal key, or null if the vault is sealed. */
78
+ readUnsealKey() {
79
+ if (!fs.existsSync(this.unsealKeyPath))
80
+ return null;
81
+ return fs.readFileSync(this.unsealKeyPath, 'utf-8').trim();
82
+ }
83
+ /** Whether the vault is currently unsealed (unseal key file exists). */
84
+ isUnsealed() {
85
+ return fs.existsSync(this.unsealKeyPath);
86
+ }
87
+ /**
88
+ * Seal the vault — securely remove the unseal key file.
89
+ * Overwrites the file with zeros before unlinking (defense in depth
90
+ * against filesystem journal recovery).
91
+ */
92
+ seal() {
93
+ if (fs.existsSync(this.unsealKeyPath)) {
94
+ const stat = fs.statSync(this.unsealKeyPath);
95
+ fs.writeFileSync(this.unsealKeyPath, Buffer.alloc(stat.size, 0));
96
+ fs.unlinkSync(this.unsealKeyPath);
97
+ }
98
+ }
99
+ /**
100
+ * Remove seal configuration entirely — reverts to standard master key mode.
101
+ * Also removes any existing unseal key.
102
+ */
103
+ removeSealConfig() {
104
+ if (fs.existsSync(this.configPath)) {
105
+ fs.unlinkSync(this.configPath);
106
+ }
107
+ this.seal();
108
+ }
109
+ }
110
+ //# sourceMappingURL=seal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal.js","sourceRoot":"","sources":["../../src/vault/seal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /** A single share from Shamir's Secret Sharing. */
2
+ export interface ShamirShare {
3
+ /** Share index (1–255). Each share must have a unique index. */
4
+ index: number;
5
+ /** Share data — same length as the original secret. */
6
+ data: Buffer;
7
+ }
8
+ /**
9
+ * Split a secret into `totalShares` shares, requiring `threshold` to reconstruct.
10
+ *
11
+ * @param secret The secret to split (arbitrary-length Buffer).
12
+ * @param threshold Minimum shares needed for reconstruction (2 ≤ t ≤ n).
13
+ * @param totalShares Number of shares to produce (t ≤ n ≤ 255).
14
+ * @returns Array of shares, each with a unique index and data.
15
+ */
16
+ export declare function split(secret: Buffer, threshold: number, totalShares: number): ShamirShare[];
17
+ /**
18
+ * Reconstruct a secret from shares using Lagrange interpolation at x = 0.
19
+ *
20
+ * @param shares At least `threshold` shares with unique indices.
21
+ * @returns The reconstructed secret.
22
+ */
23
+ export declare function combine(shares: ShamirShare[]): Buffer;
24
+ /**
25
+ * Encode a share as a human-readable string.
26
+ * Format: `aegis_share_<index_hex>_<data_hex>`
27
+ */
28
+ export declare function encodeShare(share: ShamirShare): string;
29
+ /**
30
+ * Decode a share from its string representation.
31
+ */
32
+ export declare function decodeShare(encoded: string): ShamirShare;
33
+ //# sourceMappingURL=shamir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shamir.d.ts","sourceRoot":"","sources":["../../src/vault/shamir.ts"],"names":[],"mappings":"AA8EA,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE,CA4B3F;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAuCrD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAGtD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAuBxD"}