@centient/secrets 0.6.0 → 0.8.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.
Files changed (37) hide show
  1. package/README.md +87 -1
  2. package/dist/cli/hidden-prompt.d.ts +48 -0
  3. package/dist/cli/hidden-prompt.d.ts.map +1 -0
  4. package/dist/cli/hidden-prompt.js +127 -0
  5. package/dist/cli/hidden-prompt.js.map +1 -0
  6. package/dist/cli/secrets-cli.d.ts +2 -1
  7. package/dist/cli/secrets-cli.d.ts.map +1 -1
  8. package/dist/cli/secrets-cli.js +55 -31
  9. package/dist/cli/secrets-cli.js.map +1 -1
  10. package/dist/index.d.ts +6 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/key-providers/index.d.ts +6 -2
  15. package/dist/key-providers/index.d.ts.map +1 -1
  16. package/dist/key-providers/index.js +2 -1
  17. package/dist/key-providers/index.js.map +1 -1
  18. package/dist/key-providers/keychain-provider.d.ts +30 -0
  19. package/dist/key-providers/keychain-provider.d.ts.map +1 -1
  20. package/dist/key-providers/keychain-provider.js +21 -5
  21. package/dist/key-providers/keychain-provider.js.map +1 -1
  22. package/dist/key-providers/passphrase-provider.d.ts +79 -0
  23. package/dist/key-providers/passphrase-provider.d.ts.map +1 -0
  24. package/dist/key-providers/passphrase-provider.js +298 -0
  25. package/dist/key-providers/passphrase-provider.js.map +1 -0
  26. package/dist/key-providers/resolve.d.ts +18 -3
  27. package/dist/key-providers/resolve.d.ts.map +1 -1
  28. package/dist/key-providers/resolve.js +47 -13
  29. package/dist/key-providers/resolve.js.map +1 -1
  30. package/dist/key-providers/types.d.ts +20 -2
  31. package/dist/key-providers/types.d.ts.map +1 -1
  32. package/dist/key-providers/types.js +1 -1
  33. package/dist/vault/session-vault.d.ts +31 -1
  34. package/dist/vault/session-vault.d.ts.map +1 -1
  35. package/dist/vault/session-vault.js +23 -6
  36. package/dist/vault/session-vault.js.map +1 -1
  37. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
- export { KeychainProvider } from "./keychain-provider.js";
1
+ export { KeychainProvider, DEFAULT_KEYCHAIN_SERVICE, DEFAULT_KEYCHAIN_ACCOUNT, } from "./keychain-provider.js";
2
2
  export { OnePasswordProvider } from "./onepassword-provider.js";
3
+ export { PassphraseProvider, DEFAULT_PASSPHRASE_KDF_PARAMS, DEFAULT_PASSPHRASE_VAULT_PATH, PASSPHRASE_KDF, PASSPHRASE_METADATA_VERSION, PASSPHRASE_SALT_LENGTH, PASSPHRASE_VERIFIER_ALGORITHM, PASSPHRASE_VERIFIER_CONTEXT, passphraseMetadataPathForVault, derivePassphraseKey, } from "./passphrase-provider.js";
3
4
  export { resolveKeyProvider, getProviderByType, loadConfig, saveSecretsConfig } from "./resolve.js";
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/key-providers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/key-providers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EACL,kBAAkB,EAClB,6BAA6B,EAC7B,6BAA6B,EAC7B,cAAc,EACd,2BAA2B,EAC3B,sBAAsB,EACtB,6BAA6B,EAC7B,2BAA2B,EAC3B,8BAA8B,EAC9B,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
@@ -8,8 +8,38 @@
8
8
  * with the system Keychain, which prompts for Touch ID or system password.
9
9
  */
10
10
  import type { KeyProvider, KeyProviderType } from "./types.js";
