@centient/secrets 0.5.0 → 0.6.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 (36) hide show
  1. package/README.md +2 -0
  2. package/dist/cli/hidden-input.d.ts +52 -0
  3. package/dist/cli/hidden-input.d.ts.map +1 -0
  4. package/dist/cli/hidden-input.js +109 -0
  5. package/dist/cli/hidden-input.js.map +1 -0
  6. package/dist/cli/secrets-cli.d.ts +7 -0
  7. package/dist/cli/secrets-cli.d.ts.map +1 -1
  8. package/dist/cli/secrets-cli.js +234 -161
  9. package/dist/cli/secrets-cli.js.map +1 -1
  10. package/dist/crypto/vault-common.d.ts +17 -4
  11. package/dist/crypto/vault-common.d.ts.map +1 -1
  12. package/dist/crypto/vault-common.js +23 -6
  13. package/dist/crypto/vault-common.js.map +1 -1
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +6 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/vault/file-lock.d.ts +33 -0
  19. package/dist/vault/file-lock.d.ts.map +1 -0
  20. package/dist/vault/file-lock.js +143 -0
  21. package/dist/vault/file-lock.js.map +1 -0
  22. package/dist/vault/session-vault-errors.d.ts +38 -0
  23. package/dist/vault/session-vault-errors.d.ts.map +1 -0
  24. package/dist/vault/session-vault-errors.js +67 -0
  25. package/dist/vault/session-vault-errors.js.map +1 -0
  26. package/dist/vault/session-vault.d.ts +147 -0
  27. package/dist/vault/session-vault.d.ts.map +1 -0
  28. package/dist/vault/session-vault.js +667 -0
  29. package/dist/vault/session-vault.js.map +1 -0
  30. package/dist/vault/sidecar.d.ts +37 -0
  31. package/dist/vault/sidecar.d.ts.map +1 -0
  32. package/dist/vault/sidecar.js +84 -0
  33. package/dist/vault/sidecar.js.map +1 -0
  34. package/dist/vault/types.d.ts +1 -1
  35. package/dist/vault/types.d.ts.map +1 -1
  36. package/package.json +1 -1
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Cross-platform secrets vault with AES-256-GCM encryption and platform-native key storage.
4
4
 
