@zivis/mcp 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-client.d.ts +42 -0
- package/dist/api-client.js +145 -0
- package/dist/api-client.js.map +1 -0
- package/dist/auth/index.d.ts +29 -0
- package/dist/auth/index.js +73 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/jwt.d.ts +24 -0
- package/dist/auth/jwt.js +25 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/keychain.d.ts +34 -0
- package/dist/auth/keychain.js +272 -0
- package/dist/auth/keychain.js.map +1 -0
- package/dist/auth/oauth.d.ts +38 -0
- package/dist/auth/oauth.js +241 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/sessions.d.ts +28 -0
- package/dist/auth/sessions.js +69 -0
- package/dist/auth/sessions.js.map +1 -0
- package/dist/auth/token-refresh.d.ts +24 -0
- package/dist/auth/token-refresh.js +91 -0
- package/dist/auth/token-refresh.js.map +1 -0
- package/dist/cli.d.ts +23 -0
- package/dist/cli.js +962 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/project-binding.d.ts +25 -0
- package/dist/project-binding.js +67 -0
- package/dist/project-binding.js.map +1 -0
- package/dist/resolve-application-id.d.ts +12 -0
- package/dist/resolve-application-id.js +21 -0
- package/dist/resolve-application-id.js.map +1 -0
- package/dist/sanitize.d.ts +23 -0
- package/dist/sanitize.js +125 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.js +447 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/check-project.d.ts +32 -0
- package/dist/tools/check-project.js +180 -0
- package/dist/tools/check-project.js.map +1 -0
- package/dist/tools/check-repo-trust.d.ts +33 -0
- package/dist/tools/check-repo-trust.js +212 -0
- package/dist/tools/check-repo-trust.js.map +1 -0
- package/dist/tools/create-diagram.d.ts +114 -0
- package/dist/tools/create-diagram.js +176 -0
- package/dist/tools/create-diagram.js.map +1 -0
- package/dist/tools/create-document.d.ts +28 -0
- package/dist/tools/create-document.js +53 -0
- package/dist/tools/create-document.js.map +1 -0
- package/dist/tools/discover-local-infra.d.ts +24 -0
- package/dist/tools/discover-local-infra.js +763 -0
- package/dist/tools/discover-local-infra.js.map +1 -0
- package/dist/tools/enterprise/capture-evidence.d.ts +54 -0
- package/dist/tools/enterprise/capture-evidence.js +72 -0
- package/dist/tools/enterprise/capture-evidence.js.map +1 -0
- package/dist/tools/enterprise/create-report-ticket.d.ts +34 -0
- package/dist/tools/enterprise/create-report-ticket.js +44 -0
- package/dist/tools/enterprise/create-report-ticket.js.map +1 -0
- package/dist/tools/enterprise/end-pentest-session.d.ts +33 -0
- package/dist/tools/enterprise/end-pentest-session.js +42 -0
- package/dist/tools/enterprise/end-pentest-session.js.map +1 -0
- package/dist/tools/enterprise/generate-report.d.ts +55 -0
- package/dist/tools/enterprise/generate-report.js +111 -0
- package/dist/tools/enterprise/generate-report.js.map +1 -0
- package/dist/tools/enterprise/get-org-zat.d.ts +27 -0
- package/dist/tools/enterprise/get-org-zat.js +62 -0
- package/dist/tools/enterprise/get-org-zat.js.map +1 -0
- package/dist/tools/enterprise/get-report-status.d.ts +27 -0
- package/dist/tools/enterprise/get-report-status.js +38 -0
- package/dist/tools/enterprise/get-report-status.js.map +1 -0
- package/dist/tools/enterprise/get-threat-model.d.ts +29 -0
- package/dist/tools/enterprise/get-threat-model.js +83 -0
- package/dist/tools/enterprise/get-threat-model.js.map +1 -0
- package/dist/tools/enterprise/list-agents.d.ts +42 -0
- package/dist/tools/enterprise/list-agents.js +95 -0
- package/dist/tools/enterprise/list-agents.js.map +1 -0
- package/dist/tools/enterprise/list-report-issues.d.ts +36 -0
- package/dist/tools/enterprise/list-report-issues.js +50 -0
- package/dist/tools/enterprise/list-report-issues.js.map +1 -0
- package/dist/tools/enterprise/list-threat-models.d.ts +36 -0
- package/dist/tools/enterprise/list-threat-models.js +82 -0
- package/dist/tools/enterprise/list-threat-models.js.map +1 -0
- package/dist/tools/enterprise/manage-actor.d.ts +58 -0
- package/dist/tools/enterprise/manage-actor.js +99 -0
- package/dist/tools/enterprise/manage-actor.js.map +1 -0
- package/dist/tools/enterprise/manage-attack-scenario.d.ts +70 -0
- package/dist/tools/enterprise/manage-attack-scenario.js +89 -0
- package/dist/tools/enterprise/manage-attack-scenario.js.map +1 -0
- package/dist/tools/enterprise/manage-component.d.ts +58 -0
- package/dist/tools/enterprise/manage-component.js +90 -0
- package/dist/tools/enterprise/manage-component.js.map +1 -0
- package/dist/tools/enterprise/manage-data-asset.d.ts +53 -0
- package/dist/tools/enterprise/manage-data-asset.js +90 -0
- package/dist/tools/enterprise/manage-data-asset.js.map +1 -0
- package/dist/tools/enterprise/manage-data-flow.d.ts +57 -0
- package/dist/tools/enterprise/manage-data-flow.js +98 -0
- package/dist/tools/enterprise/manage-data-flow.js.map +1 -0
- package/dist/tools/enterprise/manage-finding.d.ts +69 -0
- package/dist/tools/enterprise/manage-finding.js +106 -0
- package/dist/tools/enterprise/manage-finding.js.map +1 -0
- package/dist/tools/enterprise/manage-security-control.d.ts +59 -0
- package/dist/tools/enterprise/manage-security-control.js +96 -0
- package/dist/tools/enterprise/manage-security-control.js.map +1 -0
- package/dist/tools/enterprise/manage-test-case.d.ts +88 -0
- package/dist/tools/enterprise/manage-test-case.js +119 -0
- package/dist/tools/enterprise/manage-test-case.js.map +1 -0
- package/dist/tools/enterprise/promote-finding-to-issue.d.ts +36 -0
- package/dist/tools/enterprise/promote-finding-to-issue.js +65 -0
- package/dist/tools/enterprise/promote-finding-to-issue.js.map +1 -0
- package/dist/tools/enterprise/publish-report-version.d.ts +34 -0
- package/dist/tools/enterprise/publish-report-version.js +75 -0
- package/dist/tools/enterprise/publish-report-version.js.map +1 -0
- package/dist/tools/enterprise/publish-test-to-library.d.ts +31 -0
- package/dist/tools/enterprise/publish-test-to-library.js +40 -0
- package/dist/tools/enterprise/publish-test-to-library.js.map +1 -0
- package/dist/tools/enterprise/record-test-result.d.ts +67 -0
- package/dist/tools/enterprise/record-test-result.js +75 -0
- package/dist/tools/enterprise/record-test-result.js.map +1 -0
- package/dist/tools/enterprise/start-pentest-session.d.ts +35 -0
- package/dist/tools/enterprise/start-pentest-session.js +50 -0
- package/dist/tools/enterprise/start-pentest-session.js.map +1 -0
- package/dist/tools/enterprise/sync-report-section.d.ts +41 -0
- package/dist/tools/enterprise/sync-report-section.js +79 -0
- package/dist/tools/enterprise/sync-report-section.js.map +1 -0
- package/dist/tools/enterprise/update-report-issue.d.ts +55 -0
- package/dist/tools/enterprise/update-report-issue.js +69 -0
- package/dist/tools/enterprise/update-report-issue.js.map +1 -0
- package/dist/tools/generate-diagram.d.ts +36 -0
- package/dist/tools/generate-diagram.js +153 -0
- package/dist/tools/generate-diagram.js.map +1 -0
- package/dist/tools/get-agent-test-results.d.ts +41 -0
- package/dist/tools/get-agent-test-results.js +86 -0
- package/dist/tools/get-agent-test-results.js.map +1 -0
- package/dist/tools/get-application-overview.d.ts +27 -0
- package/dist/tools/get-application-overview.js +143 -0
- package/dist/tools/get-application-overview.js.map +1 -0
- package/dist/tools/get-application.d.ts +27 -0
- package/dist/tools/get-application.js +83 -0
- package/dist/tools/get-application.js.map +1 -0
- package/dist/tools/get-artifact-content.d.ts +29 -0
- package/dist/tools/get-artifact-content.js +86 -0
- package/dist/tools/get-artifact-content.js.map +1 -0
- package/dist/tools/get-diagram.d.ts +27 -0
- package/dist/tools/get-diagram.js +109 -0
- package/dist/tools/get-diagram.js.map +1 -0
- package/dist/tools/get-document.d.ts +22 -0
- package/dist/tools/get-document.js +43 -0
- package/dist/tools/get-document.js.map +1 -0
- package/dist/tools/get-finding-details.d.ts +28 -0
- package/dist/tools/get-finding-details.js +43 -0
- package/dist/tools/get-finding-details.js.map +1 -0
- package/dist/tools/get-findings.d.ts +57 -0
- package/dist/tools/get-findings.js +103 -0
- package/dist/tools/get-findings.js.map +1 -0
- package/dist/tools/get-oss-zat.d.ts +27 -0
- package/dist/tools/get-oss-zat.js +105 -0
- package/dist/tools/get-oss-zat.js.map +1 -0
- package/dist/tools/get-recon-scan.d.ts +27 -0
- package/dist/tools/get-recon-scan.js +46 -0
- package/dist/tools/get-recon-scan.js.map +1 -0
- package/dist/tools/get-scan-output.d.ts +27 -0
- package/dist/tools/get-scan-output.js +64 -0
- package/dist/tools/get-scan-output.js.map +1 -0
- package/dist/tools/get-scenario-details.d.ts +27 -0
- package/dist/tools/get-scenario-details.js +46 -0
- package/dist/tools/get-scenario-details.js.map +1 -0
- package/dist/tools/get-test-case-results.d.ts +37 -0
- package/dist/tools/get-test-case-results.js +66 -0
- package/dist/tools/get-test-case-results.js.map +1 -0
- package/dist/tools/get-test-details.d.ts +29 -0
- package/dist/tools/get-test-details.js +49 -0
- package/dist/tools/get-test-details.js.map +1 -0
- package/dist/tools/get-trust-keys.d.ts +22 -0
- package/dist/tools/get-trust-keys.js +67 -0
- package/dist/tools/get-trust-keys.js.map +1 -0
- package/dist/tools/import-openapi-endpoints.d.ts +33 -0
- package/dist/tools/import-openapi-endpoints.js +93 -0
- package/dist/tools/import-openapi-endpoints.js.map +1 -0
- package/dist/tools/inspect-zat.d.ts +26 -0
- package/dist/tools/inspect-zat.js +247 -0
- package/dist/tools/inspect-zat.js.map +1 -0
- package/dist/tools/list-agent-test-cases.d.ts +41 -0
- package/dist/tools/list-agent-test-cases.js +73 -0
- package/dist/tools/list-agent-test-cases.js.map +1 -0
- package/dist/tools/list-applications.d.ts +34 -0
- package/dist/tools/list-applications.js +74 -0
- package/dist/tools/list-applications.js.map +1 -0
- package/dist/tools/list-diagrams.d.ts +42 -0
- package/dist/tools/list-diagrams.js +81 -0
- package/dist/tools/list-diagrams.js.map +1 -0
- package/dist/tools/list-documents.d.ts +24 -0
- package/dist/tools/list-documents.js +50 -0
- package/dist/tools/list-documents.js.map +1 -0
- package/dist/tools/list-endpoints.d.ts +47 -0
- package/dist/tools/list-endpoints.js +98 -0
- package/dist/tools/list-endpoints.js.map +1 -0
- package/dist/tools/list-recon-scans.d.ts +36 -0
- package/dist/tools/list-recon-scans.js +74 -0
- package/dist/tools/list-recon-scans.js.map +1 -0
- package/dist/tools/list-scan-artifacts.d.ts +41 -0
- package/dist/tools/list-scan-artifacts.js +63 -0
- package/dist/tools/list-scan-artifacts.js.map +1 -0
- package/dist/tools/list-scans.d.ts +44 -0
- package/dist/tools/list-scans.js +91 -0
- package/dist/tools/list-scans.js.map +1 -0
- package/dist/tools/list-test-library.d.ts +44 -0
- package/dist/tools/list-test-library.js +83 -0
- package/dist/tools/list-test-library.js.map +1 -0
- package/dist/tools/list-test-scenarios.d.ts +31 -0
- package/dist/tools/list-test-scenarios.js +66 -0
- package/dist/tools/list-test-scenarios.js.map +1 -0
- package/dist/tools/local-scan.d.ts +40 -0
- package/dist/tools/local-scan.js +261 -0
- package/dist/tools/local-scan.js.map +1 -0
- package/dist/tools/manage-diagram.d.ts +109 -0
- package/dist/tools/manage-diagram.js +316 -0
- package/dist/tools/manage-diagram.js.map +1 -0
- package/dist/tools/open-in-ide.d.ts +39 -0
- package/dist/tools/open-in-ide.js +61 -0
- package/dist/tools/open-in-ide.js.map +1 -0
- package/dist/tools/run-test-scenario.d.ts +37 -0
- package/dist/tools/run-test-scenario.js +70 -0
- package/dist/tools/run-test-scenario.js.map +1 -0
- package/dist/tools/scan-pr.d.ts +27 -0
- package/dist/tools/scan-pr.js +51 -0
- package/dist/tools/scan-pr.js.map +1 -0
- package/dist/tools/security-review.d.ts +65 -0
- package/dist/tools/security-review.js +378 -0
- package/dist/tools/security-review.js.map +1 -0
- package/dist/tools/setup-red-team-target.d.ts +79 -0
- package/dist/tools/setup-red-team-target.js +430 -0
- package/dist/tools/setup-red-team-target.js.map +1 -0
- package/dist/tools/triage-finding.d.ts +47 -0
- package/dist/tools/triage-finding.js +116 -0
- package/dist/tools/triage-finding.js.map +1 -0
- package/dist/tools/update-document.d.ts +28 -0
- package/dist/tools/update-document.js +63 -0
- package/dist/tools/update-document.js.map +1 -0
- package/dist/tools/update-endpoint.d.ts +65 -0
- package/dist/tools/update-endpoint.js +145 -0
- package/dist/tools/update-endpoint.js.map +1 -0
- package/dist/tools/update-mermaid-source.d.ts +34 -0
- package/dist/tools/update-mermaid-source.js +76 -0
- package/dist/tools/update-mermaid-source.js.map +1 -0
- package/dist/tools/verify-trust-mark.d.ts +29 -0
- package/dist/tools/verify-trust-mark.js +108 -0
- package/dist/tools/verify-trust-mark.js.map +1 -0
- package/dist/types.d.ts +220 -0
- package/dist/types.js +33 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZIVIS API Client
|
|
3
|
+
*
|
|
4
|
+
* HTTPS client that attaches the appropriate auth header
|
|
5
|
+
* based on the active auth method:
|
|
6
|
+
* - OAuth: Authorization: Bearer <token>
|
|
7
|
+
* - API Key: X-API-Key: <key>
|
|
8
|
+
*
|
|
9
|
+
* Handles 401 responses by attempting token refresh (OAuth)
|
|
10
|
+
* before returning an auth error.
|
|
11
|
+
*/
|
|
12
|
+
import type { ZivisConfig } from "./types.js";
|
|
13
|
+
export declare class ApiClient {
|
|
14
|
+
private config;
|
|
15
|
+
constructor(config?: ZivisConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Build auth headers from current credentials
|
|
18
|
+
*/
|
|
19
|
+
private buildAuthHeaders;
|
|
20
|
+
/**
|
|
21
|
+
* Make an authenticated request to the ZIVIS API.
|
|
22
|
+
*
|
|
23
|
+
* Automatically resolves credentials and attaches auth headers.
|
|
24
|
+
* On 401 with OAuth, attempts one token refresh and retries.
|
|
25
|
+
*/
|
|
26
|
+
request<T>(method: string, path: string, body?: unknown): Promise<T>;
|
|
27
|
+
private doRequest;
|
|
28
|
+
get<T>(path: string): Promise<T>;
|
|
29
|
+
/**
|
|
30
|
+
* Fetch a path and return the response as plain text (not JSON).
|
|
31
|
+
* Used for artifact content streaming where the response is not JSON.
|
|
32
|
+
*/
|
|
33
|
+
getText(path: string): Promise<string>;
|
|
34
|
+
patch<T>(path: string, body: unknown): Promise<T>;
|
|
35
|
+
post<T>(path: string, body: unknown): Promise<T>;
|
|
36
|
+
del<T>(path: string): Promise<T>;
|
|
37
|
+
}
|
|
38
|
+
export declare class ApiError extends Error {
|
|
39
|
+
readonly status: number;
|
|
40
|
+
readonly code: string;
|
|
41
|
+
constructor(message: string, status: number, code: string);
|
|
42
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZIVIS API Client
|
|
3
|
+
*
|
|
4
|
+
* HTTPS client that attaches the appropriate auth header
|
|
5
|
+
* based on the active auth method:
|
|
6
|
+
* - OAuth: Authorization: Bearer <token>
|
|
7
|
+
* - API Key: X-API-Key: <key>
|
|
8
|
+
*
|
|
9
|
+
* Handles 401 responses by attempting token refresh (OAuth)
|
|
10
|
+
* before returning an auth error.
|
|
11
|
+
*/
|
|
12
|
+
import { resolveAuth } from "./auth/index.js";
|
|
13
|
+
import { DEFAULT_CONFIG } from "./types.js";
|
|
14
|
+
export class ApiClient {
|
|
15
|
+
config;
|
|
16
|
+
constructor(config = DEFAULT_CONFIG) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build auth headers from current credentials
|
|
21
|
+
*/
|
|
22
|
+
buildAuthHeaders(creds) {
|
|
23
|
+
switch (creds.method) {
|
|
24
|
+
case "oauth":
|
|
25
|
+
return { Authorization: `Bearer ${creds.accessToken}` };
|
|
26
|
+
case "apikey":
|
|
27
|
+
return { "X-API-Key": creds.apiKey };
|
|
28
|
+
case "none":
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Make an authenticated request to the ZIVIS API.
|
|
34
|
+
*
|
|
35
|
+
* Automatically resolves credentials and attaches auth headers.
|
|
36
|
+
* On 401 with OAuth, attempts one token refresh and retries.
|
|
37
|
+
*/
|
|
38
|
+
async request(method, path, body) {
|
|
39
|
+
const creds = await resolveAuth(this.config);
|
|
40
|
+
if (creds.method === "none") {
|
|
41
|
+
throw new ApiError("Not authenticated. Run: zivis auth login", 401, "AUTH_REQUIRED");
|
|
42
|
+
}
|
|
43
|
+
const result = await this.doRequest(method, path, body, creds);
|
|
44
|
+
// If 401 and using OAuth, try refreshing
|
|
45
|
+
if (result.status === 401 && creds.method === "oauth") {
|
|
46
|
+
const freshCreds = await resolveAuth(this.config);
|
|
47
|
+
if (freshCreds.method === "oauth" &&
|
|
48
|
+
freshCreds.accessToken !== creds.accessToken) {
|
|
49
|
+
// Token was refreshed, retry
|
|
50
|
+
const retryResult = await this.doRequest(method, path, body, freshCreds);
|
|
51
|
+
if (retryResult.status === 401) {
|
|
52
|
+
throw new ApiError("Session expired. Run: zivis auth login", 401, "SESSION_EXPIRED");
|
|
53
|
+
}
|
|
54
|
+
if (!retryResult.ok) {
|
|
55
|
+
throw new ApiError(retryResult.errorMessage || "API request failed", retryResult.status, "API_ERROR");
|
|
56
|
+
}
|
|
57
|
+
return retryResult.data;
|
|
58
|
+
}
|
|
59
|
+
throw new ApiError("Session expired. Run: zivis auth login", 401, "SESSION_EXPIRED");
|
|
60
|
+
}
|
|
61
|
+
if (!result.ok) {
|
|
62
|
+
throw new ApiError(result.errorMessage || `API request failed: ${method} ${path}`, result.status, "API_ERROR");
|
|
63
|
+
}
|
|
64
|
+
return result.data;
|
|
65
|
+
}
|
|
66
|
+
async doRequest(method, path, body, creds) {
|
|
67
|
+
const url = `${this.config.apiBaseUrl}${path}`;
|
|
68
|
+
const headers = {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
"User-Agent": "@zivis-ai/cli",
|
|
71
|
+
...this.buildAuthHeaders(creds),
|
|
72
|
+
};
|
|
73
|
+
const fetchOptions = { method, headers };
|
|
74
|
+
if (body && method !== "GET") {
|
|
75
|
+
fetchOptions.body = JSON.stringify(body);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetch(url, fetchOptions);
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
status: response.status,
|
|
84
|
+
errorMessage: errorBody.message ||
|
|
85
|
+
errorBody.error ||
|
|
86
|
+
`HTTP ${response.status}`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const data = (await response.json());
|
|
90
|
+
return { ok: true, status: response.status, data };
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
// Network error
|
|
94
|
+
const message = err instanceof Error ? err.message : "Network request failed";
|
|
95
|
+
throw new ApiError(`Failed to connect to ZIVIS API (${url}): ${message}`, 0, "NETWORK_ERROR");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ── Convenience methods ──
|
|
99
|
+
async get(path) {
|
|
100
|
+
return this.request("GET", path);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Fetch a path and return the response as plain text (not JSON).
|
|
104
|
+
* Used for artifact content streaming where the response is not JSON.
|
|
105
|
+
*/
|
|
106
|
+
async getText(path) {
|
|
107
|
+
const creds = await resolveAuth(this.config);
|
|
108
|
+
if (creds.method === "none") {
|
|
109
|
+
throw new ApiError("Not authenticated. Run: zivis auth login", 401, "AUTH_REQUIRED");
|
|
110
|
+
}
|
|
111
|
+
const url = `${this.config.apiBaseUrl}${path}`;
|
|
112
|
+
const headers = {
|
|
113
|
+
"User-Agent": "@zivis-ai/cli",
|
|
114
|
+
...this.buildAuthHeaders(creds),
|
|
115
|
+
};
|
|
116
|
+
const response = await fetch(url, { method: "GET", headers });
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
119
|
+
throw new ApiError(errorBody.message ||
|
|
120
|
+
errorBody.error ||
|
|
121
|
+
`HTTP ${response.status}`, response.status, "API_ERROR");
|
|
122
|
+
}
|
|
123
|
+
return response.text();
|
|
124
|
+
}
|
|
125
|
+
async patch(path, body) {
|
|
126
|
+
return this.request("PATCH", path, body);
|
|
127
|
+
}
|
|
128
|
+
async post(path, body) {
|
|
129
|
+
return this.request("POST", path, body);
|
|
130
|
+
}
|
|
131
|
+
async del(path) {
|
|
132
|
+
return this.request("DELETE", path);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export class ApiError extends Error {
|
|
136
|
+
status;
|
|
137
|
+
code;
|
|
138
|
+
constructor(message, status, code) {
|
|
139
|
+
super(message);
|
|
140
|
+
this.status = status;
|
|
141
|
+
this.code = code;
|
|
142
|
+
this.name = "ApiError";
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Resolves credentials using the defined precedence:
|
|
5
|
+
* 1. OS Keychain — OAuth tokens (preferred, user-scoped, auto-refresh)
|
|
6
|
+
* 2. OS Keychain — API key (fallback, org-scoped)
|
|
7
|
+
* 3. ZIVIS_API_KEY env var (CI environments)
|
|
8
|
+
* 4. Not authenticated (tools return auth error with setup instructions)
|
|
9
|
+
*/
|
|
10
|
+
import type { AuthCredentials, AuthMethod, ZivisConfig } from "../types.js";
|
|
11
|
+
export { login } from "./oauth.js";
|
|
12
|
+
export { keychainClearAll, keychainClearSession, getStorageName, getSessionAccount } from "./keychain.js";
|
|
13
|
+
export { keychainStore, keychainRead } from "./keychain.js";
|
|
14
|
+
export { loadTokens } from "./token-refresh.js";
|
|
15
|
+
export { loadSessionIndex, saveSessionEntry, removeSessionEntry, listSessions } from "./sessions.js";
|
|
16
|
+
/**
|
|
17
|
+
* Resolve current auth credentials following the precedence chain.
|
|
18
|
+
*
|
|
19
|
+
* IMPORTANT: When config.session is set (ZIVIS_SESSION env var), auth resolution
|
|
20
|
+
* is scoped to that session ONLY. It will NOT fall through to the default session
|
|
21
|
+
* or API key — this prevents accidental cross-tenant data access.
|
|
22
|
+
*
|
|
23
|
+
* @param forceMethod - Override the automatic method selection
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveAuth(config?: ZivisConfig, forceMethod?: AuthMethod): Promise<AuthCredentials>;
|
|
26
|
+
/**
|
|
27
|
+
* Get a human-readable description of the current auth state
|
|
28
|
+
*/
|
|
29
|
+
export declare function getAuthDescription(config?: ZivisConfig): Promise<string>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Resolves credentials using the defined precedence:
|
|
5
|
+
* 1. OS Keychain — OAuth tokens (preferred, user-scoped, auto-refresh)
|
|
6
|
+
* 2. OS Keychain — API key (fallback, org-scoped)
|
|
7
|
+
* 3. ZIVIS_API_KEY env var (CI environments)
|
|
8
|
+
* 4. Not authenticated (tools return auth error with setup instructions)
|
|
9
|
+
*/
|
|
10
|
+
import { keychainRead } from "./keychain.js";
|
|
11
|
+
import { getValidAccessToken } from "./token-refresh.js";
|
|
12
|
+
import { DEFAULT_CONFIG } from "../types.js";
|
|
13
|
+
export { login } from "./oauth.js";
|
|
14
|
+
export { keychainClearAll, keychainClearSession, getStorageName, getSessionAccount } from "./keychain.js";
|
|
15
|
+
export { keychainStore, keychainRead } from "./keychain.js";
|
|
16
|
+
export { loadTokens } from "./token-refresh.js";
|
|
17
|
+
export { loadSessionIndex, saveSessionEntry, removeSessionEntry, listSessions } from "./sessions.js";
|
|
18
|
+
/**
|
|
19
|
+
* Resolve current auth credentials following the precedence chain.
|
|
20
|
+
*
|
|
21
|
+
* IMPORTANT: When config.session is set (ZIVIS_SESSION env var), auth resolution
|
|
22
|
+
* is scoped to that session ONLY. It will NOT fall through to the default session
|
|
23
|
+
* or API key — this prevents accidental cross-tenant data access.
|
|
24
|
+
*
|
|
25
|
+
* @param forceMethod - Override the automatic method selection
|
|
26
|
+
*/
|
|
27
|
+
export async function resolveAuth(config = DEFAULT_CONFIG, forceMethod) {
|
|
28
|
+
const session = config.session;
|
|
29
|
+
// 1. OAuth tokens (unless forced to apikey)
|
|
30
|
+
if (forceMethod !== "apikey") {
|
|
31
|
+
const accessToken = await getValidAccessToken(config);
|
|
32
|
+
if (accessToken) {
|
|
33
|
+
return { method: "oauth", accessToken };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// 2. ZIVIS_API_KEY env var — always checked, even for named sessions.
|
|
37
|
+
// This is an explicit user action (they set the env var in their MCP config),
|
|
38
|
+
// so it's safe to use regardless of session scope.
|
|
39
|
+
const envKey = process.env.ZIVIS_API_KEY;
|
|
40
|
+
if (envKey) {
|
|
41
|
+
return { method: "apikey", apiKey: envKey };
|
|
42
|
+
}
|
|
43
|
+
// CROSS-TENANT SAFETY: If a named session is active, do NOT fall through
|
|
44
|
+
// to default keychain credentials. This prevents accidentally using admin tokens
|
|
45
|
+
// when working in a customer's project.
|
|
46
|
+
if (session) {
|
|
47
|
+
return { method: "none" };
|
|
48
|
+
}
|
|
49
|
+
// 3. API key from keychain (only for default/no-session)
|
|
50
|
+
if (forceMethod !== "oauth") {
|
|
51
|
+
const apiKey = await keychainRead("apikey");
|
|
52
|
+
if (apiKey) {
|
|
53
|
+
return { method: "apikey", apiKey };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// 4. Not authenticated
|
|
57
|
+
return { method: "none" };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get a human-readable description of the current auth state
|
|
61
|
+
*/
|
|
62
|
+
export async function getAuthDescription(config = DEFAULT_CONFIG) {
|
|
63
|
+
const creds = await resolveAuth(config);
|
|
64
|
+
switch (creds.method) {
|
|
65
|
+
case "oauth":
|
|
66
|
+
return "OAuth (access token)";
|
|
67
|
+
case "apikey":
|
|
68
|
+
return `API Key (${creds.apiKey?.startsWith("sk_") ? `sk_...${creds.apiKey.slice(-4)}` : "***"})`;
|
|
69
|
+
case "none":
|
|
70
|
+
return "Not authenticated";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC1G,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAErG;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAsB,cAAc,EACpC,WAAwB;IAExB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAE/B,4CAA4C;IAC5C,IAAI,WAAW,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,8EAA8E;IAC9E,mDAAmD;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACzC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC9C,CAAC;IAED,yEAAyE;IACzE,iFAAiF;IACjF,wCAAwC;IACxC,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC5B,CAAC;IAED,yDAAyD;IACzD,IAAI,WAAW,KAAK,OAAO,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IAED,uBAAuB;IACvB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAsB,cAAc;IAEpC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,KAAK,CAAC,MAAM,EAAE,CAAC;QACrB,KAAK,OAAO;YACV,OAAO,sBAAsB,CAAC;QAChC,KAAK,QAAQ;YACX,OAAO,YAAY,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;QACpG,KAAK,MAAM;YACT,OAAO,mBAAmB,CAAC;IAC/B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT helpers for local safety checks.
|
|
3
|
+
*
|
|
4
|
+
* The API is the authoritative verifier of JWT signatures. These helpers
|
|
5
|
+
* decode the payload only to read claims locally (org_id, email, sub) so
|
|
6
|
+
* the CLI/MCP server can enforce project-binding guardrails before making
|
|
7
|
+
* any API calls.
|
|
8
|
+
*/
|
|
9
|
+
export interface JwtClaims {
|
|
10
|
+
/** WorkOS user sub (e.g., "user_01HXYZ...") */
|
|
11
|
+
sub?: string;
|
|
12
|
+
/** WorkOS org ID (e.g., "org_01HXYZ...") */
|
|
13
|
+
org_id?: string;
|
|
14
|
+
/** Email (present on id_token, sometimes on access_token) */
|
|
15
|
+
email?: string;
|
|
16
|
+
/** Expiry (unix seconds) */
|
|
17
|
+
exp?: number;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Decode a JWT payload WITHOUT verifying the signature.
|
|
22
|
+
* Returns null if the token is malformed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function decodeJwtPayload(token: string): JwtClaims | null;
|
package/dist/auth/jwt.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT helpers for local safety checks.
|
|
3
|
+
*
|
|
4
|
+
* The API is the authoritative verifier of JWT signatures. These helpers
|
|
5
|
+
* decode the payload only to read claims locally (org_id, email, sub) so
|
|
6
|
+
* the CLI/MCP server can enforce project-binding guardrails before making
|
|
7
|
+
* any API calls.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Decode a JWT payload WITHOUT verifying the signature.
|
|
11
|
+
* Returns null if the token is malformed.
|
|
12
|
+
*/
|
|
13
|
+
export function decodeJwtPayload(token) {
|
|
14
|
+
try {
|
|
15
|
+
const parts = token.split(".");
|
|
16
|
+
if (parts.length !== 3)
|
|
17
|
+
return null;
|
|
18
|
+
const payload = Buffer.from(parts[1], "base64url").toString("utf8");
|
|
19
|
+
return JSON.parse(payload);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../src/auth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAc,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OS Keychain credential storage
|
|
3
|
+
*
|
|
4
|
+
* Uses native OS CLI commands to store/retrieve credentials securely.
|
|
5
|
+
* No native npm dependencies (no keytar).
|
|
6
|
+
*
|
|
7
|
+
* - macOS: Keychain Services via `security` CLI
|
|
8
|
+
* - Linux: Secret Service API via `secret-tool` CLI
|
|
9
|
+
* - Windows: DPAPI via PowerShell
|
|
10
|
+
*
|
|
11
|
+
* Falls back to encrypted file if keychain CLI is unavailable.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Returns the keychain account key for a given session.
|
|
15
|
+
* - No session or undefined → "oauth" (backward compatible)
|
|
16
|
+
* - Named session → "oauth.{session}"
|
|
17
|
+
*/
|
|
18
|
+
export declare function getSessionAccount(session?: string): string;
|
|
19
|
+
export declare function keychainStore(account: string, value: string): Promise<void>;
|
|
20
|
+
export declare function keychainRead(account: string): Promise<string | null>;
|
|
21
|
+
export declare function keychainDelete(account: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Delete credentials for a specific session
|
|
24
|
+
*/
|
|
25
|
+
export declare function keychainClearSession(session?: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Delete all stored credentials (default OAuth + API key).
|
|
28
|
+
* Does NOT clear named sessions — use keychainClearSession() for those.
|
|
29
|
+
*/
|
|
30
|
+
export declare function keychainClearAll(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the storage mechanism name for display purposes
|
|
33
|
+
*/
|
|
34
|
+
export declare function getStorageName(): string;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OS Keychain credential storage
|
|
3
|
+
*
|
|
4
|
+
* Uses native OS CLI commands to store/retrieve credentials securely.
|
|
5
|
+
* No native npm dependencies (no keytar).
|
|
6
|
+
*
|
|
7
|
+
* - macOS: Keychain Services via `security` CLI
|
|
8
|
+
* - Linux: Secret Service API via `secret-tool` CLI
|
|
9
|
+
* - Windows: DPAPI via PowerShell
|
|
10
|
+
*
|
|
11
|
+
* Falls back to encrypted file if keychain CLI is unavailable.
|
|
12
|
+
*/
|
|
13
|
+
import { execFile } from "node:child_process";
|
|
14
|
+
import { promisify } from "node:util";
|
|
15
|
+
import * as fs from "node:fs/promises";
|
|
16
|
+
import * as path from "node:path";
|
|
17
|
+
import * as os from "node:os";
|
|
18
|
+
import * as crypto from "node:crypto";
|
|
19
|
+
import { ENV_CONFIG } from "../types.js";
|
|
20
|
+
const execFileAsync = promisify(execFile);
|
|
21
|
+
// Use environment-aware prefix so staging and production credentials are isolated
|
|
22
|
+
const SERVICE_PREFIX = ENV_CONFIG.keychainPrefix;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the keychain account key for a given session.
|
|
25
|
+
* - No session or undefined → "oauth" (backward compatible)
|
|
26
|
+
* - Named session → "oauth.{session}"
|
|
27
|
+
*/
|
|
28
|
+
export function getSessionAccount(session) {
|
|
29
|
+
return session ? `oauth.${session}` : "oauth";
|
|
30
|
+
}
|
|
31
|
+
function getServiceName(account) {
|
|
32
|
+
return `${SERVICE_PREFIX}.${account}`;
|
|
33
|
+
}
|
|
34
|
+
function getFallbackDir() {
|
|
35
|
+
// Use environment-aware config dir so staging and production are isolated
|
|
36
|
+
const configDir = ENV_CONFIG.configDir;
|
|
37
|
+
if (process.platform === "win32") {
|
|
38
|
+
return path.join(process.env.APPDATA || os.homedir(), configDir);
|
|
39
|
+
}
|
|
40
|
+
return path.join(os.homedir(), ".config", configDir);
|
|
41
|
+
}
|
|
42
|
+
function getFallbackPath(account) {
|
|
43
|
+
return path.join(getFallbackDir(), `${account}.enc`);
|
|
44
|
+
}
|
|
45
|
+
// ── macOS Keychain ──
|
|
46
|
+
async function macosStore(account, value) {
|
|
47
|
+
const service = getServiceName(account);
|
|
48
|
+
// Delete existing entry first (ignore errors if not found)
|
|
49
|
+
try {
|
|
50
|
+
await execFileAsync("security", [
|
|
51
|
+
"delete-generic-password",
|
|
52
|
+
"-a",
|
|
53
|
+
"zivis-mcp",
|
|
54
|
+
"-s",
|
|
55
|
+
service,
|
|
56
|
+
]);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Entry didn't exist, that's fine
|
|
60
|
+
}
|
|
61
|
+
await execFileAsync("security", [
|
|
62
|
+
"add-generic-password",
|
|
63
|
+
"-a",
|
|
64
|
+
"zivis-mcp",
|
|
65
|
+
"-s",
|
|
66
|
+
service,
|
|
67
|
+
"-w",
|
|
68
|
+
value,
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
async function macosRead(account) {
|
|
72
|
+
const service = getServiceName(account);
|
|
73
|
+
try {
|
|
74
|
+
const { stdout } = await execFileAsync("security", [
|
|
75
|
+
"find-generic-password",
|
|
76
|
+
"-a",
|
|
77
|
+
"zivis-mcp",
|
|
78
|
+
"-s",
|
|
79
|
+
service,
|
|
80
|
+
"-w",
|
|
81
|
+
]);
|
|
82
|
+
return stdout.trim();
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function macosDelete(account) {
|
|
89
|
+
const service = getServiceName(account);
|
|
90
|
+
try {
|
|
91
|
+
await execFileAsync("security", [
|
|
92
|
+
"delete-generic-password",
|
|
93
|
+
"-a",
|
|
94
|
+
"zivis-mcp",
|
|
95
|
+
"-s",
|
|
96
|
+
service,
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Entry didn't exist
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ── Linux Secret Service ──
|
|
104
|
+
async function linuxStore(account, value) {
|
|
105
|
+
const child = execFileAsync("secret-tool", [
|
|
106
|
+
"store",
|
|
107
|
+
"--label",
|
|
108
|
+
`ZIVIS MCP ${account}`,
|
|
109
|
+
"service",
|
|
110
|
+
SERVICE_PREFIX,
|
|
111
|
+
"account",
|
|
112
|
+
account,
|
|
113
|
+
]);
|
|
114
|
+
// secret-tool reads value from stdin
|
|
115
|
+
child.child.stdin?.write(value);
|
|
116
|
+
child.child.stdin?.end();
|
|
117
|
+
await child;
|
|
118
|
+
}
|
|
119
|
+
async function linuxRead(account) {
|
|
120
|
+
try {
|
|
121
|
+
const { stdout } = await execFileAsync("secret-tool", [
|
|
122
|
+
"lookup",
|
|
123
|
+
"service",
|
|
124
|
+
SERVICE_PREFIX,
|
|
125
|
+
"account",
|
|
126
|
+
account,
|
|
127
|
+
]);
|
|
128
|
+
return stdout.trim() || null;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function linuxDelete(account) {
|
|
135
|
+
try {
|
|
136
|
+
await execFileAsync("secret-tool", [
|
|
137
|
+
"clear",
|
|
138
|
+
"service",
|
|
139
|
+
SERVICE_PREFIX,
|
|
140
|
+
"account",
|
|
141
|
+
account,
|
|
142
|
+
]);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Entry didn't exist
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// ── Encrypted File Fallback (Windows + fallback for all platforms) ──
|
|
149
|
+
function deriveKey() {
|
|
150
|
+
// Use machine-specific data as encryption key seed
|
|
151
|
+
const seed = `zivis-mcp:${os.hostname()}:${os.userInfo().username}`;
|
|
152
|
+
return crypto.createHash("sha256").update(seed).digest();
|
|
153
|
+
}
|
|
154
|
+
async function fileStore(account, value) {
|
|
155
|
+
const key = deriveKey();
|
|
156
|
+
const iv = crypto.randomBytes(16);
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
158
|
+
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
|
|
159
|
+
let encrypted = cipher.update(value, "utf8", "hex");
|
|
160
|
+
encrypted += cipher.final("hex");
|
|
161
|
+
const data = JSON.stringify({ iv: iv.toString("hex"), data: encrypted });
|
|
162
|
+
const dir = getFallbackDir();
|
|
163
|
+
await fs.mkdir(dir, { recursive: true });
|
|
164
|
+
await fs.writeFile(getFallbackPath(account), data, { mode: 0o600 });
|
|
165
|
+
}
|
|
166
|
+
async function fileRead(account) {
|
|
167
|
+
try {
|
|
168
|
+
const raw = await fs.readFile(getFallbackPath(account), "utf8");
|
|
169
|
+
const { iv, data } = JSON.parse(raw);
|
|
170
|
+
const key = deriveKey();
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
+
const decipher = crypto.createDecipheriv("aes-256-cbc", key, Buffer.from(iv, "hex"));
|
|
173
|
+
let decrypted = decipher.update(data, "hex", "utf8");
|
|
174
|
+
decrypted += decipher.final("utf8");
|
|
175
|
+
return decrypted;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async function fileDelete(account) {
|
|
182
|
+
try {
|
|
183
|
+
await fs.unlink(getFallbackPath(account));
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// File didn't exist
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// ── Platform Detection & Dispatch ──
|
|
190
|
+
async function isKeychainAvailable() {
|
|
191
|
+
try {
|
|
192
|
+
if (process.platform === "darwin") {
|
|
193
|
+
await execFileAsync("security", ["help"]);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if (process.platform === "linux") {
|
|
197
|
+
await execFileAsync("which", ["secret-tool"]);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
let keychainAvailable = null;
|
|
207
|
+
async function useKeychain() {
|
|
208
|
+
if (keychainAvailable === null) {
|
|
209
|
+
keychainAvailable = await isKeychainAvailable();
|
|
210
|
+
}
|
|
211
|
+
return keychainAvailable;
|
|
212
|
+
}
|
|
213
|
+
// ── Public API ──
|
|
214
|
+
export async function keychainStore(account, value) {
|
|
215
|
+
// Always store to encrypted file as fallback (for environments where keychain CLI
|
|
216
|
+
// may not be available, e.g., MCP servers spawned by IDEs with different $PATH)
|
|
217
|
+
await fileStore(account, value);
|
|
218
|
+
// Also store to native keychain if available
|
|
219
|
+
if (await useKeychain()) {
|
|
220
|
+
if (process.platform === "darwin") {
|
|
221
|
+
await macosStore(account, value);
|
|
222
|
+
}
|
|
223
|
+
else if (process.platform === "linux") {
|
|
224
|
+
await linuxStore(account, value);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
export async function keychainRead(account) {
|
|
229
|
+
if (await useKeychain()) {
|
|
230
|
+
if (process.platform === "darwin")
|
|
231
|
+
return macosRead(account);
|
|
232
|
+
if (process.platform === "linux")
|
|
233
|
+
return linuxRead(account);
|
|
234
|
+
}
|
|
235
|
+
return fileRead(account);
|
|
236
|
+
}
|
|
237
|
+
export async function keychainDelete(account) {
|
|
238
|
+
if (await useKeychain()) {
|
|
239
|
+
if (process.platform === "darwin")
|
|
240
|
+
return macosDelete(account);
|
|
241
|
+
if (process.platform === "linux")
|
|
242
|
+
return linuxDelete(account);
|
|
243
|
+
}
|
|
244
|
+
return fileDelete(account);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Delete credentials for a specific session
|
|
248
|
+
*/
|
|
249
|
+
export async function keychainClearSession(session) {
|
|
250
|
+
await keychainDelete(getSessionAccount(session));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Delete all stored credentials (default OAuth + API key).
|
|
254
|
+
* Does NOT clear named sessions — use keychainClearSession() for those.
|
|
255
|
+
*/
|
|
256
|
+
export async function keychainClearAll() {
|
|
257
|
+
await keychainDelete("oauth");
|
|
258
|
+
await keychainDelete("apikey");
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Returns the storage mechanism name for display purposes
|
|
262
|
+
*/
|
|
263
|
+
export function getStorageName() {
|
|
264
|
+
if (process.platform === "darwin")
|
|
265
|
+
return "macOS Keychain";
|
|
266
|
+
if (process.platform === "linux")
|
|
267
|
+
return "Secret Service";
|
|
268
|
+
if (process.platform === "win32")
|
|
269
|
+
return "encrypted file";
|
|
270
|
+
return "encrypted file";
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=keychain.js.map
|