11
+ /**
12
+ * Default Keychain item coordinates. These are the historical values every
13
+ * consumer shared before per-consumer keys existed — keeping them as the
14
+ * defaults guarantees existing vaults keep opening with no options passed.
15
+ */
16
+ export declare const DEFAULT_KEYCHAIN_SERVICE = "centient-vault";
17
+ export declare const DEFAULT_KEYCHAIN_ACCOUNT = "vault-key";
18
+ /**
19
+ * Per-consumer Keychain item coordinates.
20
+ *
21
+ * A consumer that wants its own master key (rather than sharing the global
22
+ * `centient-vault`/`vault-key` item with every other consumer on the machine)
23
+ * names its own Keychain item here — e.g. `{ service: "burnrate-vault" }`.
24
+ * Omitted fields fall back to the historical defaults so behaviour is
25
+ * byte-identical to before when no options are supplied.
26
+ */
27
+ export interface KeychainProviderOptions {
28
+ /** Keychain service name. Defaults to {@link DEFAULT_KEYCHAIN_SERVICE}. */
29
+ service?: string;
30
+ /** Keychain account name. Defaults to {@link DEFAULT_KEYCHAIN_ACCOUNT}. */
31
+ account?: string;
32
+ }
11
33
  export declare class KeychainProvider implements KeyProvider {
12
34
  readonly name: KeyProviderType;
35
+ private readonly service;
36
+ private readonly account;
37
+ /**
38
+ * @param options - Optional per-consumer Keychain item coordinates. With no
39
+ * options the provider targets the historical `centient-vault`/`vault-key`
40
+ * item, so existing vaults keep opening unchanged.
41
+ */
42
+ constructor(options?: KeychainProviderOptions);
13
43
  /** Returns true if running on macOS. */
14
44
  static detect(): boolean;
15
45
  getKey(): Buffer | null;
@@ -1 +1 @@
1
- {"version":3,"file":"keychain-provider.d.ts","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAa/D,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAc;IAE5C,wCAAwC;IACxC,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM,GAAG,IAAI;IAIvB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B,SAAS,IAAI,OAAO;CAGrB"}
1
+ {"version":3,"file":"keychain-provider.d.ts","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAM/D;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,mBAAmB,CAAC;AACzD,eAAO,MAAM,wBAAwB,cAAc,CAAC;AAMpD;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAc;IAE5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC;;;;OAIG;gBACS,OAAO,GAAE,uBAA4B;IAKjD,wCAAwC;IACxC,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM,GAAG,IAAI;IAIvB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B,SAAS,IAAI,OAAO;CAGrB"}
@@ -11,25 +11,41 @@ import { getKeyFromKeychain, storeKeyInKeychain, deleteFromKeychain, } from "../
11
11
  // =============================================================================
12
12
  // Constants
13
13
  // =============================================================================
14
- const KEYCHAIN_SERVICE = "centient-vault";
15
- const KEYCHAIN_ACCOUNT = "vault-key";
14
+ /**
15
+ * Default Keychain item coordinates. These are the historical values every
16
+ * consumer shared before per-consumer keys existed — keeping them as the
17
+ * defaults guarantees existing vaults keep opening with no options passed.
18
+ */
19
+ export const DEFAULT_KEYCHAIN_SERVICE = "centient-vault";
20
+ export const DEFAULT_KEYCHAIN_ACCOUNT = "vault-key";
16
21
  // =============================================================================
17
22
  // Implementation
18
23
  // =============================================================================
19
24
  export class KeychainProvider {
20
25
  name = "keychain";
26
+ service;
27
+ account;
28
+ /**
29
+ * @param options - Optional per-consumer Keychain item coordinates. With no
30
+ * options the provider targets the historical `centient-vault`/`vault-key`
31
+ * item, so existing vaults keep opening unchanged.
32
+ */
33
+ constructor(options = {}) {
34
+ this.service = options.service ?? DEFAULT_KEYCHAIN_SERVICE;
35
+ this.account = options.account ?? DEFAULT_KEYCHAIN_ACCOUNT;
36
+ }
21
37
  /** Returns true if running on macOS. */
22
38
  static detect() {
23
39
  return process.platform === "darwin";
24
40
  }
25
41
  getKey() {
26
- return getKeyFromKeychain(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
42
+ return getKeyFromKeychain(this.service, this.account);
27
43
  }
28
44
  storeKey(key) {
29
- return storeKeyInKeychain(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT, key);
45
+ return storeKeyInKeychain(this.service, this.account, key);
30
46
  }
31
47
  deleteKey() {
32
- return deleteFromKeychain(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
48
+ return deleteFromKeychain(this.service, this.account);
33
49
  }
34
50
  }
35
51
  //# sourceMappingURL=keychain-provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keychain-provider.js","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AAGnC,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAC1C,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAErC,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAoB,UAAU,CAAC;IAE5C,wCAAwC;IACxC,MAAM,CAAC,MAAM;QACX,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACvC,CAAC;IAED,MAAM;QACJ,OAAO,kBAAkB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IAChE,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,OAAO,kBAAkB,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC;IACrE,CAAC;IAED,SAAS;QACP,OAAO,kBAAkB,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IAChE,CAAC;CACF"}
1
+ {"version":3,"file":"keychain-provider.js","sourceRoot":"","sources":["../../src/key-providers/keychain-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AAGnC,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,gBAAgB,CAAC;AACzD,MAAM,CAAC,MAAM,wBAAwB,GAAG,WAAW,CAAC;AAsBpD,gFAAgF;AAChF,iBAAiB;AACjB,gFAAgF;AAEhF,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAoB,UAAU,CAAC;IAE3B,OAAO,CAAS;IAChB,OAAO,CAAS;IAEjC;;;;OAIG;IACH,YAAY,UAAmC,EAAE;QAC/C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,wBAAwB,CAAC;QAC3D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,wBAAwB,CAAC;IAC7D,CAAC;IAED,wCAAwC;IACxC,MAAM,CAAC,MAAM;QACX,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACvC,CAAC;IAED,MAAM;QACJ,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;IAED,QAAQ,CAAC,GAAW;QAClB,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC7D,CAAC;IAED,SAAS;QACP,OAAO,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;CACF"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Key Provider — Passphrase
3
+ *
4
+ * Derives the vault encryption key from a human-entered passphrase using a
5
+ * per-vault salt. The passphrase and derived key are never persisted; only
6
+ * non-secret KDF metadata plus a verifier are written beside the vault.
7
+ */
8
+ import type { KeyProvider, KeyProviderError, KeyProviderType } from "./types.js";
9
+ export declare const PASSPHRASE_METADATA_VERSION = 1;
10
+ export declare const PASSPHRASE_KDF: "scrypt";
11
+ export declare const PASSPHRASE_VERIFIER_ALGORITHM: "hmac-sha256";
12
+ export declare const PASSPHRASE_VERIFIER_CONTEXT = "centient-secrets-passphrase:v1";
13
+ export declare const PASSPHRASE_SALT_LENGTH = 32;
14
+ export declare const DEFAULT_PASSPHRASE_VAULT_PATH: string;
15
+ export declare const DEFAULT_PASSPHRASE_KDF_PARAMS: PassphraseKdfParams;
16
+ export interface PassphraseKdfParams {
17
+ /** scrypt CPU/memory cost parameter. */
18
+ N: number;
19
+ /** scrypt block size parameter. */
20
+ r: number;
21
+ /** scrypt parallelization parameter. */
22
+ p: number;
23
+ /** Derived key length in bytes. */
24
+ keyLength: number;
25
+ /** Node scrypt memory ceiling in bytes. */
26
+ maxmem: number;
27
+ }
28
+ export interface PassphraseMetadata {
29
+ version: typeof PASSPHRASE_METADATA_VERSION;
30
+ kdf: typeof PASSPHRASE_KDF;
31
+ params: PassphraseKdfParams;
32
+ salt: string;
33
+ verifier: {
34
+ algorithm: typeof PASSPHRASE_VERIFIER_ALGORITHM;
35
+ value: string;
36
+ };
37
+ }
38
+ export type PassphrasePrompt = (message: string) => string | null;
39
+ export interface PassphraseProviderOptions {
40
+ /** Vault path used to derive the default metadata location. */
41
+ vaultPath?: string;
42
+ /** Explicit metadata file path; primarily useful for tests. */
43
+ metadataPath?: string;
44
+ /** Hidden prompt implementation; tests can inject a deterministic prompt. */
45
+ prompt?: PassphrasePrompt;
46
+ /** KDF params for setup; defaults are intentionally production-cost. */
47
+ params?: PassphraseKdfParams;
48
+ }
49
+ export declare function passphraseMetadataPathForVault(vaultPath: string): string;
50
+ export declare class PassphraseProvider implements KeyProvider {
51
+ readonly name: KeyProviderType;
52
+ private readonly metadataPath;
53
+ private readonly prompt;
54
+ private readonly setupParams;
55
+ private lastError;
56
+ constructor(options?: PassphraseProviderOptions);
57
+ /** Returns true when a passphrase can be requested from this process. */
58
+ static detect(): boolean;
59
+ get metadataFile(): string;
60
+ getLastError(): KeyProviderError | null;
61
+ getKey(): Buffer | null;
62
+ /**
63
+ * Passphrase providers do not store caller-supplied random keys.
64
+ * Use setupKey() so the vault key is derived from the passphrase.
65
+ */
66
+ storeKey(_key: Buffer): boolean;
67
+ /**
68
+ * Initialize passphrase metadata and return the derived key for bootstrap
69
+ * encryption. Only salt, KDF params, and verifier are persisted.
70
+ */
71
+ setupKey(): Buffer | null;
72
+ deleteKey(): boolean;
73
+ private readMetadata;
74
+ private promptForPassphrase;
75
+ private clearLastError;
76
+ private setLastError;
77
+ }
78
+ export declare function derivePassphraseKey(passphrase: string, salt: Buffer, params?: PassphraseKdfParams): Buffer;
79
+ //# sourceMappingURL=passphrase-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passphrase-provider.d.ts","sourceRoot":"","sources":["../../src/key-providers/passphrase-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,eAAe,EAChB,MAAM,YAAY,CAAC;AAMpB,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAC7C,eAAO,MAAM,cAAc,EAAG,QAAiB,CAAC;AAChD,eAAO,MAAM,6BAA6B,EAAG,aAAsB,CAAC;AACpE,eAAO,MAAM,2BAA2B,mCAAmC,CAAC;AAC5E,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,6BAA6B,QAKzC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,mBAM3C,CAAC;AAMF,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,mCAAmC;IACnC,CAAC,EAAE,MAAM,CAAC;IACV,wCAAwC;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,2BAA2B,CAAC;IAC5C,GAAG,EAAE,OAAO,cAAc,CAAC;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QACR,SAAS,EAAE,OAAO,6BAA6B,CAAC;QAChD,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAElE,MAAM,WAAW,yBAAyB;IACxC,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,wEAAwE;IACxE,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAMD,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMxE;AAMD,qBAAa,kBAAmB,YAAW,WAAW;IACpD,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAgB;IAE9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;IAClD,OAAO,CAAC,SAAS,CAAiC;gBAEtC,OAAO,GAAE,yBAA8B;IAQnD,yEAAyE;IACzE,MAAM,CAAC,MAAM,IAAI,OAAO;IAIxB,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,YAAY,IAAI,gBAAgB,GAAG,IAAI;IAIvC,MAAM,IAAI,MAAM,GAAG,IAAI;IAmCvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQ/B;;;OAGG;IACH,QAAQ,IAAI,MAAM,GAAG,IAAI;IA8DzB,SAAS,IAAI,OAAO;IAcpB,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;CAGrB;AAMD,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,mBAAmD,GAC1D,MAAM,CAOR"}
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Key Provider — Passphrase
3
+ *
4
+ * Derives the vault encryption key from a human-entered passphrase using a
5
+ * per-vault salt. The passphrase and derived key are never persisted; only
6
+ * non-secret KDF metadata plus a verifier are written beside the vault.
7
+ */
8
+ import { mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
9
+ import { dirname, basename, join } from "node:path";
10
+ import { createHmac, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
11
+ import { homedir } from "node:os";
12
+ import { promptHiddenSync } from "../cli/hidden-prompt.js";
13
+ // =============================================================================
14
+ // Constants
15
+ // =============================================================================
16
+ export const PASSPHRASE_METADATA_VERSION = 1;
17
+ export const PASSPHRASE_KDF = "scrypt";
18
+ export const PASSPHRASE_VERIFIER_ALGORITHM = "hmac-sha256";
19
+ export const PASSPHRASE_VERIFIER_CONTEXT = "centient-secrets-passphrase:v1";
20
+ export const PASSPHRASE_SALT_LENGTH = 32;
21
+ export const DEFAULT_PASSPHRASE_VAULT_PATH = join(homedir(), ".centient", "secrets", "vault.enc");
22
+ export const DEFAULT_PASSPHRASE_KDF_PARAMS = {
23
+ N: 2 ** 17,
24
+ r: 8,
25
+ p: 1,
26
+ keyLength: 32,
27
+ maxmem: 192 * 1024 * 1024,
28
+ };
29
+ // =============================================================================
30
+ // Path helpers
31
+ // =============================================================================
32
+ export function passphraseMetadataPathForVault(vaultPath) {
33
+ const name = basename(vaultPath);
34
+ const metadataName = name.endsWith(".enc")
35
+ ? `${name.slice(0, -".enc".length)}.passphrase.json`
36
+ : `${name}.passphrase.json`;
37
+ return join(dirname(vaultPath), metadataName);
38
+ }
39
+ // =============================================================================
40
+ // Implementation
41
+ // =============================================================================
42
+ export class PassphraseProvider {
43
+ name = "passphrase";
44
+ metadataPath;
45
+ prompt;
46
+ setupParams;
47
+ lastError = null;
48
+ constructor(options = {}) {
49
+ this.metadataPath =
50
+ options.metadataPath ??
51
+ passphraseMetadataPathForVault(options.vaultPath ?? DEFAULT_PASSPHRASE_VAULT_PATH);
52
+ this.prompt = options.prompt ?? promptHiddenSync;
53
+ this.setupParams = options.params ?? DEFAULT_PASSPHRASE_KDF_PARAMS;
54
+ }
55
+ /** Returns true when a passphrase can be requested from this process. */
56
+ static detect() {
57
+ return process.stdin.isTTY === true;
58
+ }
59
+ get metadataFile() {
60
+ return this.metadataPath;
61
+ }
62
+ getLastError() {
63
+ return this.lastError;
64
+ }
65
+ getKey() {
66
+ this.clearLastError();
67
+ const metadata = this.readMetadata();
68
+ if (metadata === null)
69
+ return null;
70
+ const passphrase = this.promptForPassphrase("Vault passphrase: ");
71
+ if (passphrase === null)
72
+ return null;
73
+ const salt = Buffer.from(metadata.salt, "base64");
74
+ const expectedVerifier = Buffer.from(metadata.verifier.value, "base64");
75
+ let key;
76
+ try {
77
+ key = derivePassphraseKey(passphrase, salt, metadata.params);
78
+ }
79
+ catch (err) {
80
+ this.setLastError("KDF_FAILED", `Failed to derive passphrase key: ${err instanceof Error ? err.message : String(err)}`);
81
+ return null;
82
+ }
83
+ if (!verifyKey(key, expectedVerifier)) {
84
+ key.fill(0);
85
+ this.setLastError("PASSPHRASE_VERIFICATION_FAILED", "Passphrase verification failed. Check the passphrase for this vault and try again.");
86
+ return null;
87
+ }
88
+ return key;
89
+ }
90
+ /**
91
+ * Passphrase providers do not store caller-supplied random keys.
92
+ * Use setupKey() so the vault key is derived from the passphrase.
93
+ */
94
+ storeKey(_key) {
95
+ this.setLastError("UNSUPPORTED_OPERATION", "Passphrase provider derives the vault key from a typed passphrase and cannot store a caller-supplied key. Use setupKey() during vault initialization.");
96
+ return false;
97
+ }
98
+ /**
99
+ * Initialize passphrase metadata and return the derived key for bootstrap
100
+ * encryption. Only salt, KDF params, and verifier are persisted.
101
+ */
102
+ setupKey() {
103
+ this.clearLastError();
104
+ const passphrase = this.promptForPassphrase("Create vault passphrase: ");
105
+ if (passphrase === null)
106
+ return null;
107
+ if (passphrase.length === 0) {
108
+ this.setLastError("EMPTY_PASSPHRASE", "Passphrase cannot be empty.");
109
+ return null;
110
+ }
111
+ const confirmation = this.promptForPassphrase("Confirm vault passphrase: ");
112
+ if (confirmation === null)
113
+ return null;
114
+ if (passphrase !== confirmation) {
115
+ this.setLastError("PASSPHRASE_MISMATCH", "Passphrases did not match; passphrase metadata was not written.");
116
+ return null;
117
+ }
118
+ const salt = randomBytes(PASSPHRASE_SALT_LENGTH);
119
+ let key;
120
+ try {
121
+ key = derivePassphraseKey(passphrase, salt, this.setupParams);
122
+ }
123
+ catch (err) {
124
+ this.setLastError("KDF_FAILED", `Failed to derive passphrase key: ${err instanceof Error ? err.message : String(err)}`);
125
+ return null;
126
+ }
127
+ const metadata = {
128
+ version: PASSPHRASE_METADATA_VERSION,
129
+ kdf: PASSPHRASE_KDF,
130
+ params: { ...this.setupParams },
131
+ salt: salt.toString("base64"),
132
+ verifier: {
133
+ algorithm: PASSPHRASE_VERIFIER_ALGORITHM,
134
+ value: createVerifier(key).toString("base64"),
135
+ },
136
+ };
137
+ try {
138
+ mkdirSync(dirname(this.metadataPath), { recursive: true, mode: 0o700 });
139
+ writeFileSync(this.metadataPath, JSON.stringify(metadata, null, 2) + "\n", { encoding: "utf8", mode: 0o600 });
140
+ }
141
+ catch (err) {
142
+ key.fill(0);
143
+ this.setLastError("METADATA_WRITE_FAILED", `Failed to write passphrase metadata at ${this.metadataPath}: ${err instanceof Error ? err.message : String(err)}`);
144
+ return null;
145
+ }
146
+ return key;
147
+ }
148
+ deleteKey() {
149
+ this.clearLastError();
150
+ try {
151
+ rmSync(this.metadataPath, { force: true });
152
+ return true;
153
+ }
154
+ catch (err) {
155
+ this.setLastError("METADATA_DELETE_FAILED", `Failed to delete passphrase metadata at ${this.metadataPath}: ${err instanceof Error ? err.message : String(err)}`);
156
+ return false;
157
+ }
158
+ }
159
+ readMetadata() {
160
+ let parsed;
161
+ try {
162
+ parsed = JSON.parse(readFileSync(this.metadataPath, "utf8"));
163
+ }
164
+ catch (err) {
165
+ const notFound = isNotFoundError(err);
166
+ this.setLastError(notFound ? "METADATA_NOT_FOUND" : "METADATA_READ_FAILED", notFound
167
+ ? `Passphrase provider is not initialized for this vault. Run \`centient secrets init\` from an interactive terminal, or configure another secrets.provider.`
168
+ : `Failed to read passphrase metadata at ${this.metadataPath}: ${err instanceof Error ? err.message : String(err)}`);
169
+ return null;
170
+ }
171
+ const metadata = validateMetadata(parsed);
172
+ if (metadata === null) {
173
+ this.setLastError("METADATA_INVALID", `Passphrase metadata at ${this.metadataPath} is invalid or unsupported.`);
174
+ return null;
175
+ }
176
+ return metadata;
177
+ }
178
+ promptForPassphrase(message) {
179
+ try {
180
+ const value = this.prompt(message);
181
+ if (value === null) {
182
+ this.setLastError("PASSPHRASE_INTERRUPTED", "Passphrase entry was interrupted.");
183
+ return null;
184
+ }
185
+ return value;
186
+ }
187
+ catch (err) {
188
+ this.setLastError("PASSPHRASE_PROMPT_FAILED", err instanceof Error ? err.message : String(err));
189
+ return null;
190
+ }
191
+ }
192
+ clearLastError() {
193
+ this.lastError = null;
194
+ }
195
+ setLastError(code, message) {
196
+ this.lastError = { code, message };
197
+ }
198
+ }
199
+ // =============================================================================
200
+ // Crypto helpers
201
+ // =============================================================================
202
+ export function derivePassphraseKey(passphrase, salt, params = DEFAULT_PASSPHRASE_KDF_PARAMS) {
203
+ return scryptSync(passphrase, salt, params.keyLength, {
204
+ N: params.N,
205
+ r: params.r,
206
+ p: params.p,
207
+ maxmem: params.maxmem,
208
+ });
209
+ }
210
+ function createVerifier(key) {
211
+ return createHmac("sha256", key)
212
+ .update(PASSPHRASE_VERIFIER_CONTEXT, "utf8")
213
+ .digest();
214
+ }
215
+ function verifyKey(key, expectedVerifier) {
216
+ const actualVerifier = createVerifier(key);
217
+ try {
218
+ return (actualVerifier.length === expectedVerifier.length &&
219
+ timingSafeEqual(actualVerifier, expectedVerifier));
220
+ }
221
+ finally {
222
+ actualVerifier.fill(0);
223
+ }
224
+ }
225
+ function validateMetadata(value) {
226
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
227
+ return null;
228
+ }
229
+ const record = value;
230
+ if (record.version !== PASSPHRASE_METADATA_VERSION ||
231
+ record.kdf !== PASSPHRASE_KDF ||
232
+ typeof record.salt !== "string") {
233
+ return null;
234
+ }
235
+ const params = validateParams(record.params);
236
+ if (params === null)
237
+ return null;
238
+ const verifierRaw = record.verifier;
239
+ if (typeof verifierRaw !== "object" ||
240
+ verifierRaw === null ||
241
+ Array.isArray(verifierRaw)) {
242
+ return null;
243
+ }
244
+ const verifier = verifierRaw;
245
+ if (verifier.algorithm !== PASSPHRASE_VERIFIER_ALGORITHM ||
246
+ typeof verifier.value !== "string") {
247
+ return null;
248
+ }
249
+ const salt = Buffer.from(record.salt, "base64");
250
+ const verifierValue = Buffer.from(verifier.value, "base64");
251
+ if (salt.length < 16 || verifierValue.length !== 32)
252
+ return null;
253
+ return {
254
+ version: PASSPHRASE_METADATA_VERSION,
255
+ kdf: PASSPHRASE_KDF,
256
+ params,
257
+ salt: record.salt,
258
+ verifier: {
259
+ algorithm: PASSPHRASE_VERIFIER_ALGORITHM,
260
+ value: verifier.value,
261
+ },
262
+ };
263
+ }
264
+ function validateParams(value) {
265
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
266
+ return null;
267
+ }
268
+ const record = value;
269
+ const params = {
270
+ N: Number(record.N),
271
+ r: Number(record.r),
272
+ p: Number(record.p),
273
+ keyLength: Number(record.keyLength),
274
+ maxmem: Number(record.maxmem),
275
+ };
276
+ if (!Number.isSafeInteger(params.N) ||
277
+ !Number.isSafeInteger(params.r) ||
278
+ !Number.isSafeInteger(params.p) ||
279
+ !Number.isSafeInteger(params.keyLength) ||
280
+ !Number.isSafeInteger(params.maxmem) ||
281
+ params.N <= 1 ||
282
+ !isPowerOfTwo(params.N) ||
283
+ params.r <= 0 ||
284
+ params.p <= 0 ||
285
+ params.keyLength !== 32 ||
286
+ params.maxmem <= 0) {
287
+ return null;
288
+ }
289
+ return params;
290
+ }
291
+ function isPowerOfTwo(value) {
292
+ return value >= 2 && Math.log2(value) % 1 === 0;
293
+ }
294
+ function isNotFoundError(err) {
295
+ return (err instanceof Error &&
296
+ err.code === "ENOENT");
297
+ }
298
+ //# sourceMappingURL=passphrase-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passphrase-provider.js","sourceRoot":"","sources":["../../src/key-providers/passphrase-provider.ts"],"names":[],"mappings":"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"}
@@ -7,9 +7,24 @@
7
7
  *
8
8
  * Resolution order:
9
9
  * 1. Explicit config (secrets.provider field) — use it; fail if unavailable
10
- * 2. Auto-detection — 1Password if `op` is available, else Keychain on macOS
10
+ * 2. Auto-detection — 1Password if `op` is available, else Keychain on macOS,
11
+ * else passphrase when an interactive TTY is available
11
12
  */
13
+ import type { KeychainProviderOptions } from "./keychain-provider.js";
12
14
  import type { KeyProvider, KeyProviderType, CentientConfig, SecretsConfig } from "./types.js";
15
+ export interface ResolveKeyProviderOptions {
16
+ /** Vault path used by providers with per-vault metadata. */
17
+ vaultPath?: string;
18
+ /**
19
+ * Per-consumer Keychain item coordinates. When the resolved provider is the
20
+ * macOS Keychain, these name the Keychain item so a consumer can use its own
21
+ * master key (e.g. `{ service: "burnrate-vault" }`) instead of sharing the
22
+ * global `centient-vault`/`vault-key` item with every other consumer on the
23
+ * machine. Omitted/undefined fields fall back to the historical defaults,
24
+ * so the no-options path is byte-identical to before.
25
+ */
26
+ keychain?: KeychainProviderOptions;
27
+ }
13
28
  /**
14
29
  * Load the global centient config file.
15
30
  * Returns an empty object if the file doesn't exist or is malformed.
@@ -27,7 +42,7 @@ export declare function saveSecretsConfig(secrets: SecretsConfig): boolean;
27
42
  * @returns An object with the resolved provider, or an error message
28
43
  * if the explicitly configured provider is unavailable.
29
44
  */
30
- export declare function resolveKeyProvider(): {
45
+ export declare function resolveKeyProvider(options?: ResolveKeyProviderOptions): {
31
46
  ok: true;
32
47
  provider: KeyProvider;
33
48
  method: "config" | "auto";
@@ -42,5 +57,5 @@ export declare function resolveKeyProvider(): {
42
57
  * Get a specific provider by type, regardless of config.
43
58
  * Used by the migrate command to construct source/target providers.
44
59
  */
45
- export declare function getProviderByType(type: KeyProviderType, config?: SecretsConfig): KeyProvider | null;
60
+ export declare function getProviderByType(type: KeyProviderType, config?: SecretsConfig, options?: ResolveKeyProviderOptions): KeyProvider | null;
46
61
  //# sourceMappingURL=resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/key-providers/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAYpB;;;GAGG;AACH,wBAAgB,UAAU,IAAI,cAAc,CAY3C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAWjE;AAMD;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC3B,GAAG;IACF,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C,CAWA;AAyFD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,EACrB,MAAM,CAAC,EAAE,aAAa,GACrB,WAAW,GAAG,IAAI,CAWpB"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/key-providers/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGtE,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,yBAAyB;IACxC,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CACpC;AAMD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,cAAc,CAY3C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAWjE;AAMD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG;IAC3E,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC3B,GAAG;IACF,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C,CAWA;AAqHD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,eAAe,EACrB,MAAM,CAAC,EAAE,aAAa,EACtB,OAAO,GAAE,yBAA8B,GACtC,WAAW,GAAG,IAAI,CAiBpB"}