@cybedefend/vibedefend 1.5.0 → 1.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.
- package/README.md +67 -2
- package/dist/api/gateway-request.js +49 -0
- package/dist/api/gateway-request.js.map +1 -0
- package/dist/api/projects.js +67 -0
- package/dist/api/projects.js.map +1 -1
- package/dist/api/repository-link.js +157 -0
- package/dist/api/repository-link.js.map +1 -0
- package/dist/auth/auth-store.js +107 -25
- package/dist/auth/auth-store.js.map +1 -1
- package/dist/auth/auth.js +21 -0
- package/dist/auth/auth.js.map +1 -1
- package/dist/clients/cursor.js +5 -1
- package/dist/clients/cursor.js.map +1 -1
- package/dist/clients/vscode.js +38 -29
- package/dist/clients/vscode.js.map +1 -1
- package/dist/commands/mcp/allow.js +219 -0
- package/dist/commands/mcp/allow.js.map +1 -0
- package/dist/commands/mcp/connect.js +337 -0
- package/dist/commands/mcp/connect.js.map +1 -0
- package/dist/commands/mcp/index.js +170 -0
- package/dist/commands/mcp/index.js.map +1 -0
- package/dist/commands/mcp/proxy.js +264 -0
- package/dist/commands/mcp/proxy.js.map +1 -0
- package/dist/commands/mcp/scan.js +349 -0
- package/dist/commands/mcp/scan.js.map +1 -0
- package/dist/commands/mcp/sync.js +215 -0
- package/dist/commands/mcp/sync.js.map +1 -0
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/diagnostics.js +78 -12
- package/dist/diagnostics.js.map +1 -1
- package/dist/doctor.js +19 -0
- package/dist/doctor.js.map +1 -1
- package/dist/guards-evaluator/analysis-types.js +27 -0
- package/dist/guards-evaluator/analysis-types.js.map +1 -0
- package/dist/guards-evaluator/command-analysis.js +572 -0
- package/dist/guards-evaluator/command-analysis.js.map +1 -0
- package/dist/guards-evaluator/command-view.js +586 -0
- package/dist/guards-evaluator/command-view.js.map +1 -0
- package/dist/guards-evaluator/env.js +11 -0
- package/dist/guards-evaluator/env.js.map +1 -0
- package/dist/guards-evaluator/evaluate.js +91 -41
- package/dist/guards-evaluator/evaluate.js.map +1 -1
- package/dist/guards-evaluator/index.js +2 -1
- package/dist/guards-evaluator/index.js.map +1 -1
- package/dist/guards-evaluator/inline-code.js +259 -0
- package/dist/guards-evaluator/inline-code.js.map +1 -0
- package/dist/guards-evaluator/normalize.js +716 -0
- package/dist/guards-evaluator/normalize.js.map +1 -0
- package/dist/guards-evaluator/preprocess.js +13 -5
- package/dist/guards-evaluator/preprocess.js.map +1 -1
- package/dist/guards-evaluator/redact.js +19 -0
- package/dist/guards-evaluator/redact.js.map +1 -1
- package/dist/guards-evaluator/regex.js +25 -3
- package/dist/guards-evaluator/regex.js.map +1 -1
- package/dist/guards-evaluator/safe-commands.js +155 -0
- package/dist/guards-evaluator/safe-commands.js.map +1 -0
- package/dist/guards-evaluator/triage.js +315 -0
- package/dist/guards-evaluator/triage.js.map +1 -0
- package/dist/hook-runner.js +24679 -5079
- package/dist/hooks/install.js +38 -0
- package/dist/hooks/install.js.map +1 -1
- package/dist/hooks/runtime/config.js +38 -0
- package/dist/hooks/runtime/config.js.map +1 -1
- package/dist/hooks/runtime/emit.js +94 -61
- package/dist/hooks/runtime/emit.js.map +1 -1
- package/dist/hooks/runtime/fetch-rules.js +22 -7
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/gateway-http-error.js +34 -0
- package/dist/hooks/runtime/gateway-http-error.js.map +1 -0
- package/dist/hooks/runtime/guard-rules-cache.js +139 -17
- package/dist/hooks/runtime/guard-rules-cache.js.map +1 -1
- package/dist/hooks/runtime/guard-violations-buffer.js +321 -48
- package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -1
- package/dist/hooks/runtime/judge-cache.js +6 -0
- package/dist/hooks/runtime/judge-cache.js.map +1 -1
- package/dist/hooks/runtime/judge-triage.js +193 -0
- package/dist/hooks/runtime/judge-triage.js.map +1 -0
- package/dist/hooks/runtime/judge.js +7 -1
- package/dist/hooks/runtime/judge.js.map +1 -1
- package/dist/hooks/runtime/pre-compact.js +12 -6
- package/dist/hooks/runtime/pre-compact.js.map +1 -1
- package/dist/hooks/runtime/resolve.js +90 -8
- package/dist/hooks/runtime/resolve.js.map +1 -1
- package/dist/hooks/runtime/retry-policy.js +57 -0
- package/dist/hooks/runtime/retry-policy.js.map +1 -0
- package/dist/hooks/runtime/review-sessions.js +74 -0
- package/dist/hooks/runtime/review-sessions.js.map +1 -0
- package/dist/hooks/runtime/script-resolve.js +695 -0
- package/dist/hooks/runtime/script-resolve.js.map +1 -0
- package/dist/hooks/runtime/session-activation.js +5 -1
- package/dist/hooks/runtime/session-activation.js.map +1 -1
- package/dist/hooks/runtime/session-review.js +163 -45
- package/dist/hooks/runtime/session-review.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +2 -1
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/session-writes.js +232 -0
- package/dist/hooks/runtime/session-writes.js.map +1 -0
- package/dist/hooks/runtime/sniff.js +26 -7
- package/dist/hooks/runtime/sniff.js.map +1 -1
- package/dist/hooks/runtime/target-resolve.js +336 -0
- package/dist/hooks/runtime/target-resolve.js.map +1 -0
- package/dist/hooks/runtime/unmapped-tools.js +93 -0
- package/dist/hooks/runtime/unmapped-tools.js.map +1 -0
- package/dist/hooks/runtime/usage-block.js +4 -0
- package/dist/hooks/runtime/usage-block.js.map +1 -1
- package/dist/hooks/runtime/user-prompt-submit.js +2 -1
- package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
- package/dist/hooks/runtime/wire-text.js +41 -0
- package/dist/hooks/runtime/wire-text.js.map +1 -0
- package/dist/hooks/runtime/work-dir.js +84 -0
- package/dist/hooks/runtime/work-dir.js.map +1 -0
- package/dist/index.js +45 -12
- package/dist/index.js.map +1 -1
- package/dist/install.js +174 -11
- package/dist/install.js.map +1 -1
- package/dist/link.js +74 -48
- package/dist/link.js.map +1 -1
- package/dist/login.js +77 -11
- package/dist/login.js.map +1 -1
- package/dist/mcp/auth/agent-sign-ins.js +174 -0
- package/dist/mcp/auth/agent-sign-ins.js.map +1 -0
- package/dist/mcp/auth/callback.js +200 -0
- package/dist/mcp/auth/callback.js.map +1 -0
- package/dist/mcp/auth/connect.js +392 -0
- package/dist/mcp/auth/connect.js.map +1 -0
- package/dist/mcp/auth/discovery.js +399 -0
- package/dist/mcp/auth/discovery.js.map +1 -0
- package/dist/mcp/auth/oauth.js +326 -0
- package/dist/mcp/auth/oauth.js.map +1 -0
- package/dist/mcp/auth/probe.js +128 -0
- package/dist/mcp/auth/probe.js.map +1 -0
- package/dist/mcp/auth/secrets.js +446 -0
- package/dist/mcp/auth/secrets.js.map +1 -0
- package/dist/mcp/auth/store.js +260 -0
- package/dist/mcp/auth/store.js.map +1 -0
- package/dist/mcp/auth/tokenSource.js +55 -0
- package/dist/mcp/auth/tokenSource.js.map +1 -0
- package/dist/mcp/config/atomicWrite.js +98 -0
- package/dist/mcp/config/atomicWrite.js.map +1 -0
- package/dist/mcp/config/clients.js +171 -0
- package/dist/mcp/config/clients.js.map +1 -0
- package/dist/mcp/config/cybedefend-servers.js +48 -0
- package/dist/mcp/config/cybedefend-servers.js.map +1 -0
- package/dist/mcp/config/discover.js +114 -0
- package/dist/mcp/config/discover.js.map +1 -0
- package/dist/mcp/config/hook.js +123 -0
- package/dist/mcp/config/hook.js.map +1 -0
- package/dist/mcp/config/index.js +11 -0
- package/dist/mcp/config/index.js.map +1 -0
- package/dist/mcp/config/install.js +132 -0
- package/dist/mcp/config/install.js.map +1 -0
- package/dist/mcp/config/installed.js +37 -0
- package/dist/mcp/config/installed.js.map +1 -0
- package/dist/mcp/config/jsonEdit.js +119 -0
- package/dist/mcp/config/jsonEdit.js.map +1 -0
- package/dist/mcp/config/lock.js +102 -0
- package/dist/mcp/config/lock.js.map +1 -0
- package/dist/mcp/config/proxyBinary.js +211 -0
- package/dist/mcp/config/proxyBinary.js.map +1 -0
- package/dist/mcp/config/rewrite.js +388 -0
- package/dist/mcp/config/rewrite.js.map +1 -0
- package/dist/mcp/config/types.js +34 -0
- package/dist/mcp/config/types.js.map +1 -0
- package/dist/mcp/proxy/audit.js +83 -0
- package/dist/mcp/proxy/audit.js.map +1 -0
- package/dist/mcp/proxy/authInterceptor.js +119 -0
- package/dist/mcp/proxy/authInterceptor.js.map +1 -0
- package/dist/mcp/proxy/expand.js +93 -0
- package/dist/mcp/proxy/expand.js.map +1 -0
- package/dist/mcp/proxy/inject.js +397 -0
- package/dist/mcp/proxy/inject.js.map +1 -0
- package/dist/mcp/proxy/intercept.js +37 -0
- package/dist/mcp/proxy/intercept.js.map +1 -0
- package/dist/mcp/proxy/jsonrpc.js +153 -0
- package/dist/mcp/proxy/jsonrpc.js.map +1 -0
- package/dist/mcp/proxy/log.js +109 -0
- package/dist/mcp/proxy/log.js.map +1 -0
- package/dist/mcp/proxy/paths.js +53 -0
- package/dist/mcp/proxy/paths.js.map +1 -0
- package/dist/mcp/proxy/proxy.js +510 -0
- package/dist/mcp/proxy/proxy.js.map +1 -0
- package/dist/mcp/proxy/spec.js +203 -0
- package/dist/mcp/proxy/spec.js.map +1 -0
- package/dist/mcp/proxy/sse.js +77 -0
- package/dist/mcp/proxy/sse.js.map +1 -0
- package/dist/mcp/proxy/upstream.js +2 -0
- package/dist/mcp/proxy/upstream.js.map +1 -0
- package/dist/mcp/proxy/upstreamHttp.js +499 -0
- package/dist/mcp/proxy/upstreamHttp.js.map +1 -0
- package/dist/mcp/proxy/upstreamStdio.js +188 -0
- package/dist/mcp/proxy/upstreamStdio.js.map +1 -0
- package/dist/mcp/proxy/upstreams.js +143 -0
- package/dist/mcp/proxy/upstreams.js.map +1 -0
- package/dist/mcp/proxy/verifyInterceptor.js +559 -0
- package/dist/mcp/proxy/verifyInterceptor.js.map +1 -0
- package/dist/mcp/proxy/windowsCommand.js +99 -0
- package/dist/mcp/proxy/windowsCommand.js.map +1 -0
- package/dist/mcp/scan/args.js +228 -0
- package/dist/mcp/scan/args.js.map +1 -0
- package/dist/mcp/scan/results.js +253 -0
- package/dist/mcp/scan/results.js.map +1 -0
- package/dist/mcp/scan/types.js +40 -0
- package/dist/mcp/scan/types.js.map +1 -0
- package/dist/mcp/verify/api.js +475 -0
- package/dist/mcp/verify/api.js.map +1 -0
- package/dist/mcp/verify/backend.js +143 -0
- package/dist/mcp/verify/backend.js.map +1 -0
- package/dist/mcp/verify/cache.js +182 -0
- package/dist/mcp/verify/cache.js.map +1 -0
- package/dist/mcp/verify/contract-errors.js +198 -0
- package/dist/mcp/verify/contract-errors.js.map +1 -0
- package/dist/mcp/verify/digest.js +91 -0
- package/dist/mcp/verify/digest.js.map +1 -0
- package/dist/mcp/verify/factory.js +56 -0
- package/dist/mcp/verify/factory.js.map +1 -0
- package/dist/mcp/verify/identity.js +173 -0
- package/dist/mcp/verify/identity.js.map +1 -0
- package/dist/mcp/verify/policy-store.js +63 -0
- package/dist/mcp/verify/policy-store.js.map +1 -0
- package/dist/mcp/verify/policy.js +158 -0
- package/dist/mcp/verify/policy.js.map +1 -0
- package/dist/mcp/verify/pool.js +27 -0
- package/dist/mcp/verify/pool.js.map +1 -0
- package/dist/mcp/verify/token-refresh.js +44 -0
- package/dist/mcp/verify/token-refresh.js.map +1 -0
- package/dist/mcp/verify/token.js +67 -0
- package/dist/mcp/verify/token.js.map +1 -0
- package/dist/mcp/verify/verifier.js +1009 -0
- package/dist/mcp/verify/verifier.js.map +1 -0
- package/dist/org-gate.js +1 -1
- package/dist/org-gate.js.map +1 -1
- package/dist/org.js +146 -0
- package/dist/org.js.map +1 -0
- package/dist/project-create.js +129 -0
- package/dist/project-create.js.map +1 -0
- package/dist/prompts.js +21 -0
- package/dist/prompts.js.map +1 -1
- package/dist/re2.wasm +0 -0
- package/dist/status.js +61 -0
- package/dist/status.js.map +1 -1
- package/dist/uninstall.js +49 -4
- package/dist/uninstall.js.map +1 -1
- package/dist/utils.js +62 -6
- package/dist/utils.js.map +1 -1
- package/package.json +10 -3
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a third-party MCP token is kept, per platform.
|
|
3
|
+
*
|
|
4
|
+
* One interface, four implementations, in decreasing order of protection:
|
|
5
|
+
*
|
|
6
|
+
* - macOS: the system keychain, through `security`, in a service of its own.
|
|
7
|
+
* - Linux: the session secret service, through `secret-tool` (libsecret).
|
|
8
|
+
* - Windows: DPAPI, through PowerShell's `ConvertFrom-SecureString`. The
|
|
9
|
+
* plan says "Credential Manager"; DPAPI is the primitive Credential
|
|
10
|
+
* Manager itself is built on, and it is the only one reachable without a
|
|
11
|
+
* native dependency — `cmdkey` can write a credential but cannot read its
|
|
12
|
+
* password back, which makes it useless to us. The ciphertext is bound to
|
|
13
|
+
* the user and the machine, and lands in the same file as the fallback.
|
|
14
|
+
* - Anywhere else, or when the above is unavailable: `tokens.enc`, AES-256-GCM
|
|
15
|
+
* under a key derived from a machine secret and a per-install salt.
|
|
16
|
+
*
|
|
17
|
+
* The last one is obfuscation, not protection, and says so out loud: anything
|
|
18
|
+
* running as this user can derive the same key. It exists so that a laptop
|
|
19
|
+
* without a session keyring keeps working, and it is announced every time it
|
|
20
|
+
* is used, as the plan requires.
|
|
21
|
+
*
|
|
22
|
+
* No token is ever logged, interpolated into an error message, or passed as a
|
|
23
|
+
* command-line argument — except on macOS, where `security` takes the value
|
|
24
|
+
* in `argv`. That one is inherited from the legacy implementation and noted
|
|
25
|
+
* in the Phase 2 summary.
|
|
26
|
+
*/
|
|
27
|
+
import { execFileSync } from 'node:child_process';
|
|
28
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync, timingSafeEqual, } from 'node:crypto';
|
|
29
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
30
|
+
import { hostname, homedir, userInfo } from 'node:os';
|
|
31
|
+
import { join } from 'node:path';
|
|
32
|
+
import { mcpHomeDir, PROXY_ENV_PREFIX } from '../proxy/paths.js';
|
|
33
|
+
/**
|
|
34
|
+
* Keychain service dedicated to third-party MCP credentials.
|
|
35
|
+
*
|
|
36
|
+
* Deliberately not `"Codex MCP Credentials"`, where `src/auth/auth-store.ts`
|
|
37
|
+
* keeps the CybeDefend entries: a loose lookup of that service falling back
|
|
38
|
+
* to "the first entry found" could surface a Linear token as the CybeDefend
|
|
39
|
+
* one, which would then leave as `Authorization: Bearer` towards our own API.
|
|
40
|
+
* A separate service closes that structurally.
|
|
41
|
+
*/
|
|
42
|
+
export const MCP_KEYCHAIN_SERVICE = 'CybeDefend MCP Server Credentials';
|
|
43
|
+
const COMMAND_TIMEOUT_MS = 5000;
|
|
44
|
+
function defaultExecFile(file, args, input) {
|
|
45
|
+
return execFileSync(file, args, {
|
|
46
|
+
encoding: 'utf8',
|
|
47
|
+
stdio: input === undefined ? ['ignore', 'pipe', 'ignore'] : ['pipe', 'pipe', 'ignore'],
|
|
48
|
+
input,
|
|
49
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
50
|
+
windowsHide: true,
|
|
51
|
+
}).trim();
|
|
52
|
+
}
|
|
53
|
+
function defaultAnnounce(detail) {
|
|
54
|
+
try {
|
|
55
|
+
process.stderr.write(`vibedefend: ${detail}\n`);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
/* a message must never take the CLI down */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ─── macOS ──────────────────────────────────────────────────────────────────
|
|
62
|
+
class MacosKeychain {
|
|
63
|
+
exec;
|
|
64
|
+
kind = 'macos-keychain';
|
|
65
|
+
constructor(exec) {
|
|
66
|
+
this.exec = exec;
|
|
67
|
+
}
|
|
68
|
+
get(key) {
|
|
69
|
+
try {
|
|
70
|
+
const blob = this.exec('security', [
|
|
71
|
+
'find-generic-password',
|
|
72
|
+
'-s',
|
|
73
|
+
MCP_KEYCHAIN_SERVICE,
|
|
74
|
+
'-a',
|
|
75
|
+
key,
|
|
76
|
+
'-w',
|
|
77
|
+
]);
|
|
78
|
+
return blob.trim() === '' ? null : blob.trim();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
set(key, value) {
|
|
85
|
+
this.exec('security', [
|
|
86
|
+
'add-generic-password',
|
|
87
|
+
'-U',
|
|
88
|
+
'-s',
|
|
89
|
+
MCP_KEYCHAIN_SERVICE,
|
|
90
|
+
'-a',
|
|
91
|
+
key,
|
|
92
|
+
'-w',
|
|
93
|
+
value,
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
delete(key) {
|
|
97
|
+
try {
|
|
98
|
+
this.exec('security', ['delete-generic-password', '-s', MCP_KEYCHAIN_SERVICE, '-a', key]);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
/* absent, or the keychain is locked */
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ─── Linux ──────────────────────────────────────────────────────────────────
|
|
106
|
+
class LinuxSecretService {
|
|
107
|
+
exec;
|
|
108
|
+
kind = 'linux-secret-service';
|
|
109
|
+
constructor(exec) {
|
|
110
|
+
this.exec = exec;
|
|
111
|
+
}
|
|
112
|
+
get(key) {
|
|
113
|
+
try {
|
|
114
|
+
const blob = this.exec('secret-tool', [
|
|
115
|
+
'lookup',
|
|
116
|
+
'service',
|
|
117
|
+
MCP_KEYCHAIN_SERVICE,
|
|
118
|
+
'account',
|
|
119
|
+
key,
|
|
120
|
+
]);
|
|
121
|
+
return blob.trim() === '' ? null : blob.trim();
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
set(key, value) {
|
|
128
|
+
// The value goes in on stdin: `secret-tool store` reads it there
|
|
129
|
+
// precisely so it never appears in `/proc/<pid>/cmdline`.
|
|
130
|
+
this.exec('secret-tool', ['store', '--label', MCP_KEYCHAIN_SERVICE, 'service', MCP_KEYCHAIN_SERVICE, 'account', key], value);
|
|
131
|
+
}
|
|
132
|
+
delete(key) {
|
|
133
|
+
try {
|
|
134
|
+
this.exec('secret-tool', ['clear', 'service', MCP_KEYCHAIN_SERVICE, 'account', key]);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
/* absent, or no session keyring */
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// ─── Windows ────────────────────────────────────────────────────────────────
|
|
142
|
+
/**
|
|
143
|
+
* DPAPI, driven by PowerShell, with the ciphertext kept in `tokens.enc`.
|
|
144
|
+
*
|
|
145
|
+
* `ConvertFrom-SecureString` (no `-Key`) encrypts under the current user's
|
|
146
|
+
* DPAPI master key: the result is useless to another user and on another
|
|
147
|
+
* machine. Both directions read their input from stdin, never from `argv`,
|
|
148
|
+
* because a command line is visible to anything that can list processes.
|
|
149
|
+
*/
|
|
150
|
+
class WindowsDpapi {
|
|
151
|
+
exec;
|
|
152
|
+
file;
|
|
153
|
+
kind = 'windows-dpapi';
|
|
154
|
+
constructor(exec, file) {
|
|
155
|
+
this.exec = exec;
|
|
156
|
+
this.file = file;
|
|
157
|
+
}
|
|
158
|
+
powershell(script, input) {
|
|
159
|
+
return this.exec('powershell.exe', ['-NoProfile', '-NonInteractive', '-NoLogo', '-Command', script], input);
|
|
160
|
+
}
|
|
161
|
+
get(key) {
|
|
162
|
+
const stored = this.file.readRaw(key);
|
|
163
|
+
if (!stored)
|
|
164
|
+
return null;
|
|
165
|
+
try {
|
|
166
|
+
const plain = this.powershell('$e = [Console]::In.ReadToEnd().Trim(); ' +
|
|
167
|
+
'$s = ConvertTo-SecureString -String $e; ' +
|
|
168
|
+
'[Runtime.InteropServices.Marshal]::PtrToStringBSTR(' +
|
|
169
|
+
'[Runtime.InteropServices.Marshal]::SecureStringToBSTR($s))', stored);
|
|
170
|
+
return plain.trim() === '' ? null : plain;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
set(key, value) {
|
|
177
|
+
const encrypted = this.powershell('$p = [Console]::In.ReadToEnd(); ' +
|
|
178
|
+
'$s = ConvertTo-SecureString -String $p -AsPlainText -Force; ' +
|
|
179
|
+
'ConvertFrom-SecureString -SecureString $s', value);
|
|
180
|
+
if (encrypted.trim() === '')
|
|
181
|
+
throw new Error('DPAPI returned an empty ciphertext');
|
|
182
|
+
this.file.writeRaw(key, encrypted.trim());
|
|
183
|
+
}
|
|
184
|
+
delete(key) {
|
|
185
|
+
this.file.writeRaw(key, null);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* `tokens.enc`: AES-256-GCM, key derived with scrypt from a machine secret
|
|
190
|
+
* and a per-install salt.
|
|
191
|
+
*
|
|
192
|
+
* What this is: enough that a token is not readable in a backup, in a synced
|
|
193
|
+
* folder, or by a tool grepping dotfiles for `Bearer`. What it is not: a
|
|
194
|
+
* defence against code running as this user, which can derive the same key.
|
|
195
|
+
* Callers announce it; see `selectSecretBackend`.
|
|
196
|
+
*/
|
|
197
|
+
export class EncryptedFileStore {
|
|
198
|
+
path;
|
|
199
|
+
machineSecretFn;
|
|
200
|
+
readFileFn;
|
|
201
|
+
writeFileFn;
|
|
202
|
+
kind = 'encrypted-file';
|
|
203
|
+
/**
|
|
204
|
+
* Keyed by salt, not by nothing.
|
|
205
|
+
*
|
|
206
|
+
* The salt is created with the envelope and never changes afterwards, but
|
|
207
|
+
* caching a key without remembering which salt produced it is how the first
|
|
208
|
+
* version of this class wrote a file it could not read back: `encrypt` read
|
|
209
|
+
* the envelope to get a salt, then `writeRaw` read it AGAIN — and a missing
|
|
210
|
+
* file yields a FRESH random salt every time — so the ciphertext went to
|
|
211
|
+
* disk under one key while the envelope recorded another. Everything worked
|
|
212
|
+
* inside the writing process, where the key was cached, and nothing worked
|
|
213
|
+
* in the next one.
|
|
214
|
+
*/
|
|
215
|
+
keys = new Map();
|
|
216
|
+
constructor(path, machineSecretFn, readFileFn, writeFileFn) {
|
|
217
|
+
this.path = path;
|
|
218
|
+
this.machineSecretFn = machineSecretFn;
|
|
219
|
+
this.readFileFn = readFileFn;
|
|
220
|
+
this.writeFileFn = writeFileFn;
|
|
221
|
+
}
|
|
222
|
+
get(key) {
|
|
223
|
+
const envelope = this.load();
|
|
224
|
+
const raw = envelope.entries[key];
|
|
225
|
+
if (!raw)
|
|
226
|
+
return null;
|
|
227
|
+
try {
|
|
228
|
+
return this.decrypt(envelope.salt, raw);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// A ciphertext that no longer opens — the machine secret changed, or
|
|
232
|
+
// the file was tampered with — behaves like an absent credential.
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
set(key, value) {
|
|
237
|
+
const envelope = this.load();
|
|
238
|
+
envelope.entries[key] = this.encrypt(envelope.salt, value);
|
|
239
|
+
this.persist(envelope);
|
|
240
|
+
}
|
|
241
|
+
delete(key) {
|
|
242
|
+
const envelope = this.load();
|
|
243
|
+
delete envelope.entries[key];
|
|
244
|
+
this.persist(envelope);
|
|
245
|
+
}
|
|
246
|
+
/** Reads one entry without decrypting it. Used by the DPAPI backend. */
|
|
247
|
+
readRaw(key) {
|
|
248
|
+
return this.load().entries[key] ?? null;
|
|
249
|
+
}
|
|
250
|
+
/** Writes one entry as it is, or removes it when `value` is `null`. */
|
|
251
|
+
writeRaw(key, value) {
|
|
252
|
+
const envelope = this.load();
|
|
253
|
+
if (value === null)
|
|
254
|
+
delete envelope.entries[key];
|
|
255
|
+
else
|
|
256
|
+
envelope.entries[key] = value;
|
|
257
|
+
this.persist(envelope);
|
|
258
|
+
}
|
|
259
|
+
load() {
|
|
260
|
+
try {
|
|
261
|
+
const parsed = JSON.parse(this.readFileFn(this.path));
|
|
262
|
+
if (parsed && parsed.v === 1 && typeof parsed.salt === 'string' && parsed.entries) {
|
|
263
|
+
return { v: 1, salt: parsed.salt, entries: { ...parsed.entries } };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
/* absent or unreadable: start a new envelope */
|
|
268
|
+
}
|
|
269
|
+
return { v: 1, salt: randomBytes(16).toString('base64'), entries: {} };
|
|
270
|
+
}
|
|
271
|
+
persist(envelope) {
|
|
272
|
+
this.writeFileFn(this.path, JSON.stringify(envelope, null, 2));
|
|
273
|
+
}
|
|
274
|
+
/** scrypt costs about 50 ms, and a session asks for the key more than once. */
|
|
275
|
+
keyFor(salt) {
|
|
276
|
+
const known = this.keys.get(salt);
|
|
277
|
+
if (known)
|
|
278
|
+
return known;
|
|
279
|
+
const derived = scryptSync(this.machineSecretFn(), Buffer.from(salt, 'base64'), 32);
|
|
280
|
+
this.keys.set(salt, derived);
|
|
281
|
+
return derived;
|
|
282
|
+
}
|
|
283
|
+
encrypt(salt, plain) {
|
|
284
|
+
const iv = randomBytes(12);
|
|
285
|
+
const cipher = createCipheriv('aes-256-gcm', this.keyFor(salt), iv, { authTagLength: 16 });
|
|
286
|
+
const body = Buffer.concat([cipher.update(plain, 'utf8'), cipher.final()]);
|
|
287
|
+
return [
|
|
288
|
+
iv.toString('base64'),
|
|
289
|
+
cipher.getAuthTag().toString('base64'),
|
|
290
|
+
body.toString('base64'),
|
|
291
|
+
].join('.');
|
|
292
|
+
}
|
|
293
|
+
decrypt(salt, blob) {
|
|
294
|
+
const [ivPart, tagPart, bodyPart] = blob.split('.');
|
|
295
|
+
if (!ivPart || !tagPart || !bodyPart)
|
|
296
|
+
throw new Error('malformed ciphertext');
|
|
297
|
+
const decipher = createDecipheriv('aes-256-gcm', this.keyFor(salt), Buffer.from(ivPart, 'base64'), { authTagLength: 16 });
|
|
298
|
+
decipher.setAuthTag(Buffer.from(tagPart, 'base64'));
|
|
299
|
+
return Buffer.concat([
|
|
300
|
+
decipher.update(Buffer.from(bodyPart, 'base64')),
|
|
301
|
+
decipher.final(),
|
|
302
|
+
]).toString('utf8');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
export function tokensFile(dir) {
|
|
306
|
+
return join(dir ?? mcpHomeDir(), 'tokens.enc');
|
|
307
|
+
}
|
|
308
|
+
function defaultReadFile(path) {
|
|
309
|
+
if (!existsSync(path))
|
|
310
|
+
throw new Error('ENOENT: no such file');
|
|
311
|
+
return readFileSync(path, 'utf8');
|
|
312
|
+
}
|
|
313
|
+
function defaultWriteFile(path, content) {
|
|
314
|
+
// The mode is set AT CREATION, as in `auth-store.ts`: a `chmod` afterwards
|
|
315
|
+
// leaves the file readable for the length of a syscall, and on a shared
|
|
316
|
+
// machine that window is enough.
|
|
317
|
+
mkdirSync(join(path, '..'), { recursive: true, mode: 0o700 });
|
|
318
|
+
writeFileSync(path, content, { encoding: 'utf8', mode: 0o600 });
|
|
319
|
+
chmodSync(path, 0o600);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Something stable for this machine and this user, and cheap to read.
|
|
323
|
+
*
|
|
324
|
+
* Not a secret in the cryptographic sense — a machine id is readable by any
|
|
325
|
+
* local process — which is exactly why the file it keys is called a fallback.
|
|
326
|
+
*/
|
|
327
|
+
export function machineSecret(platform = process.platform) {
|
|
328
|
+
const parts = [userInfo().username, homedir()];
|
|
329
|
+
try {
|
|
330
|
+
if (platform === 'linux') {
|
|
331
|
+
for (const candidate of ['/etc/machine-id', '/var/lib/dbus/machine-id']) {
|
|
332
|
+
if (existsSync(candidate)) {
|
|
333
|
+
parts.push(readFileSync(candidate, 'utf8').trim());
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
else if (platform === 'darwin') {
|
|
339
|
+
const out = execFileSync('ioreg', ['-rd1', '-c', 'IOPlatformExpertDevice'], {
|
|
340
|
+
encoding: 'utf8',
|
|
341
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
342
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
343
|
+
});
|
|
344
|
+
const match = /"IOPlatformUUID"\s*=\s*"([^"]+)"/.exec(out);
|
|
345
|
+
if (match)
|
|
346
|
+
parts.push(match[1]);
|
|
347
|
+
}
|
|
348
|
+
else if (platform === 'win32') {
|
|
349
|
+
const out = execFileSync('reg', ['query', 'HKLM\\SOFTWARE\\Microsoft\\Cryptography', '/v', 'MachineGuid'], { encoding: 'utf8', timeout: COMMAND_TIMEOUT_MS, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
350
|
+
const match = /MachineGuid\s+REG_SZ\s+(\S+)/.exec(out);
|
|
351
|
+
if (match)
|
|
352
|
+
parts.push(match[1]);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
/* no machine id available: the hostname below still varies per machine */
|
|
357
|
+
}
|
|
358
|
+
parts.push(hostname());
|
|
359
|
+
return parts.join('|');
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Picks the backend for this platform, and falls back to the encrypted file
|
|
363
|
+
* when it is not usable — an SSH session with no keyring, a locked keychain,
|
|
364
|
+
* a machine without `secret-tool`.
|
|
365
|
+
*
|
|
366
|
+
* The probe is a real round trip on a throwaway key rather than a version
|
|
367
|
+
* check: `secret-tool --version` succeeds on a machine whose D-Bus session
|
|
368
|
+
* has no secret service at all, which is exactly the case that has to
|
|
369
|
+
* degrade.
|
|
370
|
+
*/
|
|
371
|
+
export function selectSecretBackend(deps = {}) {
|
|
372
|
+
const exec = deps.execFileFn ?? defaultExecFile;
|
|
373
|
+
const platform = deps.platform ?? process.platform;
|
|
374
|
+
// `VIBEDEFEND_MCP_SECRET_BACKEND=file` skips the platform store entirely.
|
|
375
|
+
// The test suite needs it — a suite that wrote into the developer's keychain
|
|
376
|
+
// would be exactly the damage the plan forbids for `~/.cybedefend/` — and it
|
|
377
|
+
// is the honest answer for a headless box whose keyring prompt nobody will
|
|
378
|
+
// ever see.
|
|
379
|
+
const forced = (deps.env ?? process.env)[`${PROXY_ENV_PREFIX}SECRET_BACKEND`];
|
|
380
|
+
const file = new EncryptedFileStore(
|
|
381
|
+
// `dir` wins, then whatever `VIBEDEFEND_MCP_DIR` says in the environment
|
|
382
|
+
// this call was handed. A command that scopes its own environment — every
|
|
383
|
+
// test does — must not have its credential file fall back to the real one.
|
|
384
|
+
tokensFile(deps.dir ?? mcpHomeDir(deps.env ?? process.env)), deps.machineSecretFn ?? (() => machineSecret(platform)), deps.readFileFn ?? defaultReadFile, deps.writeFileFn ?? defaultWriteFile);
|
|
385
|
+
const announce = deps.onFallback ?? defaultAnnounce;
|
|
386
|
+
if (forced === 'file')
|
|
387
|
+
return { backend: file, degraded: false };
|
|
388
|
+
const platformBackend = platform === 'darwin'
|
|
389
|
+
? new MacosKeychain(exec)
|
|
390
|
+
: platform === 'linux'
|
|
391
|
+
? new LinuxSecretService(exec)
|
|
392
|
+
: platform === 'win32'
|
|
393
|
+
? new WindowsDpapi(exec, file)
|
|
394
|
+
: null;
|
|
395
|
+
if (!platformBackend) {
|
|
396
|
+
announce(`no OS credential store on ${platform} — MCP tokens are kept in ${tokensFile(deps.dir)}, ` +
|
|
397
|
+
'encrypted under a key derived from this machine; anything running as you can read them');
|
|
398
|
+
return { backend: file, degraded: true };
|
|
399
|
+
}
|
|
400
|
+
const failure = probe(platformBackend);
|
|
401
|
+
if (!failure)
|
|
402
|
+
return { backend: platformBackend, degraded: false };
|
|
403
|
+
announce(`${platformBackend.kind} is unavailable (${failure}) — MCP tokens are kept in ${tokensFile(deps.dir)}, encrypted under a key derived from this machine; anything running as you can read them`);
|
|
404
|
+
return { backend: file, degraded: true };
|
|
405
|
+
}
|
|
406
|
+
/** The probe key. Written, read back, removed; never a real credential. */
|
|
407
|
+
const PROBE_KEY = 'vibedefend-availability-probe';
|
|
408
|
+
function probe(backend) {
|
|
409
|
+
const expected = randomBytes(16).toString('base64');
|
|
410
|
+
try {
|
|
411
|
+
backend.set(PROBE_KEY, expected);
|
|
412
|
+
const seen = backend.get(PROBE_KEY);
|
|
413
|
+
backend.delete(PROBE_KEY);
|
|
414
|
+
if (seen === null)
|
|
415
|
+
return 'the store accepted a write but returned nothing';
|
|
416
|
+
const a = Buffer.from(seen);
|
|
417
|
+
const b = Buffer.from(expected);
|
|
418
|
+
if (a.length !== b.length || !timingSafeEqual(a, b)) {
|
|
419
|
+
return 'the store returned a different value than the one written';
|
|
420
|
+
}
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
try {
|
|
425
|
+
backend.delete(PROBE_KEY);
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
/* nothing to clean up */
|
|
429
|
+
}
|
|
430
|
+
// The diagnostic goes to stderr, so it must not carry the value the store
|
|
431
|
+
// was handed. Here that value is only the probe's, but the same code path
|
|
432
|
+
// is what a real credential travels through, and a store that echoes its
|
|
433
|
+
// input into an error message is common enough (`secret-tool` does).
|
|
434
|
+
const detail = error instanceof Error ? firstLine(error.message) : 'unknown failure';
|
|
435
|
+
return redact(detail, expected);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/** Removes a known secret from a message that is about to be printed. */
|
|
439
|
+
function redact(message, secret) {
|
|
440
|
+
return secret === '' ? message : message.split(secret).join('<redacted>');
|
|
441
|
+
}
|
|
442
|
+
function firstLine(message) {
|
|
443
|
+
const line = message.split('\n')[0]?.trim() ?? '';
|
|
444
|
+
return line.length > 160 ? `${line.slice(0, 160)}…` : line;
|
|
445
|
+
}
|
|
446
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../src/mcp/auth/secrets.ts"],"names":[],"mappings":"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"}
|