sigild 0.0.1 → 0.0.3
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 +142 -33
- package/THREAT_MODEL.md +47 -19
- package/dist/src/bin/sigil-hook-post.d.ts +3 -0
- package/dist/src/bin/sigil-hook-post.d.ts.map +1 -0
- package/dist/src/bin/sigil-hook-post.js +15 -0
- package/dist/src/bin/sigil-hook-post.js.map +1 -0
- package/dist/src/bin/sigil-hook-pre.d.ts +3 -0
- package/dist/src/bin/sigil-hook-pre.d.ts.map +1 -0
- package/dist/src/bin/sigil-hook-pre.js +18 -0
- package/dist/src/bin/sigil-hook-pre.js.map +1 -0
- package/dist/src/bin/sigil-mcp.d.ts +3 -0
- package/dist/src/bin/sigil-mcp.d.ts.map +1 -0
- package/dist/src/bin/sigil-mcp.js +90 -0
- package/dist/src/bin/sigil-mcp.js.map +1 -0
- package/dist/src/bin/sigil.d.ts +3 -0
- package/dist/src/bin/sigil.d.ts.map +1 -0
- package/dist/src/bin/sigil.js +9 -0
- package/dist/src/bin/sigil.js.map +1 -0
- package/dist/src/cli/args.d.ts +26 -0
- package/dist/src/cli/args.d.ts.map +1 -0
- package/dist/src/cli/args.js +36 -0
- package/dist/src/cli/args.js.map +1 -0
- package/dist/src/cli/index.d.ts +7 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +7 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/main.d.ts +26 -0
- package/dist/src/cli/main.d.ts.map +1 -0
- package/dist/src/cli/main.js +197 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/paths.d.ts +18 -0
- package/dist/src/cli/paths.d.ts.map +1 -0
- package/dist/src/cli/paths.js +13 -0
- package/dist/src/cli/paths.js.map +1 -0
- package/dist/src/cli/portal.d.ts +59 -0
- package/dist/src/cli/portal.d.ts.map +1 -0
- package/dist/src/cli/portal.js +112 -0
- package/dist/src/cli/portal.js.map +1 -0
- package/dist/src/cli/status.d.ts +28 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +59 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/cli/unlock.d.ts +36 -0
- package/dist/src/cli/unlock.d.ts.map +1 -0
- package/dist/src/cli/unlock.js +77 -0
- package/dist/src/cli/unlock.js.map +1 -0
- package/dist/src/control/client.d.ts +26 -0
- package/dist/src/control/client.d.ts.map +1 -0
- package/dist/src/control/client.js +76 -0
- package/dist/src/control/client.js.map +1 -0
- package/dist/src/control/index.d.ts +4 -0
- package/dist/src/control/index.d.ts.map +1 -0
- package/dist/src/control/index.js +4 -0
- package/dist/src/control/index.js.map +1 -0
- package/dist/src/control/protocol.d.ts +54 -0
- package/dist/src/control/protocol.d.ts.map +1 -0
- package/dist/src/control/protocol.js +60 -0
- package/dist/src/control/protocol.js.map +1 -0
- package/dist/src/control/server.d.ts +52 -0
- package/dist/src/control/server.d.ts.map +1 -0
- package/dist/src/control/server.js +199 -0
- package/dist/src/control/server.js.map +1 -0
- package/dist/src/daemon/handles.d.ts +35 -6
- package/dist/src/daemon/handles.d.ts.map +1 -1
- package/dist/src/daemon/handles.js +83 -28
- package/dist/src/daemon/handles.js.map +1 -1
- package/dist/src/daemon/index.d.ts +2 -3
- package/dist/src/daemon/index.d.ts.map +1 -1
- package/dist/src/daemon/index.js +2 -3
- package/dist/src/daemon/index.js.map +1 -1
- package/dist/src/daemon/methods.d.ts +13 -0
- package/dist/src/daemon/methods.d.ts.map +1 -1
- package/dist/src/daemon/methods.js +50 -1
- package/dist/src/daemon/methods.js.map +1 -1
- package/dist/src/hooks/command-scanner.d.ts +5 -0
- package/dist/src/hooks/command-scanner.d.ts.map +1 -0
- package/dist/src/hooks/command-scanner.js +117 -0
- package/dist/src/hooks/command-scanner.js.map +1 -0
- package/dist/src/hooks/glob.d.ts +8 -0
- package/dist/src/hooks/glob.d.ts.map +1 -0
- package/dist/src/hooks/glob.js +98 -0
- package/dist/src/hooks/glob.js.map +1 -0
- package/dist/src/hooks/index.d.ts +9 -0
- package/dist/src/hooks/index.d.ts.map +1 -0
- package/dist/src/hooks/index.js +9 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/install.d.ts +29 -0
- package/dist/src/hooks/install.d.ts.map +1 -0
- package/dist/src/hooks/install.js +86 -0
- package/dist/src/hooks/install.js.map +1 -0
- package/dist/src/hooks/path-blocker.d.ts +29 -0
- package/dist/src/hooks/path-blocker.d.ts.map +1 -0
- package/dist/src/hooks/path-blocker.js +59 -0
- package/dist/src/hooks/path-blocker.js.map +1 -0
- package/dist/src/hooks/post-tool-use.d.ts +13 -0
- package/dist/src/hooks/post-tool-use.d.ts.map +1 -0
- package/dist/src/hooks/post-tool-use.js +45 -0
- package/dist/src/hooks/post-tool-use.js.map +1 -0
- package/dist/src/hooks/pre-tool-use.d.ts +8 -0
- package/dist/src/hooks/pre-tool-use.d.ts.map +1 -0
- package/dist/src/hooks/pre-tool-use.js +38 -0
- package/dist/src/hooks/pre-tool-use.js.map +1 -0
- package/dist/src/hooks/protocol.d.ts +41 -0
- package/dist/src/hooks/protocol.d.ts.map +1 -0
- package/dist/src/hooks/protocol.js +27 -0
- package/dist/src/hooks/protocol.js.map +1 -0
- package/dist/src/hooks/redactor.d.ts +19 -0
- package/dist/src/hooks/redactor.d.ts.map +1 -0
- package/dist/src/hooks/redactor.js +71 -0
- package/dist/src/hooks/redactor.js.map +1 -0
- package/dist/src/mcp/index.d.ts +4 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +4 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/protocol.d.ts +98 -0
- package/dist/src/mcp/protocol.d.ts.map +1 -0
- package/dist/src/mcp/protocol.js +79 -0
- package/dist/src/mcp/protocol.js.map +1 -0
- package/dist/src/mcp/server.d.ts +46 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +108 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +16 -0
- package/dist/src/mcp/tools.d.ts.map +1 -0
- package/dist/src/mcp/tools.js +117 -0
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/policy/evaluate.d.ts +13 -0
- package/dist/src/policy/evaluate.d.ts.map +1 -0
- package/dist/src/policy/evaluate.js +73 -0
- package/dist/src/policy/evaluate.js.map +1 -0
- package/dist/src/policy/index.d.ts +5 -0
- package/dist/src/policy/index.d.ts.map +1 -0
- package/dist/src/policy/index.js +5 -0
- package/dist/src/policy/index.js.map +1 -0
- package/dist/src/policy/loader.d.ts +33 -0
- package/dist/src/policy/loader.d.ts.map +1 -0
- package/dist/src/policy/loader.js +170 -0
- package/dist/src/policy/loader.js.map +1 -0
- package/dist/src/policy/template.d.ts +10 -0
- package/dist/src/policy/template.d.ts.map +1 -0
- package/dist/src/policy/template.js +69 -0
- package/dist/src/policy/template.js.map +1 -0
- package/dist/src/policy/types.d.ts +62 -0
- package/dist/src/policy/types.d.ts.map +1 -0
- package/dist/src/policy/types.js +10 -0
- package/dist/src/policy/types.js.map +1 -0
- package/package.json +9 -3
- package/dist/src/bin/sigild.d.ts +0 -3
- package/dist/src/bin/sigild.d.ts.map +0 -1
- package/dist/src/bin/sigild.js +0 -30
- package/dist/src/bin/sigild.js.map +0 -1
- package/dist/src/daemon/rpc.d.ts +0 -61
- package/dist/src/daemon/rpc.d.ts.map +0 -1
- package/dist/src/daemon/rpc.js +0 -76
- package/dist/src/daemon/rpc.js.map +0 -1
- package/dist/src/daemon/runtime.d.ts +0 -40
- package/dist/src/daemon/runtime.d.ts.map +0 -1
- package/dist/src/daemon/runtime.js +0 -61
- package/dist/src/daemon/runtime.js.map +0 -1
- package/dist/src/daemon/server.d.ts +0 -53
- package/dist/src/daemon/server.d.ts.map +0 -1
- package/dist/src/daemon/server.js +0 -103
- package/dist/src/daemon/server.js.map +0 -1
|
@@ -11,9 +11,16 @@ export declare class HandleLoadError extends Error {
|
|
|
11
11
|
/**
|
|
12
12
|
* In-memory registry of handle → unlocked SecretBuffer.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Lifecycle inside sigil-mcp:
|
|
15
|
+
* - Constructed empty + locked at startup.
|
|
16
|
+
* - `sigil unlock` calls loadFromDir / addEntry → table becomes unlocked.
|
|
17
|
+
* - `sigil lock` calls lock() → entries zeroed + cleared, table re-lockable.
|
|
18
|
+
* - Process exit calls dispose() → final teardown, no further use.
|
|
19
|
+
*
|
|
20
|
+
* The unlocked flag is tracked separately from entry count so that an unlock
|
|
21
|
+
* with zero portals on disk still distinguishes "no portals exist" (handle
|
|
22
|
+
* lookup → PORTAL_NOT_FOUND) from "never unlocked" (handle lookup →
|
|
23
|
+
* DAEMON_LOCKED).
|
|
17
24
|
*/
|
|
18
25
|
export declare class HandleTable {
|
|
19
26
|
#private;
|
|
@@ -24,17 +31,31 @@ export declare class HandleTable {
|
|
|
24
31
|
static handleFromFilename(filename: string): string | null;
|
|
25
32
|
/**
|
|
26
33
|
* Load every keyfile in `dir` named `<handle>.sigil`, decrypting each with
|
|
27
|
-
* the same passphrase. Throws HandleLoadError on any failure
|
|
34
|
+
* the same passphrase. Throws HandleLoadError on any failure; on failure
|
|
35
|
+
* the table is left locked with any partially-loaded entries zeroized.
|
|
28
36
|
*
|
|
29
37
|
* Order: deterministic by sorted filename, so audit logs and list_portals
|
|
30
38
|
* output are stable across restarts.
|
|
39
|
+
*
|
|
40
|
+
* Marks the table as unlocked on success — even if the directory was
|
|
41
|
+
* empty (zero portals to load). After that, sign calls see PORTAL_NOT_FOUND
|
|
42
|
+
* instead of DAEMON_LOCKED.
|
|
31
43
|
*/
|
|
32
44
|
loadFromDir(dir: string, passphrase: Buffer): void;
|
|
33
45
|
/**
|
|
34
46
|
* Add a handle directly (for tests or for non-file-backed key sources).
|
|
35
|
-
* Takes ownership of the SecretBuffer; dispose() will zeroize it.
|
|
47
|
+
* Takes ownership of the SecretBuffer; lock()/dispose() will zeroize it.
|
|
48
|
+
* Does NOT flip the unlocked flag — loadFromDir does that once after a
|
|
49
|
+
* successful pass. Tests that want an unlocked table should call
|
|
50
|
+
* markUnlocked() explicitly.
|
|
36
51
|
*/
|
|
37
52
|
addEntry(handle: string, secret: SecretBuffer): void;
|
|
53
|
+
/**
|
|
54
|
+
* Explicitly mark the table as unlocked without loading anything. Useful
|
|
55
|
+
* for tests that pre-populate via addEntry and want sign methods to
|
|
56
|
+
* succeed.
|
|
57
|
+
*/
|
|
58
|
+
markUnlocked(): void;
|
|
38
59
|
has(handle: string): boolean;
|
|
39
60
|
/**
|
|
40
61
|
* Returns the SecretBuffer for the handle. Caller must NOT dispose it —
|
|
@@ -42,8 +63,16 @@ export declare class HandleTable {
|
|
|
42
63
|
*/
|
|
43
64
|
get(handle: string): SecretBuffer | undefined;
|
|
44
65
|
list(): PortalInfo[];
|
|
66
|
+
isUnlocked(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Zeroize every entry and re-lock the table. The table remains usable —
|
|
69
|
+
* a subsequent unlock can repopulate it. Idempotent.
|
|
70
|
+
*/
|
|
71
|
+
lock(): void;
|
|
45
72
|
/**
|
|
46
|
-
*
|
|
73
|
+
* Final teardown: zeroize every key and mark the table unusable. After
|
|
74
|
+
* dispose(), get/has/list/lock/markUnlocked/addEntry/loadFromDir throw.
|
|
75
|
+
* Idempotent.
|
|
47
76
|
*/
|
|
48
77
|
dispose(): void;
|
|
49
78
|
get isDisposed(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handles.d.ts","sourceRoot":"","sources":["../../../src/daemon/handles.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBACtB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAK7C;AAED
|
|
1
|
+
{"version":3,"file":"handles.d.ts","sourceRoot":"","sources":["../../../src/daemon/handles.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBACtB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAK7C;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAW;;IAMtB,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAMjE,MAAM,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO1D;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAyClD;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IAcpD;;;;OAIG;IACH,YAAY,IAAI,IAAI;IAKpB,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAK5B;;;OAGG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAK7C,IAAI,IAAI,UAAU,EAAE;IAKpB,UAAU,IAAI,OAAO;IAKrB;;;OAGG;IACH,IAAI,IAAI,IAAI;IAOZ;;;;OAIG;IACH,OAAO,IAAI,IAAI;IAQf,IAAI,UAAU,IAAI,OAAO,CAExB;CACF"}
|
|
@@ -19,13 +19,21 @@ export class HandleLoadError extends Error {
|
|
|
19
19
|
/**
|
|
20
20
|
* In-memory registry of handle → unlocked SecretBuffer.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Lifecycle inside sigil-mcp:
|
|
23
|
+
* - Constructed empty + locked at startup.
|
|
24
|
+
* - `sigil unlock` calls loadFromDir / addEntry → table becomes unlocked.
|
|
25
|
+
* - `sigil lock` calls lock() → entries zeroed + cleared, table re-lockable.
|
|
26
|
+
* - Process exit calls dispose() → final teardown, no further use.
|
|
27
|
+
*
|
|
28
|
+
* The unlocked flag is tracked separately from entry count so that an unlock
|
|
29
|
+
* with zero portals on disk still distinguishes "no portals exist" (handle
|
|
30
|
+
* lookup → PORTAL_NOT_FOUND) from "never unlocked" (handle lookup →
|
|
31
|
+
* DAEMON_LOCKED).
|
|
25
32
|
*/
|
|
26
33
|
export class HandleTable {
|
|
27
34
|
// Wrapped in a private map; not exposed.
|
|
28
35
|
#entries = new Map();
|
|
36
|
+
#unlocked = false;
|
|
29
37
|
#disposed = false;
|
|
30
38
|
static parseHandle(handle) {
|
|
31
39
|
const m = HANDLE_RE.exec(handle);
|
|
@@ -43,10 +51,15 @@ export class HandleTable {
|
|
|
43
51
|
}
|
|
44
52
|
/**
|
|
45
53
|
* Load every keyfile in `dir` named `<handle>.sigil`, decrypting each with
|
|
46
|
-
* the same passphrase. Throws HandleLoadError on any failure
|
|
54
|
+
* the same passphrase. Throws HandleLoadError on any failure; on failure
|
|
55
|
+
* the table is left locked with any partially-loaded entries zeroized.
|
|
47
56
|
*
|
|
48
57
|
* Order: deterministic by sorted filename, so audit logs and list_portals
|
|
49
58
|
* output are stable across restarts.
|
|
59
|
+
*
|
|
60
|
+
* Marks the table as unlocked on success — even if the directory was
|
|
61
|
+
* empty (zero portals to load). After that, sign calls see PORTAL_NOT_FOUND
|
|
62
|
+
* instead of DAEMON_LOCKED.
|
|
50
63
|
*/
|
|
51
64
|
loadFromDir(dir, passphrase) {
|
|
52
65
|
if (this.#disposed)
|
|
@@ -56,38 +69,50 @@ export class HandleTable {
|
|
|
56
69
|
entries = readdirSync(dir).sort();
|
|
57
70
|
}
|
|
58
71
|
catch (err) {
|
|
59
|
-
if (err.code === 'ENOENT')
|
|
72
|
+
if (err.code === 'ENOENT') {
|
|
73
|
+
this.#unlocked = true;
|
|
60
74
|
return;
|
|
75
|
+
}
|
|
61
76
|
throw new HandleLoadError(`failed to read keys directory ${dir}`, err);
|
|
62
77
|
}
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
catch (err) {
|
|
73
|
-
throw new HandleLoadError(`failed to read keyfile ${path}`, err);
|
|
74
|
-
}
|
|
75
|
-
let secret;
|
|
76
|
-
try {
|
|
77
|
-
secret = unsealKey(blob, passphrase);
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
if (err instanceof WrongPassphraseError) {
|
|
81
|
-
throw new HandleLoadError(`wrong passphrase or tampered keyfile: ${path}`, err);
|
|
78
|
+
try {
|
|
79
|
+
for (const filename of entries) {
|
|
80
|
+
const handle = HandleTable.handleFromFilename(filename);
|
|
81
|
+
if (handle === null)
|
|
82
|
+
continue;
|
|
83
|
+
const path = join(dir, filename);
|
|
84
|
+
let blob;
|
|
85
|
+
try {
|
|
86
|
+
blob = readFileSync(path);
|
|
82
87
|
}
|
|
83
|
-
|
|
88
|
+
catch (err) {
|
|
89
|
+
throw new HandleLoadError(`failed to read keyfile ${path}`, err);
|
|
90
|
+
}
|
|
91
|
+
let secret;
|
|
92
|
+
try {
|
|
93
|
+
secret = unsealKey(blob, passphrase);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (err instanceof WrongPassphraseError) {
|
|
97
|
+
throw new HandleLoadError(`wrong passphrase or tampered keyfile: ${path}`, err);
|
|
98
|
+
}
|
|
99
|
+
throw new HandleLoadError(`failed to unseal keyfile ${path}`, err);
|
|
100
|
+
}
|
|
101
|
+
this.addEntry(handle, secret);
|
|
84
102
|
}
|
|
85
|
-
this
|
|
103
|
+
this.#unlocked = true;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
this.lock();
|
|
107
|
+
throw err;
|
|
86
108
|
}
|
|
87
109
|
}
|
|
88
110
|
/**
|
|
89
111
|
* Add a handle directly (for tests or for non-file-backed key sources).
|
|
90
|
-
* Takes ownership of the SecretBuffer; dispose() will zeroize it.
|
|
112
|
+
* Takes ownership of the SecretBuffer; lock()/dispose() will zeroize it.
|
|
113
|
+
* Does NOT flip the unlocked flag — loadFromDir does that once after a
|
|
114
|
+
* successful pass. Tests that want an unlocked table should call
|
|
115
|
+
* markUnlocked() explicitly.
|
|
91
116
|
*/
|
|
92
117
|
addEntry(handle, secret) {
|
|
93
118
|
if (this.#disposed)
|
|
@@ -103,6 +128,16 @@ export class HandleTable {
|
|
|
103
128
|
info: { handle, kind: 'eth', address },
|
|
104
129
|
});
|
|
105
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Explicitly mark the table as unlocked without loading anything. Useful
|
|
133
|
+
* for tests that pre-populate via addEntry and want sign methods to
|
|
134
|
+
* succeed.
|
|
135
|
+
*/
|
|
136
|
+
markUnlocked() {
|
|
137
|
+
if (this.#disposed)
|
|
138
|
+
throw new Error('HandleTable is disposed');
|
|
139
|
+
this.#unlocked = true;
|
|
140
|
+
}
|
|
106
141
|
has(handle) {
|
|
107
142
|
if (this.#disposed)
|
|
108
143
|
throw new Error('HandleTable is disposed');
|
|
@@ -122,8 +157,27 @@ export class HandleTable {
|
|
|
122
157
|
throw new Error('HandleTable is disposed');
|
|
123
158
|
return Array.from(this.#entries.values()).map((e) => ({ ...e.info }));
|
|
124
159
|
}
|
|
160
|
+
isUnlocked() {
|
|
161
|
+
if (this.#disposed)
|
|
162
|
+
return false;
|
|
163
|
+
return this.#unlocked;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Zeroize every entry and re-lock the table. The table remains usable —
|
|
167
|
+
* a subsequent unlock can repopulate it. Idempotent.
|
|
168
|
+
*/
|
|
169
|
+
lock() {
|
|
170
|
+
if (this.#disposed)
|
|
171
|
+
return;
|
|
172
|
+
for (const e of this.#entries.values())
|
|
173
|
+
e.secret.dispose();
|
|
174
|
+
this.#entries.clear();
|
|
175
|
+
this.#unlocked = false;
|
|
176
|
+
}
|
|
125
177
|
/**
|
|
126
|
-
*
|
|
178
|
+
* Final teardown: zeroize every key and mark the table unusable. After
|
|
179
|
+
* dispose(), get/has/list/lock/markUnlocked/addEntry/loadFromDir throw.
|
|
180
|
+
* Idempotent.
|
|
127
181
|
*/
|
|
128
182
|
dispose() {
|
|
129
183
|
if (this.#disposed)
|
|
@@ -131,6 +185,7 @@ export class HandleTable {
|
|
|
131
185
|
for (const e of this.#entries.values())
|
|
132
186
|
e.secret.dispose();
|
|
133
187
|
this.#entries.clear();
|
|
188
|
+
this.#unlocked = false;
|
|
134
189
|
this.#disposed = true;
|
|
135
190
|
}
|
|
136
191
|
get isDisposed() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handles.js","sourceRoot":"","sources":["../../../src/daemon/handles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAEL,SAAS,EACT,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,GAAG,QAAQ,CAAC;AAC7B,6EAA6E;AAC7E,uEAAuE;AACvE,gDAAgD;AAChD,MAAM,SAAS,GAAG,0BAA0B,CAAC;AAQ7C,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACtB,KAAK,CAAW;IAClC,YAAY,OAAe,EAAE,KAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC9C,CAAC;CACF;AAED
|
|
1
|
+
{"version":3,"file":"handles.js","sourceRoot":"","sources":["../../../src/daemon/handles.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { type RpcId, type RpcRequest, type RpcResponse, type RpcSuccess, type RpcError, type RpcErrorObject, type ParseResult, RPC_VERSION, RPC_PARSE_ERROR, RPC_INVALID_REQUEST, RPC_METHOD_NOT_FOUND, RPC_INVALID_PARAMS, RPC_INTERNAL_ERROR, RPC_PORTAL_NOT_FOUND, RPC_POLICY_DENIED, RPC_INVALID_PAYLOAD, parseRequest, encodeResponse, encodeError, } from './rpc.js';
|
|
2
1
|
export { type PortalInfo, HandleLoadError, HandleTable, } from './handles.js';
|
|
3
|
-
export { type MethodContext, type MethodHandler, RpcMethodError, METHODS, dispatch, } from './methods.js';
|
|
4
|
-
export {
|
|
2
|
+
export { type MethodContext, type MethodHandler, RpcMethodError, RPC_INVALID_PARAMS, RPC_METHOD_NOT_FOUND, RPC_PORTAL_NOT_FOUND, RPC_POLICY_DENIED, RPC_INVALID_PAYLOAD, RPC_DAEMON_LOCKED, METHODS, dispatch, } from './methods.js';
|
|
3
|
+
export { readPassphrase, type ReadPassphraseDeps } from './passphrase.js';
|
|
5
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,eAAe,EACf,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,OAAO,EACP,QAAQ,GACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/src/daemon/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { RPC_VERSION, RPC_PARSE_ERROR, RPC_INVALID_REQUEST, RPC_METHOD_NOT_FOUND, RPC_INVALID_PARAMS, RPC_INTERNAL_ERROR, RPC_PORTAL_NOT_FOUND, RPC_POLICY_DENIED, RPC_INVALID_PAYLOAD, parseRequest, encodeResponse, encodeError, } from './rpc.js';
|
|
2
1
|
export { HandleLoadError, HandleTable, } from './handles.js';
|
|
3
|
-
export { RpcMethodError, METHODS, dispatch, } from './methods.js';
|
|
4
|
-
export {
|
|
2
|
+
export { RpcMethodError, RPC_INVALID_PARAMS, RPC_METHOD_NOT_FOUND, RPC_PORTAL_NOT_FOUND, RPC_POLICY_DENIED, RPC_INVALID_PAYLOAD, RPC_DAEMON_LOCKED, METHODS, dispatch, } from './methods.js';
|
|
3
|
+
export { readPassphrase } from './passphrase.js';
|
|
5
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/daemon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,OAAO,EACP,QAAQ,GACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAA2B,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { type AuditWriter } from '../audit/index.js';
|
|
2
|
+
import { type PolicyResolver } from '../policy/index.js';
|
|
2
3
|
import { type HandleTable } from './handles.js';
|
|
4
|
+
export declare const RPC_INVALID_PARAMS = -32602;
|
|
5
|
+
export declare const RPC_METHOD_NOT_FOUND = -32601;
|
|
6
|
+
export declare const RPC_PORTAL_NOT_FOUND = -32000;
|
|
7
|
+
export declare const RPC_POLICY_DENIED = -32001;
|
|
8
|
+
export declare const RPC_INVALID_PAYLOAD = -32002;
|
|
9
|
+
export declare const RPC_DAEMON_LOCKED = -32003;
|
|
3
10
|
export declare class RpcMethodError extends Error {
|
|
4
11
|
readonly code: number;
|
|
5
12
|
readonly data: unknown;
|
|
@@ -8,6 +15,12 @@ export declare class RpcMethodError extends Error {
|
|
|
8
15
|
export interface MethodContext {
|
|
9
16
|
handles: HandleTable;
|
|
10
17
|
audit: AuditWriter;
|
|
18
|
+
/**
|
|
19
|
+
* Resolves the per-portal policy at evaluation time. Wrapped in an
|
|
20
|
+
* interface so tests can inject a constant policy without touching the
|
|
21
|
+
* filesystem.
|
|
22
|
+
*/
|
|
23
|
+
policy: PolicyResolver;
|
|
11
24
|
}
|
|
12
25
|
export type MethodHandler = (params: unknown, ctx: MethodContext) => unknown;
|
|
13
26
|
export declare const METHODS: Readonly<Record<string, MethodHandler>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"methods.d.ts","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAKhD,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAE3C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAExC,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBACX,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO;CAM1D;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;AA4P7E,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAK1D,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAMrF"}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { personalSign, signTransaction, signTypedData, } from '../eth/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { evaluate, PolicyLoadError, } from '../policy/index.js';
|
|
3
|
+
// Error codes — these match JSON-RPC 2.0 standard error codes plus a
|
|
4
|
+
// sigil-specific range (-32000..-32099). They flow through the MCP wire
|
|
5
|
+
// unchanged so the client sees the exact diagnosis.
|
|
6
|
+
export const RPC_INVALID_PARAMS = -32602;
|
|
7
|
+
export const RPC_METHOD_NOT_FOUND = -32601;
|
|
8
|
+
// Sigil-specific:
|
|
9
|
+
export const RPC_PORTAL_NOT_FOUND = -32000;
|
|
10
|
+
export const RPC_POLICY_DENIED = -32001;
|
|
11
|
+
export const RPC_INVALID_PAYLOAD = -32002;
|
|
12
|
+
export const RPC_DAEMON_LOCKED = -32003;
|
|
3
13
|
export class RpcMethodError extends Error {
|
|
4
14
|
code;
|
|
5
15
|
data;
|
|
@@ -33,12 +43,44 @@ function hexToBuf(s, methodName, key) {
|
|
|
33
43
|
return Buffer.from(s.slice(2), 'hex');
|
|
34
44
|
}
|
|
35
45
|
function requirePortal(handles, handle) {
|
|
46
|
+
if (!handles.isUnlocked()) {
|
|
47
|
+
throw new RpcMethodError(RPC_DAEMON_LOCKED, 'sigil is locked — run "sigil unlock" in a terminal to load keys');
|
|
48
|
+
}
|
|
36
49
|
const sb = handles.get(handle);
|
|
37
50
|
if (!sb) {
|
|
38
51
|
throw new RpcMethodError(RPC_PORTAL_NOT_FOUND, `portal "${handle}" not found`);
|
|
39
52
|
}
|
|
40
53
|
return sb.bytes();
|
|
41
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the portal's policy and evaluate the request. On Deny — or on any
|
|
57
|
+
* PolicyLoadError (missing file, malformed TOML) — appends a deny entry to
|
|
58
|
+
* the audit log AND throws RPC_POLICY_DENIED. Returns silently on Allow.
|
|
59
|
+
*
|
|
60
|
+
* The order is: require unlocked + portal first, then policy. That way the
|
|
61
|
+
* caller's mistakes (wrong handle, daemon locked) error before we touch the
|
|
62
|
+
* policy file at all.
|
|
63
|
+
*/
|
|
64
|
+
function gatePolicy(ctx, handle, kind, payload, request) {
|
|
65
|
+
let reason;
|
|
66
|
+
try {
|
|
67
|
+
const policy = ctx.policy.resolve(handle);
|
|
68
|
+
const decision = evaluate(request, policy);
|
|
69
|
+
if (decision.allow)
|
|
70
|
+
return;
|
|
71
|
+
reason = decision.reason;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
if (err instanceof PolicyLoadError) {
|
|
75
|
+
reason = err.message;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
ctx.audit.append({ kind, portal: handle, payload, decision: 'deny', reason });
|
|
82
|
+
throw new RpcMethodError(RPC_POLICY_DENIED, reason);
|
|
83
|
+
}
|
|
42
84
|
// ---------------------------------------------------------------------------
|
|
43
85
|
// Methods
|
|
44
86
|
// ---------------------------------------------------------------------------
|
|
@@ -51,6 +93,9 @@ const sigil_eth_sign_message = (params, ctx) => {
|
|
|
51
93
|
const messageHex = asString(obj, 'message', 'eth_sign_message');
|
|
52
94
|
const message = hexToBuf(messageHex, 'eth_sign_message', 'message');
|
|
53
95
|
const priv = requirePortal(ctx.handles, portal);
|
|
96
|
+
gatePolicy(ctx, portal, 'eth_sign_message', { message: messageHex }, {
|
|
97
|
+
kind: 'message', messageBytes: message,
|
|
98
|
+
});
|
|
54
99
|
const sig = personalSign(message, priv);
|
|
55
100
|
const sigHex = ('0x' + sig.toString('hex'));
|
|
56
101
|
ctx.audit.append({
|
|
@@ -163,6 +208,7 @@ const sigil_eth_sign_transaction = (params, ctx) => {
|
|
|
163
208
|
}
|
|
164
209
|
const tx = asTx(txObj);
|
|
165
210
|
const priv = requirePortal(ctx.handles, portal);
|
|
211
|
+
gatePolicy(ctx, portal, 'eth_sign_transaction', { tx: txObj }, { kind: 'transaction', tx });
|
|
166
212
|
const signed = signTransaction(tx, priv);
|
|
167
213
|
ctx.audit.append({
|
|
168
214
|
kind: 'eth_sign_transaction',
|
|
@@ -183,6 +229,9 @@ const sigil_eth_sign_typed_data = (params, ctx) => {
|
|
|
183
229
|
// We trust the typed-data shape minimally — sign-typed.ts will throw
|
|
184
230
|
// on missing fields; we wrap that as INVALID_PARAMS for the caller.
|
|
185
231
|
const priv = requirePortal(ctx.handles, portal);
|
|
232
|
+
gatePolicy(ctx, portal, 'eth_sign_typed_data', { typedData: td }, {
|
|
233
|
+
kind: 'typed_data', typedData: td,
|
|
234
|
+
});
|
|
186
235
|
let sig;
|
|
187
236
|
try {
|
|
188
237
|
sig = signTypedData(td, priv);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"methods.js","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,YAAY,EAEZ,eAAe,EACf,aAAa,GAEd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,
|
|
1
|
+
{"version":3,"file":"methods.js","sourceRoot":"","sources":["../../../src/daemon/methods.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-scanner.d.ts","sourceRoot":"","sources":["../../../src/hooks/command-scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAwBxF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,aAAa,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA+B5G"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { isBlockedPath } from './path-blocker.js';
|
|
2
|
+
/**
|
|
3
|
+
* Scan a bash command for attempts to read a blocked path. Best-effort:
|
|
4
|
+
* a determined shell can always obfuscate, but we catch the obvious cases
|
|
5
|
+
* that a confused agent (or basic prompt injection) would produce.
|
|
6
|
+
*
|
|
7
|
+
* Approach:
|
|
8
|
+
* 1. Tokenize the command crudely on whitespace and shell metacharacters.
|
|
9
|
+
* 2. Skip the first token of each statement (the program name itself).
|
|
10
|
+
* 3. Check each remaining token against the path blocker.
|
|
11
|
+
* 4. Also detect a few "always block" reader commands when they appear at
|
|
12
|
+
* a position that suggests they're targeting a key (e.g. `gpg
|
|
13
|
+
* --export-secret-keys`).
|
|
14
|
+
*/
|
|
15
|
+
const COMMAND_SEPARATORS = /[;&|]|\$\(|`/;
|
|
16
|
+
const ALWAYS_BLOCK_COMMAND_PATTERNS = Object.freeze([
|
|
17
|
+
{ regex: /\bgpg\b[^|;]*--export-secret-keys?/i, reason: 'gpg --export-secret-keys reads private GPG key material' },
|
|
18
|
+
{ regex: /\bssh-keygen\b[^|;]*-y\b/i, reason: 'ssh-keygen -y reads a private SSH key to derive the public key' },
|
|
19
|
+
{ regex: /\bopenssl\b[^|;]*(pkey|rsa|ec)\b[^|;]*-(in|noout)/i, reason: 'openssl key dump' },
|
|
20
|
+
]);
|
|
21
|
+
export function scanBashCommand(command, opts = {}) {
|
|
22
|
+
// Check always-block patterns first; they're command-shape based.
|
|
23
|
+
for (const { regex, reason } of ALWAYS_BLOCK_COMMAND_PATTERNS) {
|
|
24
|
+
if (regex.test(command)) {
|
|
25
|
+
return { blocked: true, reason };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Tokenize the command. Split on statement separators first so we treat
|
|
29
|
+
// each statement's program name separately.
|
|
30
|
+
const statements = command.split(COMMAND_SEPARATORS);
|
|
31
|
+
for (const stmt of statements) {
|
|
32
|
+
const tokens = tokenize(stmt);
|
|
33
|
+
if (tokens.length === 0)
|
|
34
|
+
continue;
|
|
35
|
+
// Skip the first token (program name) — we don't want to block on a path
|
|
36
|
+
// that happens to coincide with the script being executed. Args follow.
|
|
37
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
38
|
+
const tok = stripShellQuoting(tokens[i]);
|
|
39
|
+
if (looksLikePath(tok)) {
|
|
40
|
+
const decision = isBlockedPath(tok, opts);
|
|
41
|
+
if (decision.blocked) {
|
|
42
|
+
return {
|
|
43
|
+
blocked: true,
|
|
44
|
+
...(decision.matchedPattern ? { matchedPattern: decision.matchedPattern } : {}),
|
|
45
|
+
reason: `command argument "${tok}" matches blocked pattern ${decision.matchedPattern}`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { blocked: false };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Very crude tokenization: split on whitespace but respect quoted strings.
|
|
55
|
+
* Good enough for the obvious-read-attempt detection we're going for.
|
|
56
|
+
*/
|
|
57
|
+
function tokenize(s) {
|
|
58
|
+
const tokens = [];
|
|
59
|
+
let cur = '';
|
|
60
|
+
let inSingle = false;
|
|
61
|
+
let inDouble = false;
|
|
62
|
+
for (let i = 0; i < s.length; i++) {
|
|
63
|
+
const c = s[i];
|
|
64
|
+
if (c === '\\' && i + 1 < s.length) {
|
|
65
|
+
cur += c + s[i + 1];
|
|
66
|
+
i++;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (c === "'" && !inDouble) {
|
|
70
|
+
inSingle = !inSingle;
|
|
71
|
+
cur += c;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (c === '"' && !inSingle) {
|
|
75
|
+
inDouble = !inDouble;
|
|
76
|
+
cur += c;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (/\s/.test(c) && !inSingle && !inDouble) {
|
|
80
|
+
if (cur.length > 0) {
|
|
81
|
+
tokens.push(cur);
|
|
82
|
+
cur = '';
|
|
83
|
+
}
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
cur += c;
|
|
87
|
+
}
|
|
88
|
+
if (cur.length > 0)
|
|
89
|
+
tokens.push(cur);
|
|
90
|
+
return tokens;
|
|
91
|
+
}
|
|
92
|
+
function stripShellQuoting(tok) {
|
|
93
|
+
// Strip outer matching quotes; leave backslash escapes for the FS layer.
|
|
94
|
+
if (tok.length >= 2) {
|
|
95
|
+
const first = tok[0];
|
|
96
|
+
const last = tok[tok.length - 1];
|
|
97
|
+
if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
|
|
98
|
+
return tok.slice(1, -1);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return tok;
|
|
102
|
+
}
|
|
103
|
+
function looksLikePath(tok) {
|
|
104
|
+
// Flags don't look like paths.
|
|
105
|
+
if (tok.startsWith('-'))
|
|
106
|
+
return false;
|
|
107
|
+
// Heuristic: contains a slash, OR starts with a dot (e.g. ".env"),
|
|
108
|
+
// OR is a bare filename ending in a key-ish extension.
|
|
109
|
+
if (tok.includes('/'))
|
|
110
|
+
return true;
|
|
111
|
+
if (tok.startsWith('.'))
|
|
112
|
+
return true;
|
|
113
|
+
if (/\.(pem|key|keystore|jks|p12)$/i.test(tok))
|
|
114
|
+
return true;
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=command-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-scanner.js","sourceRoot":"","sources":["../../../src/hooks/command-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function expandTilde(path: string): string;
|
|
2
|
+
export declare function normalizePath(path: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Convert a glob pattern to a RegExp. Anchored to the full string.
|
|
5
|
+
*/
|
|
6
|
+
export declare function globToRegex(glob: string): RegExp;
|
|
7
|
+
export declare function globMatch(path: string, pattern: string): boolean;
|
|
8
|
+
//# sourceMappingURL=glob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../../src/hooks/glob.ts"],"names":[],"mappings":"AAgBA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIhD;AAmBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwChD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAEhE"}
|