5
+ > **Daemons / long-running processes:** see [Session-backed vault (`openVault`)](./docs/session-vault.md) for the recommended API — single master-key unlock per session, in-memory cached reads, mtime-check coherence with the CLI, rollback protection via monotonic version + sidecar.
6
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Hidden-Input State Machine
3
+ *
4
+ * Pure character-stream parser used by the secrets CLI's hidden-input prompt
5
+ * (password / secret entry). Extracted from `secrets-cli.ts` so the parsing
6
+ * rules can be exercised directly in tests without stubbing `process.stdin`.
7
+ *
8
+ * Regression: issue #37 — the previous prompt resolved on the first `\n`
9
+ * from a terminal paste and silently truncated multi-line secrets (PEM keys,
10
+ * multi-line config blobs) to their first line.
11
+ */
12
+ /** VT100 bracketed-paste sentinels — wraps pasted content from the terminal. */
13
+ export declare const PASTE_START = "\u001B[200~";
14
+ export declare const PASTE_END = "\u001B[201~";
15
+ /** Enable / disable bracketed paste mode on the current terminal. */
16
+ export declare const ENABLE_BRACKETED_PASTE = "\u001B[?2004h";
17
+ export declare const DISABLE_BRACKETED_PASTE = "\u001B[?2004l";
18
+ /** Control characters recognized by the hidden-input state machine. */
19
+ export declare const CTRL_C = "\u0003";
20
+ export declare const CTRL_D = "\u0004";
21
+ export declare const BACKSPACE = "";
22
+ export declare const BS = "\b";
23
+ /** Signal emitted by {@link advanceHiddenInput} to indicate why input stopped. */
24
+ export type HiddenInputSignal = "submit" | "ctrl-c" | "continue";
25
+ /**
26
+ * Mutable state for the hidden-input parser. Callers should construct a fresh
27
+ * instance per prompt and feed chunks via {@link advanceHiddenInput}.
28
+ */
29
+ export interface HiddenInputState {
30
+ input: string;
31
+ inPaste: boolean;
32
+ escBuf: string;
33
+ /**
34
+ * True when the state machine has recognized an escape sequence that is not
35
+ * a paste-marker prefix and is swallowing characters until the sequence's
36
+ * terminator byte arrives. Prevents stray `~` / digits from unrelated CSI
37
+ * sequences (e.g. Delete `\x1b[3~`, arrow keys) from leaking into `input`.
38
+ */
39
+ swallowingCsi: boolean;
40
+ }
41
+ export declare function createHiddenInputState(): HiddenInputState;
42
+ /**
43
+ * Advance the state machine with a single chunk from stdin. Returns `"submit"`
44
+ * when the caller should resolve the prompt with `state.input`, `"ctrl-c"`
45
+ * when the user interrupted, or `"continue"` when more input is expected.
46
+ *
47
+ * Character-by-character processing ensures escape-sequence state survives
48
+ * across chunk boundaries (a fast paste may arrive split across many chunks,
49
+ * and a single chunk may contain both paste markers and regular keystrokes).
50
+ */
51
+ export declare function advanceHiddenInput(state: HiddenInputState, chunk: string): HiddenInputSignal;
52
+ //# sourceMappingURL=hidden-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hidden-input.d.ts","sourceRoot":"","sources":["../../src/cli/hidden-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gFAAgF;AAChF,eAAO,MAAM,WAAW,gBAAc,CAAC;AACvC,eAAO,MAAM,SAAS,gBAAc,CAAC;AACrC,qEAAqE;AACrE,eAAO,MAAM,sBAAsB,kBAAgB,CAAC;AACpD,eAAO,MAAM,uBAAuB,kBAAgB,CAAC;AAErD,uEAAuE;AACvE,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,SAAS,MAAW,CAAC;AAClC,eAAO,MAAM,EAAE,OAAO,CAAC;AAEvB,kFAAkF;AAClF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD;AAeD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,MAAM,GACZ,iBAAiB,CAmEnB"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Hidden-Input State Machine
3
+ *
4
+ * Pure character-stream parser used by the secrets CLI's hidden-input prompt
5
+ * (password / secret entry). Extracted from `secrets-cli.ts` so the parsing
6
+ * rules can be exercised directly in tests without stubbing `process.stdin`.
7
+ *
8
+ * Regression: issue #37 — the previous prompt resolved on the first `\n`
9
+ * from a terminal paste and silently truncated multi-line secrets (PEM keys,
10
+ * multi-line config blobs) to their first line.
11
+ */
12
+ /** VT100 bracketed-paste sentinels — wraps pasted content from the terminal. */
13
+ export const PASTE_START = "\x1b[200~";
14
+ export const PASTE_END = "\x1b[201~";
15
+ /** Enable / disable bracketed paste mode on the current terminal. */
16
+ export const ENABLE_BRACKETED_PASTE = "\x1b[?2004h";
17
+ export const DISABLE_BRACKETED_PASTE = "\x1b[?2004l";
18
+ /** Control characters recognized by the hidden-input state machine. */
19
+ export const CTRL_C = "\u0003";
20
+ export const CTRL_D = "\u0004";
21
+ export const BACKSPACE = "\u007F";
22
+ export const BS = "\b";
23
+ export function createHiddenInputState() {
24
+ return { input: "", inPaste: false, escBuf: "", swallowingCsi: false };
25
+ }
26
+ /**
27
+ * CSI final-byte range per ECMA-48: `\x40`-`\x7E` (i.e. `@` through `~`). When
28
+ * we're swallowing a CSI we know isn't a paste marker, we stop at the first
29
+ * byte in this range that isn't a parameter byte (`0`-`9`, `;`, `:`, `<`-`?`).
30
+ */
31
+ function isCsiTerminator(char) {
32
+ const code = char.charCodeAt(0);
33
+ // Parameter / intermediate bytes — not terminators.
34
+ if ((code >= 0x30 && code <= 0x3f) || (code >= 0x20 && code <= 0x2f))
35
+ return false;
36
+ // Final byte range.
37
+ return code >= 0x40 && code <= 0x7e;
38
+ }
39
+ /**
40
+ * Advance the state machine with a single chunk from stdin. Returns `"submit"`
41
+ * when the caller should resolve the prompt with `state.input`, `"ctrl-c"`
42
+ * when the user interrupted, or `"continue"` when more input is expected.
43
+ *
44
+ * Character-by-character processing ensures escape-sequence state survives
45
+ * across chunk boundaries (a fast paste may arrive split across many chunks,
46
+ * and a single chunk may contain both paste markers and regular keystrokes).
47
+ */
48
+ export function advanceHiddenInput(state, chunk) {
49
+ for (let i = 0; i < chunk.length; i++) {
50
+ const char = chunk[i];
51
+ // Swallowing a non-paste CSI sequence: drop characters until the CSI
52
+ // terminator byte arrives, then resume normal processing.
53
+ if (state.swallowingCsi) {
54
+ if (isCsiTerminator(char))
55
+ state.swallowingCsi = false;
56
+ continue;
57
+ }
58
+ // Accumulate potential bracketed-paste marker.
59
+ if (state.escBuf || char === "\x1b") {
60
+ state.escBuf += char;
61
+ if (state.escBuf === PASTE_START) {
62
+ state.inPaste = true;
63
+ state.escBuf = "";
64
+ continue;
65
+ }
66
+ if (state.escBuf === PASTE_END) {
67
+ state.inPaste = false;
68
+ state.escBuf = "";
69
+ continue;
70
+ }
71
+ // If escBuf is no longer a prefix of either paste marker, it's a
72
+ // different escape sequence (arrow keys, Delete, F-keys, etc.). Switch
73
+ // to swallow-until-terminator mode so we don't leak the sequence's
74
+ // final byte (e.g. `~` from `\x1b[3~`) into the input buffer.
75
+ if (!PASTE_START.startsWith(state.escBuf) &&
76
+ !PASTE_END.startsWith(state.escBuf)) {
77
+ // If the current char is already a terminator, we've consumed the
78
+ // entire sequence; no need to swallow more.
79
+ state.swallowingCsi = !isCsiTerminator(char);
80
+ state.escBuf = "";
81
+ }
82
+ continue;
83
+ }
84
+ // Inside a bracketed paste, newlines are literal content.
85
+ if (state.inPaste) {
86
+ state.input += char;
87
+ continue;
88
+ }
89
+ if (char === CTRL_C)
90
+ return "ctrl-c";
91
+ if (char === CTRL_D) {
92
+ // Explicit end-of-input (multi-line escape hatch for terminals without
93
+ // bracketed-paste support).
94
+ return "submit";
95
+ }
96
+ if (char === "\n" || char === "\r") {
97
+ // Single-line submit — preserves the old single-password UX.
98
+ return "submit";
99
+ }
100
+ if (char === BACKSPACE || char === BS) {
101
+ if (state.input.length > 0)
102
+ state.input = state.input.slice(0, -1);
103
+ continue;
104
+ }
105
+ state.input += char;
106
+ }
107
+ return "continue";
108
+ }
109
+ //# sourceMappingURL=hidden-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hidden-input.js","sourceRoot":"","sources":["../../src/cli/hidden-input.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,13 @@
27
27
  * - Vault is encrypted with AES-256-GCM
