@mstone6969/vault 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -6
- package/dist/crypto.d.ts +99 -2
- package/dist/crypto.d.ts.map +1 -1
- package/dist/errors.d.ts +122 -4
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +447 -33
- package/dist/index.js.map +9 -7
- package/dist/providers.d.ts +131 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/stores/file.d.ts +190 -0
- package/dist/stores/file.d.ts.map +1 -0
- package/dist/stores/file.js +1 -0
- package/dist/stores/memory.d.ts +98 -7
- package/dist/stores/memory.d.ts.map +1 -1
- package/dist/stores/sqlite.d.ts +140 -9
- package/dist/stores/sqlite.d.ts.map +1 -1
- package/dist/stores/sqlite.js +47 -12
- package/dist/stores/sqlite.js.map +3 -3
- package/dist/types.d.ts +408 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/vault.d.ts +554 -19
- package/dist/vault.d.ts.map +1 -1
- package/docs/README.md +10 -0
- package/docs/index/README.md +48 -0
- package/docs/index/classes/FileStore.md +341 -0
- package/docs/index/classes/MemoryStore.md +240 -0
- package/docs/index/classes/Vault.md +805 -0
- package/docs/index/classes/VaultError.md +371 -0
- package/docs/index/classes/VaultKeyError.md +370 -0
- package/docs/index/functions/envKey.md +43 -0
- package/docs/index/functions/fileKey.md +46 -0
- package/docs/index/functions/generateKey.md +39 -0
- package/docs/index/functions/importKey.md +49 -0
- package/docs/index/functions/isKeyProvider.md +43 -0
- package/docs/index/functions/open.md +67 -0
- package/docs/index/functions/randomValue.md +53 -0
- package/docs/index/functions/seal.md +56 -0
- package/docs/index/functions/staticKey.md +39 -0
- package/docs/index/type-aliases/Generator.md +58 -0
- package/docs/index/type-aliases/HistoryEntry.md +65 -0
- package/docs/index/type-aliases/KeyProvider.md +74 -0
- package/docs/index/type-aliases/PutOptions.md +141 -0
- package/docs/index/type-aliases/RekeyReport.md +37 -0
- package/docs/index/type-aliases/RotationContext.md +49 -0
- package/docs/index/type-aliases/RotationPolicy.md +142 -0
- package/docs/index/type-aliases/SecretRecord.md +214 -0
- package/docs/index/type-aliases/SecretSummary.md +56 -0
- package/docs/index/type-aliases/VaultEvent.md +95 -0
- package/docs/index/type-aliases/VaultOptions.md +142 -0
- package/docs/index/type-aliases/VaultStore.md +156 -0
- package/docs/index/variables/DEFAULT_ALPHABET.md +29 -0
- package/docs/index/variables/DEFAULT_HISTORY_LIMIT.md +28 -0
- package/docs/index/variables/DEFAULT_PREFIX.md +23 -0
- package/docs/stores/sqlite/README.md +11 -0
- package/docs/stores/sqlite/classes/SqliteStore.md +307 -0
- package/package.json +15 -5
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
[**@mstone6969/vault**](../../README.md)
|
|
2
|
+
|
|
3
|
+
***
|
|
4
|
+
|
|
5
|
+
[@mstone6969/vault](../../README.md) / [index](../README.md) / Vault
|
|
6
|
+
|
|
7
|
+
# Class: Vault
|
|
8
|
+
|
|
9
|
+
Defined in: cron/vault/src/vault.ts:265
|
|
10
|
+
|
|
11
|
+
A write-only credential store: values go in, and only `open`, `read` and
|
|
12
|
+
`resolve` take them out again.
|
|
13
|
+
|
|
14
|
+
Every value is sealed under its own data key, and only that key is sealed
|
|
15
|
+
under the master key. Changing the master key therefore re-seals a handful of
|
|
16
|
+
bytes per entry rather than every value, and one exposed data key exposes one
|
|
17
|
+
value rather than all of them.
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
**Storing a credential and handing it to the thing that needs it**
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Vault, MemoryStore, generateKey } from "@mstone6969/vault"
|
|
25
|
+
|
|
26
|
+
const vault = new Vault({ key: generateKey(), store: new MemoryStore() })
|
|
27
|
+
|
|
28
|
+
await vault.put("alice", "stripe_key", "sk_live_x", {
|
|
29
|
+
metadata: { kind: "api" },
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Nothing but open, read and resolve gets the value back out.
|
|
33
|
+
await vault.list("alice") // name, metadata, dates — no value
|
|
34
|
+
await vault.open("alice", "stripe_key")
|
|
35
|
+
await vault.resolve("alice", { STRIPE_KEY: "@vault:stripe_key" })
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## See
|
|
39
|
+
|
|
40
|
+
[VaultOptions](../type-aliases/VaultOptions.md) for what it is built from, [VaultStore](../type-aliases/VaultStore.md) for
|
|
41
|
+
where the records go, and [VaultError](VaultError.md) for what it throws.
|
|
42
|
+
|
|
43
|
+
## Constructors
|
|
44
|
+
|
|
45
|
+
### Constructor
|
|
46
|
+
|
|
47
|
+
> **new Vault**(`options`): `Vault`
|
|
48
|
+
|
|
49
|
+
Defined in: cron/vault/src/vault.ts:285
|
|
50
|
+
|
|
51
|
+
#### Parameters
|
|
52
|
+
|
|
53
|
+
##### options
|
|
54
|
+
|
|
55
|
+
[`VaultOptions`](../type-aliases/VaultOptions.md)
|
|
56
|
+
|
|
57
|
+
The key, the store and the policies this vault applies.
|
|
58
|
+
Nothing is contacted here: the key is resolved on first use, so a vault
|
|
59
|
+
built from a provider that is slow or unreachable costs nothing until
|
|
60
|
+
something asks it for a value.
|
|
61
|
+
|
|
62
|
+
#### Returns
|
|
63
|
+
|
|
64
|
+
`Vault`
|
|
65
|
+
|
|
66
|
+
## Properties
|
|
67
|
+
|
|
68
|
+
### prefix
|
|
69
|
+
|
|
70
|
+
> `readonly` **prefix**: `string`
|
|
71
|
+
|
|
72
|
+
Defined in: cron/vault/src/vault.ts:277
|
|
73
|
+
|
|
74
|
+
The prefix [Vault.resolve](#resolve) treats as a reference.
|
|
75
|
+
|
|
76
|
+
## Methods
|
|
77
|
+
|
|
78
|
+
### list()
|
|
79
|
+
|
|
80
|
+
> **list**(`owner`): `Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)[]\>
|
|
81
|
+
|
|
82
|
+
Defined in: cron/vault/src/vault.ts:393
|
|
83
|
+
|
|
84
|
+
Everything an owner holds, sorted by name. Never a sealed value.
|
|
85
|
+
|
|
86
|
+
#### Parameters
|
|
87
|
+
|
|
88
|
+
##### owner
|
|
89
|
+
|
|
90
|
+
`string`
|
|
91
|
+
|
|
92
|
+
Whose entries to list.
|
|
93
|
+
|
|
94
|
+
#### Returns
|
|
95
|
+
|
|
96
|
+
`Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)[]\>
|
|
97
|
+
|
|
98
|
+
One summary per entry, in name order. A sealed value is absent
|
|
99
|
+
entirely; an entry stored in the open carries its value in `value`.
|
|
100
|
+
|
|
101
|
+
#### Remarks
|
|
102
|
+
|
|
103
|
+
Expiry hides nothing here: an entry past its `expiresAt` is still listed,
|
|
104
|
+
and still refuses to open, until [Vault.purgeExpired](#purgeexpired) clears it.
|
|
105
|
+
|
|
106
|
+
#### Example
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
await vault.put("alice", "stripe_key", "sk_live_x", {
|
|
110
|
+
metadata: { kind: "api" },
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const [entry] = await vault.list("alice")
|
|
114
|
+
entry.name // "stripe_key"
|
|
115
|
+
entry.metadata // { kind: "api" }
|
|
116
|
+
entry.versions // 0
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### See
|
|
120
|
+
|
|
121
|
+
[SecretSummary](../type-aliases/SecretSummary.md)
|
|
122
|
+
|
|
123
|
+
***
|
|
124
|
+
|
|
125
|
+
### put()
|
|
126
|
+
|
|
127
|
+
> **put**(`owner`, `name`, `value`, `options?`): `Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)\>
|
|
128
|
+
|
|
129
|
+
Defined in: cron/vault/src/vault.ts:432
|
|
130
|
+
|
|
131
|
+
Stores a value, replacing whatever was under that name.
|
|
132
|
+
|
|
133
|
+
`metadata` is kept in the clear and comes back from `list`, so it must
|
|
134
|
+
hold nothing secret — a credential's kind, or the username it belongs to,
|
|
135
|
+
not the password.
|
|
136
|
+
|
|
137
|
+
#### Parameters
|
|
138
|
+
|
|
139
|
+
##### owner
|
|
140
|
+
|
|
141
|
+
`string`
|
|
142
|
+
|
|
143
|
+
Whose entry it is. Owners never see each other's entries.
|
|
144
|
+
|
|
145
|
+
##### name
|
|
146
|
+
|
|
147
|
+
`string`
|
|
148
|
+
|
|
149
|
+
What to call it: 1-64 characters of letters, numbers, dot,
|
|
150
|
+
dash or underscore. Surrounding whitespace is trimmed.
|
|
151
|
+
|
|
152
|
+
##### value
|
|
153
|
+
|
|
154
|
+
`string`
|
|
155
|
+
|
|
156
|
+
The value to store.
|
|
157
|
+
|
|
158
|
+
##### options?
|
|
159
|
+
|
|
160
|
+
[`PutOptions`](../type-aliases/PutOptions.md) = `{}`
|
|
161
|
+
|
|
162
|
+
Metadata, expiry, rotation policy, and whether the entry
|
|
163
|
+
is sealed, final, or keeps what it replaces. An option left out is
|
|
164
|
+
inherited from the existing entry.
|
|
165
|
+
|
|
166
|
+
#### Returns
|
|
167
|
+
|
|
168
|
+
`Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)\>
|
|
169
|
+
|
|
170
|
+
The stored entry, summarised — never its sealed value.
|
|
171
|
+
|
|
172
|
+
#### Throws
|
|
173
|
+
|
|
174
|
+
[VaultError](VaultError.md) 422 when the name is not 1-64 characters of
|
|
175
|
+
letters, numbers, dot, dash or underscore, or the value is empty.
|
|
176
|
+
|
|
177
|
+
#### Throws
|
|
178
|
+
|
|
179
|
+
[VaultError](VaultError.md) 409 when the entry is already there and
|
|
180
|
+
`final`: it can be deleted, never replaced.
|
|
181
|
+
|
|
182
|
+
#### Example
|
|
183
|
+
|
|
184
|
+
**Replacing a value without restating what the entry is**
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
await vault.put("alice", "db", "first-password", {
|
|
188
|
+
metadata: { kind: "login", username: "ada" },
|
|
189
|
+
rotation: { kind: "random", length: 24 },
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// Still a login, still rotatable at 24 characters, still sealed.
|
|
193
|
+
await vault.put("alice", "db", "second-password")
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### See
|
|
197
|
+
|
|
198
|
+
[Vault.rotate](#rotate) to replace a value and keep the old one,
|
|
199
|
+
[PutOptions](../type-aliases/PutOptions.md) for the rest of the options.
|
|
200
|
+
|
|
201
|
+
***
|
|
202
|
+
|
|
203
|
+
### rotate()
|
|
204
|
+
|
|
205
|
+
> **rotate**(`owner`, `name`, `value?`, `options?`): `Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)\>
|
|
206
|
+
|
|
207
|
+
Defined in: cron/vault/src/vault.ts:535
|
|
208
|
+
|
|
209
|
+
Replaces a value, keeping the one it replaces.
|
|
210
|
+
|
|
211
|
+
Called without a value, the entry's rotation policy produces one — which
|
|
212
|
+
is the point of storing a policy: whatever runs the rotation is told how
|
|
213
|
+
to make the next password, never what the current one is.
|
|
214
|
+
|
|
215
|
+
Previous values stay openable, so a job that read the credential moments
|
|
216
|
+
before a rotation can still finish on what it was given.
|
|
217
|
+
|
|
218
|
+
#### Parameters
|
|
219
|
+
|
|
220
|
+
##### owner
|
|
221
|
+
|
|
222
|
+
`string`
|
|
223
|
+
|
|
224
|
+
Whose entry to rotate.
|
|
225
|
+
|
|
226
|
+
##### name
|
|
227
|
+
|
|
228
|
+
`string`
|
|
229
|
+
|
|
230
|
+
The entry to rotate.
|
|
231
|
+
|
|
232
|
+
##### value?
|
|
233
|
+
|
|
234
|
+
`string`
|
|
235
|
+
|
|
236
|
+
The new value. Left out, the entry's rotation policy makes
|
|
237
|
+
one.
|
|
238
|
+
|
|
239
|
+
##### options?
|
|
240
|
+
|
|
241
|
+
`Omit`\<[`PutOptions`](../type-aliases/PutOptions.md), `"keepHistory"`\> = `{}`
|
|
242
|
+
|
|
243
|
+
As [Vault.put](#put), minus `keepHistory`: a rotation
|
|
244
|
+
always keeps what it replaced, up to [VaultOptions.historyLimit](../type-aliases/VaultOptions.md#historylimit).
|
|
245
|
+
|
|
246
|
+
#### Returns
|
|
247
|
+
|
|
248
|
+
`Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)\>
|
|
249
|
+
|
|
250
|
+
The rotated entry, summarised, with `rotatedAt` stamped.
|
|
251
|
+
|
|
252
|
+
#### Throws
|
|
253
|
+
|
|
254
|
+
[VaultError](VaultError.md) 404 when no value is given and there is no
|
|
255
|
+
such entry to take a policy from.
|
|
256
|
+
|
|
257
|
+
#### Throws
|
|
258
|
+
|
|
259
|
+
[VaultError](VaultError.md) 410 when no value is given and the entry has
|
|
260
|
+
expired.
|
|
261
|
+
|
|
262
|
+
#### Throws
|
|
263
|
+
|
|
264
|
+
[VaultError](VaultError.md) 422 when no value is given and the entry has
|
|
265
|
+
no rotation policy to make one with.
|
|
266
|
+
|
|
267
|
+
#### Throws
|
|
268
|
+
|
|
269
|
+
[VaultError](VaultError.md) 501 when the policy names a generator this
|
|
270
|
+
vault was not constructed with.
|
|
271
|
+
|
|
272
|
+
#### Throws
|
|
273
|
+
|
|
274
|
+
[VaultError](VaultError.md) 409 when the entry is final.
|
|
275
|
+
|
|
276
|
+
#### Example
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
await vault.put("alice", "db", "first-password", {
|
|
280
|
+
rotation: { kind: "random", length: 24 },
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
const rotated = await vault.rotate("alice", "db")
|
|
284
|
+
rotated.rotatedAt // stamped just now
|
|
285
|
+
await vault.versions("alice", "db") // ["first-password"]
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### See
|
|
289
|
+
|
|
290
|
+
[Vault.rotationDue](#rotationdue) for which entries are asking for this.
|
|
291
|
+
|
|
292
|
+
***
|
|
293
|
+
|
|
294
|
+
### rotationDue()
|
|
295
|
+
|
|
296
|
+
> **rotationDue**(`now?`): `Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)[]\>
|
|
297
|
+
|
|
298
|
+
Defined in: cron/vault/src/vault.ts:603
|
|
299
|
+
|
|
300
|
+
Entries whose policy says how often they want rotating, and whose time
|
|
301
|
+
has come. Nothing rotates them for you — schedule this and act on it.
|
|
302
|
+
|
|
303
|
+
#### Parameters
|
|
304
|
+
|
|
305
|
+
##### now?
|
|
306
|
+
|
|
307
|
+
`Date` = `...`
|
|
308
|
+
|
|
309
|
+
The moment to judge against. Pass a later one to ask what will
|
|
310
|
+
be due by then.
|
|
311
|
+
|
|
312
|
+
#### Returns
|
|
313
|
+
|
|
314
|
+
`Promise`\<[`SecretSummary`](../type-aliases/SecretSummary.md)[]\>
|
|
315
|
+
|
|
316
|
+
Summaries of every entry, whoever owns it, whose
|
|
317
|
+
[RotationPolicy.every](../type-aliases/RotationPolicy.md#every) seconds have passed since it was last
|
|
318
|
+
rotated — or since it was stored, if it never has been.
|
|
319
|
+
|
|
320
|
+
#### Remarks
|
|
321
|
+
|
|
322
|
+
One of the three calls that reach across owners, so it belongs to
|
|
323
|
+
whatever runs the schedule rather than to a request.
|
|
324
|
+
|
|
325
|
+
#### Example
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
await vault.put("alice", "db", "x", {
|
|
329
|
+
rotation: { kind: "random", every: 86_400 },
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
for (const entry of await vault.rotationDue()) {
|
|
333
|
+
await vault.rotate(entry.owner, entry.name)
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
***
|
|
338
|
+
|
|
339
|
+
### versions()
|
|
340
|
+
|
|
341
|
+
> **versions**(`owner`, `name`): `Promise`\<`string`[]\>
|
|
342
|
+
|
|
343
|
+
Defined in: cron/vault/src/vault.ts:637
|
|
344
|
+
|
|
345
|
+
Previous values of an entry, newest first, opened.
|
|
346
|
+
|
|
347
|
+
#### Parameters
|
|
348
|
+
|
|
349
|
+
##### owner
|
|
350
|
+
|
|
351
|
+
`string`
|
|
352
|
+
|
|
353
|
+
Whose entry it is.
|
|
354
|
+
|
|
355
|
+
##### name
|
|
356
|
+
|
|
357
|
+
`string`
|
|
358
|
+
|
|
359
|
+
The entry to look back through.
|
|
360
|
+
|
|
361
|
+
#### Returns
|
|
362
|
+
|
|
363
|
+
`Promise`\<`string`[]\>
|
|
364
|
+
|
|
365
|
+
The values it used to hold, newest first, in the clear. Empty
|
|
366
|
+
for an entry that has never been rotated.
|
|
367
|
+
|
|
368
|
+
#### Throws
|
|
369
|
+
|
|
370
|
+
[VaultError](VaultError.md) 404 when there is no such entry.
|
|
371
|
+
|
|
372
|
+
#### Throws
|
|
373
|
+
|
|
374
|
+
[VaultError](VaultError.md) 410 when the entry has expired.
|
|
375
|
+
|
|
376
|
+
#### Throws
|
|
377
|
+
|
|
378
|
+
[VaultError](VaultError.md) 422 when the name is not a legal one.
|
|
379
|
+
|
|
380
|
+
#### Throws
|
|
381
|
+
|
|
382
|
+
[VaultKeyError](VaultKeyError.md) 500 when a kept value will not open under
|
|
383
|
+
the master key or any of [VaultOptions.previousKeys](../type-aliases/VaultOptions.md#previouskeys).
|
|
384
|
+
|
|
385
|
+
#### Example
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
await vault.put("alice", "deploy", "v1")
|
|
389
|
+
await vault.rotate("alice", "deploy", "v2")
|
|
390
|
+
await vault.rotate("alice", "deploy", "v3")
|
|
391
|
+
|
|
392
|
+
await vault.versions("alice", "deploy") // ["v2", "v1"]
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
***
|
|
396
|
+
|
|
397
|
+
### has()
|
|
398
|
+
|
|
399
|
+
> **has**(`owner`, `name`): `Promise`\<`boolean`\>
|
|
400
|
+
|
|
401
|
+
Defined in: cron/vault/src/vault.ts:656
|
|
402
|
+
|
|
403
|
+
True when the owner has a secret under that name, expired or not.
|
|
404
|
+
|
|
405
|
+
#### Parameters
|
|
406
|
+
|
|
407
|
+
##### owner
|
|
408
|
+
|
|
409
|
+
`string`
|
|
410
|
+
|
|
411
|
+
Whose entry to look for.
|
|
412
|
+
|
|
413
|
+
##### name
|
|
414
|
+
|
|
415
|
+
`string`
|
|
416
|
+
|
|
417
|
+
The name to look for.
|
|
418
|
+
|
|
419
|
+
#### Returns
|
|
420
|
+
|
|
421
|
+
`Promise`\<`boolean`\>
|
|
422
|
+
|
|
423
|
+
Whether a record exists under it.
|
|
424
|
+
|
|
425
|
+
#### Throws
|
|
426
|
+
|
|
427
|
+
[VaultError](VaultError.md) 422 when the name is not a legal one.
|
|
428
|
+
|
|
429
|
+
#### Remarks
|
|
430
|
+
|
|
431
|
+
Opens nothing and is not stopped by expiry, so it answers "is this name
|
|
432
|
+
taken" rather than "can this value still be used".
|
|
433
|
+
|
|
434
|
+
***
|
|
435
|
+
|
|
436
|
+
### remove()
|
|
437
|
+
|
|
438
|
+
> **remove**(`owner`, `name`): `Promise`\<`boolean`\>
|
|
439
|
+
|
|
440
|
+
Defined in: cron/vault/src/vault.ts:673
|
|
441
|
+
|
|
442
|
+
Removes a secret, returning false if it wasn't there.
|
|
443
|
+
|
|
444
|
+
#### Parameters
|
|
445
|
+
|
|
446
|
+
##### owner
|
|
447
|
+
|
|
448
|
+
`string`
|
|
449
|
+
|
|
450
|
+
Whose entry to delete.
|
|
451
|
+
|
|
452
|
+
##### name
|
|
453
|
+
|
|
454
|
+
`string`
|
|
455
|
+
|
|
456
|
+
The entry to delete.
|
|
457
|
+
|
|
458
|
+
#### Returns
|
|
459
|
+
|
|
460
|
+
`Promise`\<`boolean`\>
|
|
461
|
+
|
|
462
|
+
True when something was deleted, false when there was nothing
|
|
463
|
+
under that name.
|
|
464
|
+
|
|
465
|
+
#### Throws
|
|
466
|
+
|
|
467
|
+
[VaultError](VaultError.md) 422 when the name is not a legal one.
|
|
468
|
+
|
|
469
|
+
#### Remarks
|
|
470
|
+
|
|
471
|
+
Deleting takes the kept previous values with it, and it is the one thing
|
|
472
|
+
a `final` entry allows.
|
|
473
|
+
|
|
474
|
+
***
|
|
475
|
+
|
|
476
|
+
### open()
|
|
477
|
+
|
|
478
|
+
> **open**(`owner`, `name`): `Promise`\<`string`\>
|
|
479
|
+
|
|
480
|
+
Defined in: cron/vault/src/vault.ts:719
|
|
481
|
+
|
|
482
|
+
Reads one value back. The only way plaintext leaves a sealed entry — keep
|
|
483
|
+
it in memory and out of logs and responses.
|
|
484
|
+
|
|
485
|
+
#### Parameters
|
|
486
|
+
|
|
487
|
+
##### owner
|
|
488
|
+
|
|
489
|
+
`string`
|
|
490
|
+
|
|
491
|
+
Whose entry to open.
|
|
492
|
+
|
|
493
|
+
##### name
|
|
494
|
+
|
|
495
|
+
`string`
|
|
496
|
+
|
|
497
|
+
The entry to open.
|
|
498
|
+
|
|
499
|
+
#### Returns
|
|
500
|
+
|
|
501
|
+
`Promise`\<`string`\>
|
|
502
|
+
|
|
503
|
+
The value, sealed or not.
|
|
504
|
+
|
|
505
|
+
#### Throws
|
|
506
|
+
|
|
507
|
+
[VaultError](VaultError.md) 404 when there is no such entry.
|
|
508
|
+
|
|
509
|
+
#### Throws
|
|
510
|
+
|
|
511
|
+
[VaultError](VaultError.md) 410 when the entry has expired. The record is
|
|
512
|
+
still there; it just cannot be used.
|
|
513
|
+
|
|
514
|
+
#### Throws
|
|
515
|
+
|
|
516
|
+
[VaultError](VaultError.md) 422 when the name is not a legal one.
|
|
517
|
+
|
|
518
|
+
#### Throws
|
|
519
|
+
|
|
520
|
+
[VaultKeyError](VaultKeyError.md) 500 when the value will not open under the
|
|
521
|
+
master key or any of [VaultOptions.previousKeys](../type-aliases/VaultOptions.md#previouskeys) — a wrong key or
|
|
522
|
+
an altered value, which GCM cannot tell apart.
|
|
523
|
+
|
|
524
|
+
#### Example
|
|
525
|
+
|
|
526
|
+
```ts
|
|
527
|
+
await vault.put("alice", "token", "shhh")
|
|
528
|
+
await vault.open("alice", "token") // "shhh"
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
#### See
|
|
532
|
+
|
|
533
|
+
[Vault.read](#read) for entries stored in the open,
|
|
534
|
+
[Vault.resolve](#resolve) for substituting several at once.
|
|
535
|
+
|
|
536
|
+
***
|
|
537
|
+
|
|
538
|
+
### read()
|
|
539
|
+
|
|
540
|
+
> **read**(`owner`, `name`): `Promise`\<`string`\>
|
|
541
|
+
|
|
542
|
+
Defined in: cron/vault/src/vault.ts:751
|
|
543
|
+
|
|
544
|
+
Reads an entry stored in the open. A sealed one refuses.
|
|
545
|
+
|
|
546
|
+
#### Parameters
|
|
547
|
+
|
|
548
|
+
##### owner
|
|
549
|
+
|
|
550
|
+
`string`
|
|
551
|
+
|
|
552
|
+
Whose entry to read.
|
|
553
|
+
|
|
554
|
+
##### name
|
|
555
|
+
|
|
556
|
+
`string`
|
|
557
|
+
|
|
558
|
+
The entry to read.
|
|
559
|
+
|
|
560
|
+
#### Returns
|
|
561
|
+
|
|
562
|
+
`Promise`\<`string`\>
|
|
563
|
+
|
|
564
|
+
The value, which was stored with `open: true` and was therefore
|
|
565
|
+
never secret.
|
|
566
|
+
|
|
567
|
+
#### Throws
|
|
568
|
+
|
|
569
|
+
[VaultError](VaultError.md) 403 when the entry is sealed.
|
|
570
|
+
[Vault.open](#open) is the only way a sealed value comes out.
|
|
571
|
+
|
|
572
|
+
#### Throws
|
|
573
|
+
|
|
574
|
+
[VaultError](VaultError.md) 404 when there is no such entry.
|
|
575
|
+
|
|
576
|
+
#### Throws
|
|
577
|
+
|
|
578
|
+
[VaultError](VaultError.md) 410 when the entry has expired.
|
|
579
|
+
|
|
580
|
+
#### Throws
|
|
581
|
+
|
|
582
|
+
[VaultError](VaultError.md) 422 when the name is not a legal one.
|
|
583
|
+
|
|
584
|
+
#### Example
|
|
585
|
+
|
|
586
|
+
```ts
|
|
587
|
+
await vault.put("alice", "region", "eu-west-1", { open: true })
|
|
588
|
+
await vault.read("alice", "region") // "eu-west-1"
|
|
589
|
+
|
|
590
|
+
await vault.put("alice", "token", "shhh")
|
|
591
|
+
await vault.read("alice", "token") // throws: 403, sealed
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
***
|
|
595
|
+
|
|
596
|
+
### resolve()
|
|
597
|
+
|
|
598
|
+
> **resolve**(`owner`, `values`): `Promise`\<`Record`\<`string`, `string`\>\>
|
|
599
|
+
|
|
600
|
+
Defined in: cron/vault/src/vault.ts:794
|
|
601
|
+
|
|
602
|
+
Substitutes `@vault:<name>` references in a set of values — an
|
|
603
|
+
environment, a config object — leaving everything else alone.
|
|
604
|
+
|
|
605
|
+
A reference to a secret that isn't there, or that has expired, throws:
|
|
606
|
+
running with a blank credential is worse than not running.
|
|
607
|
+
|
|
608
|
+
#### Parameters
|
|
609
|
+
|
|
610
|
+
##### owner
|
|
611
|
+
|
|
612
|
+
`string`
|
|
613
|
+
|
|
614
|
+
Whose entries the references name.
|
|
615
|
+
|
|
616
|
+
##### values
|
|
617
|
+
|
|
618
|
+
`Record`\<`string`, `string`\>
|
|
619
|
+
|
|
620
|
+
The set to substitute into. Not modified.
|
|
621
|
+
|
|
622
|
+
#### Returns
|
|
623
|
+
|
|
624
|
+
`Promise`\<`Record`\<`string`, `string`\>\>
|
|
625
|
+
|
|
626
|
+
A copy with every reference replaced by its value, or the same
|
|
627
|
+
object back when nothing in it is a reference.
|
|
628
|
+
|
|
629
|
+
#### Throws
|
|
630
|
+
|
|
631
|
+
[VaultError](VaultError.md) 404 when a reference names no entry.
|
|
632
|
+
|
|
633
|
+
#### Throws
|
|
634
|
+
|
|
635
|
+
[VaultError](VaultError.md) 410 when a referenced entry has expired.
|
|
636
|
+
|
|
637
|
+
#### Throws
|
|
638
|
+
|
|
639
|
+
[VaultError](VaultError.md) 422 when what follows the prefix is not a
|
|
640
|
+
legal name.
|
|
641
|
+
|
|
642
|
+
#### Remarks
|
|
643
|
+
|
|
644
|
+
Whitespace around the name is ignored, so `"@vault: token "` finds
|
|
645
|
+
`token`. Sealed and open entries both resolve; the prefix comes from
|
|
646
|
+
[Vault.prefix](#prefix).
|
|
647
|
+
|
|
648
|
+
#### Example
|
|
649
|
+
|
|
650
|
+
**Filling in an environment before spawning something**
|
|
651
|
+
|
|
652
|
+
```ts
|
|
653
|
+
await vault.put("alice", "token", "secret")
|
|
654
|
+
|
|
655
|
+
await vault.resolve("alice", {
|
|
656
|
+
PLAIN: "kept",
|
|
657
|
+
API_TOKEN: "@vault:token",
|
|
658
|
+
})
|
|
659
|
+
// { PLAIN: "kept", API_TOKEN: "secret" }
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
***
|
|
663
|
+
|
|
664
|
+
### reseal()
|
|
665
|
+
|
|
666
|
+
> **reseal**(`owner?`): `Promise`\<`number`\>
|
|
667
|
+
|
|
668
|
+
Defined in: cron/vault/src/vault.ts:830
|
|
669
|
+
|
|
670
|
+
Re-seals values under fresh data keys, without changing the master key.
|
|
671
|
+
|
|
672
|
+
Cheap hygiene: the ciphertext of an unchanged secret stops being
|
|
673
|
+
comparable between two copies of the database taken at different times.
|
|
674
|
+
|
|
675
|
+
#### Parameters
|
|
676
|
+
|
|
677
|
+
##### owner?
|
|
678
|
+
|
|
679
|
+
`string`
|
|
680
|
+
|
|
681
|
+
Limit it to one owner's entries. Left out, it walks the
|
|
682
|
+
whole store, whoever owns it.
|
|
683
|
+
|
|
684
|
+
#### Returns
|
|
685
|
+
|
|
686
|
+
`Promise`\<`number`\>
|
|
687
|
+
|
|
688
|
+
How many entries were re-sealed. Entries stored in the open hold
|
|
689
|
+
nothing to re-seal and are skipped.
|
|
690
|
+
|
|
691
|
+
#### Throws
|
|
692
|
+
|
|
693
|
+
[VaultKeyError](VaultKeyError.md) 500 when a value will not open. Unlike
|
|
694
|
+
[Vault.rekey](#rekey) this stops there, having already re-sealed the
|
|
695
|
+
entries it got to — those are unharmed, since the key did not change.
|
|
696
|
+
|
|
697
|
+
#### Example
|
|
698
|
+
|
|
699
|
+
```ts
|
|
700
|
+
await vault.reseal("alice") // just this owner
|
|
701
|
+
await vault.reseal() // the whole store
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
***
|
|
705
|
+
|
|
706
|
+
### rekey()
|
|
707
|
+
|
|
708
|
+
> **rekey**(`next`): `Promise`\<[`RekeyReport`](../type-aliases/RekeyReport.md)\>
|
|
709
|
+
|
|
710
|
+
Defined in: cron/vault/src/vault.ts:879
|
|
711
|
+
|
|
712
|
+
Re-seals every data key under a new master key.
|
|
713
|
+
|
|
714
|
+
The old key is kept as a fallback for the rest of this vault's life, so a
|
|
715
|
+
run that stops halfway leaves a mix that still opens. Construct the next
|
|
716
|
+
vault with `key: next, previousKeys: [old]` until you are confident, then
|
|
717
|
+
drop the old one.
|
|
718
|
+
|
|
719
|
+
An entry that will not open is left untouched and named in the report,
|
|
720
|
+
because re-sealing what you cannot read would only destroy it.
|
|
721
|
+
|
|
722
|
+
#### Parameters
|
|
723
|
+
|
|
724
|
+
##### next
|
|
725
|
+
|
|
726
|
+
`string` \| `CryptoKey` \| [`KeyProvider`](../type-aliases/KeyProvider.md)
|
|
727
|
+
|
|
728
|
+
The new master key: base64, already imported, or a provider
|
|
729
|
+
that finds one.
|
|
730
|
+
|
|
731
|
+
#### Returns
|
|
732
|
+
|
|
733
|
+
`Promise`\<[`RekeyReport`](../type-aliases/RekeyReport.md)\>
|
|
734
|
+
|
|
735
|
+
How many entries moved, and which would not, by `owner/name`.
|
|
736
|
+
|
|
737
|
+
#### Throws
|
|
738
|
+
|
|
739
|
+
[VaultKeyError](VaultKeyError.md) 500 when `next` is not a usable key. It is
|
|
740
|
+
resolved before anything is written, so nothing has changed.
|
|
741
|
+
|
|
742
|
+
#### Remarks
|
|
743
|
+
|
|
744
|
+
Walks every owner, and changes this vault as it goes: from here on it
|
|
745
|
+
seals under `next` and keeps the key it had as a fallback. An entry
|
|
746
|
+
stored in the open holds no key and is skipped, and one written before
|
|
747
|
+
envelope encryption is given a data key on the way past.
|
|
748
|
+
|
|
749
|
+
#### Example
|
|
750
|
+
|
|
751
|
+
```ts
|
|
752
|
+
const next = generateKey()
|
|
753
|
+
const report = await vault.rekey(next)
|
|
754
|
+
report.rekeyed // 2
|
|
755
|
+
report.failed // ["alice/stranger"] — left exactly as they were
|
|
756
|
+
|
|
757
|
+
// Until the failures are dealt with, keep the old key readable.
|
|
758
|
+
const moved = new Vault({ key: next, store, previousKeys: [old] })
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
#### See
|
|
762
|
+
|
|
763
|
+
[RekeyReport](../type-aliases/RekeyReport.md), [VaultOptions.previousKeys](../type-aliases/VaultOptions.md#previouskeys)
|
|
764
|
+
|
|
765
|
+
***
|
|
766
|
+
|
|
767
|
+
### purgeExpired()
|
|
768
|
+
|
|
769
|
+
> **purgeExpired**(`now?`): `Promise`\<`number`\>
|
|
770
|
+
|
|
771
|
+
Defined in: cron/vault/src/vault.ts:968
|
|
772
|
+
|
|
773
|
+
Deletes entries whose time is up. Returns how many went.
|
|
774
|
+
|
|
775
|
+
#### Parameters
|
|
776
|
+
|
|
777
|
+
##### now?
|
|
778
|
+
|
|
779
|
+
`Date` = `...`
|
|
780
|
+
|
|
781
|
+
The moment to judge against. Pass a later one to see what a
|
|
782
|
+
run then would take.
|
|
783
|
+
|
|
784
|
+
#### Returns
|
|
785
|
+
|
|
786
|
+
`Promise`\<`number`\>
|
|
787
|
+
|
|
788
|
+
How many entries were deleted.
|
|
789
|
+
|
|
790
|
+
#### Remarks
|
|
791
|
+
|
|
792
|
+
Walks every owner. Expiry stops an entry being used, not being stored:
|
|
793
|
+
until this runs, an expired entry is still there and still listed.
|
|
794
|
+
|
|
795
|
+
#### Example
|
|
796
|
+
|
|
797
|
+
```ts
|
|
798
|
+
await vault.put("alice", "temporary", "x", {
|
|
799
|
+
expiresAt: new Date(Date.now() - 1),
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
await vault.open("alice", "temporary") // throws: 410, expired
|
|
803
|
+
await vault.purgeExpired() // 1
|
|
804
|
+
await vault.has("alice", "temporary") // false
|
|
805
|
+
```
|