@coffre/vault 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cloudflare.d.ts +5 -8
- package/dist/cloudflare.js +2 -2
- package/dist/{index-CGVAd1mz.d.ts → index-CwsWOH6j.d.ts} +27 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +2 -2
- package/dist/{src-1yVV2L0_.js → src-CQJS3OZZ.js} +10 -10
- package/dist/{vault-CP8yU8xq.js → vault-ihE3Yc4a.js} +247 -189
- package/package.json +3 -3
- package/src/cloudflare.ts +1 -1
- package/src/config.ts +45 -19
- package/src/store.ts +20 -35
- package/src/vault.ts +244 -138
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ import { postgres, vault } from '@coffre/vault/cloudflare';
|
|
|
11
11
|
export default vault((env) => ({
|
|
12
12
|
database: postgres(env.VAULT_HYPERDRIVE), // coffre_vault_runtime, caching disabled
|
|
13
13
|
kek: { id: env.VAULT_KEY_ID, key: env.VAULT_KEY }, // or awsKms({ keyArn, credentials }), with a signingKey
|
|
14
|
-
|
|
14
|
+
owners: env.OWNERS.split(','), // Owners of the whole instance, whom nobody demotes while named
|
|
15
15
|
}));
|
|
16
16
|
```
|
|
17
17
|
|
package/dist/cloudflare.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as KekUnavailableError, c as awsKms, d as Kek, f as VaultConfig, i as KekProvider, l as checkpointMessage, n as AwsKmsOptions, o as SecretContext, p as derivedSigningKey, r as KekBadClaimError, s as WrappedDek, t as AwsCredentials, u as verifyCheckpoint } from "./index-
|
|
1
|
+
import { a as KekUnavailableError, c as awsKms, d as Kek, f as VaultConfig, i as KekProvider, l as checkpointMessage, n as AwsKmsOptions, o as SecretContext, p as derivedSigningKey, r as KekBadClaimError, s as WrappedDek, t as AwsCredentials, u as verifyCheckpoint } from "./index-CwsWOH6j.js";
|
|
2
2
|
import { AdmitInput, EndReferencesInput, ReferenceInput, RemoveInput, RewrapInput, SetAccessInput, SetSettingsInput, UnwrapInput, Vault, VerifyLogInput, WrapInput } from "@coffre/core/vault";
|
|
3
3
|
import { PostgresDatabase, PostgresDatabase as PostgresDatabase$1, postgres } from "@coffre/db/hyperdrive";
|
|
4
4
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
@@ -36,13 +36,9 @@ export declare class VaultEntrypoint extends WorkerEntrypoint implements Vault {
|
|
|
36
36
|
access(principal: string): Promise<import("@coffre/core/vault").Access>;
|
|
37
37
|
setAccess(input: SetAccessInput): Promise<import("@coffre/core/vault").Outcome<{
|
|
38
38
|
changes: import("@coffre/core/vault").AccessChange[];
|
|
39
|
+
admitted?: import("@coffre/core/vault").Admitted;
|
|
39
40
|
}>>;
|
|
40
|
-
admit(input: AdmitInput): Promise<import("@coffre/core/vault").Outcome<
|
|
41
|
-
created: boolean;
|
|
42
|
-
role: import("@coffre/core/access").InstanceRole;
|
|
43
|
-
scope: import("@coffre/core/access").Scope;
|
|
44
|
-
generation: number;
|
|
45
|
-
}>>;
|
|
41
|
+
admit(input: AdmitInput): Promise<import("@coffre/core/vault").Outcome<import("@coffre/core/vault").Admitted>>;
|
|
46
42
|
remove(input: RemoveInput): Promise<import("@coffre/core/vault").Outcome<{
|
|
47
43
|
revoked: import("@coffre/core/vault").Grant[];
|
|
48
44
|
generation: number;
|
|
@@ -56,7 +52,8 @@ export declare class VaultEntrypoint extends WorkerEntrypoint implements Vault {
|
|
|
56
52
|
}>>;
|
|
57
53
|
about(): Promise<{
|
|
58
54
|
checkpointKeys: Record<string, import("@coffre/core/vault").CheckpointKey>;
|
|
59
|
-
|
|
55
|
+
owners?: string[];
|
|
56
|
+
rootAdmins: [];
|
|
60
57
|
}>;
|
|
61
58
|
keyChecks(): Promise<import("@coffre/core/vault").KeyChecks>;
|
|
62
59
|
verifyLog(input: VerifyLogInput): Promise<import("@coffre/core/vault").LogVerification>;
|
package/dist/cloudflare.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, o as derivedSigningKey, r as awsKms, s as resolveVaultConfig, t as KekBadClaimError } from "./src-
|
|
2
|
-
import { n as prepareVault, t as openVault } from "./vault-
|
|
1
|
+
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, o as derivedSigningKey, r as awsKms, s as resolveVaultConfig, t as KekBadClaimError } from "./src-CQJS3OZZ.js";
|
|
2
|
+
import { n as prepareVault, t as openVault } from "./vault-ihE3Yc4a.js";
|
|
3
3
|
import { createDatabase } from "@coffre/db";
|
|
4
4
|
import { HyperdrivePool, postgres } from "@coffre/db/hyperdrive";
|
|
5
5
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
@@ -11,13 +11,13 @@ type Kek = {
|
|
|
11
11
|
key: string;
|
|
12
12
|
} | KekProvider;
|
|
13
13
|
/**
|
|
14
|
-
* What a deployment writes: every key coffre has, and who
|
|
15
|
-
*
|
|
14
|
+
* What a deployment writes: every key coffre has, and who owns the
|
|
15
|
+
* instance whatever its database says. The app holds none of it.
|
|
16
16
|
*
|
|
17
17
|
* {
|
|
18
18
|
* kek: awsKms({ keyArn: env.KMS_KEY_ARN, credentials: { … } }),
|
|
19
19
|
* previousKeks: [{ id: 'vault-2025-01-10-k7q2xm', key: env.OLD_VAULT_KEY }],
|
|
20
|
-
*
|
|
20
|
+
* owners: ['admin@acme.example'],
|
|
21
21
|
* signingKey: env.SIGNING_KEY, // required with a key service; derived from a local KEK otherwise
|
|
22
22
|
* }
|
|
23
23
|
*/
|
|
@@ -29,8 +29,6 @@ type VaultConfig = {
|
|
|
29
29
|
* on, and verifying what the vault wrote under them before the rotation.
|
|
30
30
|
*/
|
|
31
31
|
previousKeks?: readonly Kek[];
|
|
32
|
-
/** At least one email: the only way into a fresh instance, and the only members nobody can remove. */
|
|
33
|
-
rootAdmins: readonly string[];
|
|
34
32
|
/**
|
|
35
33
|
* 32 random bytes, base64: the seed of the vault's own keys, which MAC its
|
|
36
34
|
* log entries, seal member rows and sign checkpoints. Leave it out with a
|
|
@@ -43,6 +41,30 @@ type VaultConfig = {
|
|
|
43
41
|
count: number;
|
|
44
42
|
windowMinutes: number;
|
|
45
43
|
};
|
|
44
|
+
} & Owners;
|
|
45
|
+
/**
|
|
46
|
+
* At least one email, each an Owner of the whole instance: made one when
|
|
47
|
+
* the vault starts, and when they sign in, whatever their row says, and
|
|
48
|
+
* refused to anyone who would demote or remove them, themselves included.
|
|
49
|
+
* The way into a fresh instance, and back into one whose Owners are all
|
|
50
|
+
* locked out: add an email, deploy, sign in. Taking an email off makes
|
|
51
|
+
* them an Owner like any other, whom an Owner may demote. `rootAdmins`, as
|
|
52
|
+
* 0.5 named it, and `bootstrapOwners` are read until 0.7.
|
|
53
|
+
*/
|
|
54
|
+
type Owners = {
|
|
55
|
+
owners: readonly string[];
|
|
56
|
+
bootstrapOwners?: never;
|
|
57
|
+
rootAdmins?: never;
|
|
58
|
+
} | {
|
|
59
|
+
/** @deprecated `owners`, read until 0.7. */
|
|
60
|
+
bootstrapOwners: readonly string[];
|
|
61
|
+
owners?: never;
|
|
62
|
+
rootAdmins?: never;
|
|
63
|
+
} | {
|
|
64
|
+
/** @deprecated 0.5's name for `owners`, read until 0.7: a root admin is an Owner now. */
|
|
65
|
+
rootAdmins: readonly string[];
|
|
66
|
+
owners?: never;
|
|
67
|
+
bootstrapOwners?: never;
|
|
46
68
|
};
|
|
47
69
|
/** The signing key a local KEK stands for, when the vault is given none: HKDF-SHA-256 of the KEK. */
|
|
48
70
|
declare function derivedSigningKey(kek: Uint8Array): Buffer;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as KekUnavailableError, c as awsKms, d as Kek, f as VaultConfig, i as KekProvider, l as checkpointMessage, n as AwsKmsOptions, o as SecretContext, p as derivedSigningKey, r as KekBadClaimError, s as WrappedDek, t as AwsCredentials, u as verifyCheckpoint } from "./index-
|
|
1
|
+
import { a as KekUnavailableError, c as awsKms, d as Kek, f as VaultConfig, i as KekProvider, l as checkpointMessage, n as AwsKmsOptions, o as SecretContext, p as derivedSigningKey, r as KekBadClaimError, s as WrappedDek, t as AwsCredentials, u as verifyCheckpoint } from "./index-CwsWOH6j.js";
|
|
2
2
|
export type * from "@coffre/core/vault";
|
|
3
3
|
export { type AwsCredentials, type AwsKmsOptions, type Kek, KekBadClaimError, type KekProvider, KekUnavailableError, type SecretContext, type VaultConfig, type WrappedDek, awsKms, checkpointMessage, derivedSigningKey, verifyCheckpoint };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, o as derivedSigningKey, r as awsKms, t as KekBadClaimError } from "./src-
|
|
1
|
+
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, o as derivedSigningKey, r as awsKms, t as KekBadClaimError } from "./src-CQJS3OZZ.js";
|
|
2
2
|
export { KekBadClaimError, KekUnavailableError, awsKms, checkpointMessage, derivedSigningKey, verifyCheckpoint };
|
package/dist/node.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as KekUnavailableError, c as awsKms, d as Kek, f as VaultConfig, i as KekProvider, l as checkpointMessage, n as AwsKmsOptions, o as SecretContext, p as derivedSigningKey, r as KekBadClaimError, s as WrappedDek, t as AwsCredentials, u as verifyCheckpoint } from "./index-
|
|
1
|
+
import { a as KekUnavailableError, c as awsKms, d as Kek, f as VaultConfig, i as KekProvider, l as checkpointMessage, n as AwsKmsOptions, o as SecretContext, p as derivedSigningKey, r as KekBadClaimError, s as WrappedDek, t as AwsCredentials, u as verifyCheckpoint } from "./index-CwsWOH6j.js";
|
|
2
2
|
import { Vault, Vault as Vault$1 } from "@coffre/core/vault";
|
|
3
3
|
import { Database } from "@coffre/db";
|
|
4
4
|
import "@coffre/core/audit";
|
package/dist/node.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, o as derivedSigningKey, r as awsKms, s as resolveVaultConfig, t as KekBadClaimError } from "./src-
|
|
2
|
-
import { n as prepareVault, t as openVault } from "./vault-
|
|
1
|
+
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, o as derivedSigningKey, r as awsKms, s as resolveVaultConfig, t as KekBadClaimError } from "./src-CQJS3OZZ.js";
|
|
2
|
+
import { n as prepareVault, t as openVault } from "./vault-ihE3Yc4a.js";
|
|
3
3
|
import { chmodSync, existsSync, lstatSync, rmSync } from "node:fs";
|
|
4
4
|
import { Agent, createServer, request } from "node:http";
|
|
5
5
|
import { openDatabase } from "@coffre/db/connect";
|
|
@@ -55,7 +55,7 @@ function resolveVaultConfig(config) {
|
|
|
55
55
|
if (twice !== void 0) throw new Error(`two vault keys share an id: ${twice}`);
|
|
56
56
|
return {
|
|
57
57
|
keks: new KekRegistry(current, previous),
|
|
58
|
-
|
|
58
|
+
owners: checkOwners(config.owners ?? config.bootstrapOwners ?? config.rootAdmins ?? []),
|
|
59
59
|
signingKeys: signingKeys(config.signingKey, keks),
|
|
60
60
|
bulkLimit: config.bulkLimit === void 0 ? DEFAULT_BULK_LIMIT : checkBulkLimit(config.bulkLimit)
|
|
61
61
|
};
|
|
@@ -98,16 +98,16 @@ function isHumanEmail(value) {
|
|
|
98
98
|
return labels.every((label) => label.length > 0 && label.length <= 63 && /^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/.test(label));
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
|
-
*
|
|
102
|
-
* mode: they are the only way into a fresh
|
|
103
|
-
*
|
|
101
|
+
* The Owners the deployment names, lowercased the way they are compared.
|
|
102
|
+
* At least one, in every mode: they are the only way into a fresh
|
|
103
|
+
* instance, and back into one whose Owners are locked out.
|
|
104
104
|
*/
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
if (
|
|
108
|
-
const invalid =
|
|
109
|
-
if (invalid) throw new Error(`
|
|
110
|
-
return
|
|
105
|
+
function checkOwners(emails) {
|
|
106
|
+
const owners = [...new Set(emails.map((entry) => entry.trim()).filter((entry) => entry.length > 0))];
|
|
107
|
+
if (owners.length === 0) throw new Error("owners must name at least one email, or nobody can manage coffre");
|
|
108
|
+
const invalid = owners.find((entry) => !isHumanEmail(entry));
|
|
109
|
+
if (invalid) throw new Error(`owners must be human email identities; invalid: ${invalid}`);
|
|
110
|
+
return [...new Set(owners.map((entry) => entry.toLowerCase()))];
|
|
111
111
|
}
|
|
112
112
|
//#endregion
|
|
113
113
|
export { verifyCheckpoint as a, checkpointMessage$1 as i, KekUnavailableError$1 as n, derivedSigningKey as o, awsKms as r, resolveVaultConfig as s, KekBadClaimError$1 as t };
|