28
28
  * - Key stored via pluggable provider (macOS Keychain or 1Password)
29
29
  * - 4-hour session timeout
30
+ *
31
+ * Internals:
32
+ * Vault mutations flow through `openVault` (session-vault.ts) so the CLI
33
+ * and the library-facing API share one on-disk format (AAD-bound, schema 1).
34
+ * Pre-`openVault` CLI-written vaults (AAD-less, legacy flat format) are
35
+ * handled transparently by session-vault's legacy-read path and upgraded to
36
+ * schema 1 on the next successful write.
30
37
  */
31
38
  export interface SecretsOptions {
32
39
  command: "init" | "unlock" | "lock" | "list" | "list-backend-keys" | "set" | "get" | "delete" | "status" | "migrate" | "env-list" | "env-switch" | "env-create" | "env-current";
@@ -1 +1 @@
1
- {"version":3,"file":"secrets-cli.d.ts","sourceRoot":"","sources":["../../src/cli/secrets-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAWH,MAAM,WAAW,cAAc;IAC7B,OAAO,EACH,MAAM,GACN,QAAQ,GACR,MAAM,GACN,MAAM,GACN,mBAAmB,GACnB,KAAK,GACL,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAirBD;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDvE"}
1
+ {"version":3,"file":"secrets-cli.d.ts","sourceRoot":"","sources":["../../src/cli/secrets-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAkBH,MAAM,WAAW,cAAc;IAC7B,OAAO,EACH,MAAM,GACN,QAAQ,GACR,MAAM,GACN,MAAM,GACN,mBAAmB,GACnB,KAAK,GACL,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAovBD;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDvE"}