@securecode-ai/mcp 0.1.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/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/api/client.d.ts +22 -0
- package/dist/api/client.js +141 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/types.d.ts +129 -0
- package/dist/api/types.js +3 -0
- package/dist/api/types.js.map +1 -0
- package/dist/approval/auditLog.d.ts +3 -0
- package/dist/approval/auditLog.js +67 -0
- package/dist/approval/auditLog.js.map +1 -0
- package/dist/approval/broker.d.ts +11 -0
- package/dist/approval/broker.js +252 -0
- package/dist/approval/broker.js.map +1 -0
- package/dist/approval/types.d.ts +26 -0
- package/dist/approval/types.js +58 -0
- package/dist/approval/types.js.map +1 -0
- package/dist/attack/agentLoop.d.ts +21 -0
- package/dist/attack/agentLoop.js +148 -0
- package/dist/attack/agentLoop.js.map +1 -0
- package/dist/attack/executor.d.ts +17 -0
- package/dist/attack/executor.js +162 -0
- package/dist/attack/executor.js.map +1 -0
- package/dist/attack/policy.d.ts +26 -0
- package/dist/attack/policy.js +73 -0
- package/dist/attack/policy.js.map +1 -0
- package/dist/attack/protocol.d.ts +64 -0
- package/dist/attack/protocol.js +3 -0
- package/dist/attack/protocol.js.map +1 -0
- package/dist/attack/report.d.ts +16 -0
- package/dist/attack/report.js +54 -0
- package/dist/attack/report.js.map +1 -0
- package/dist/auth/credentialStore.d.ts +20 -0
- package/dist/auth/credentialStore.js +148 -0
- package/dist/auth/credentialStore.js.map +1 -0
- package/dist/auth/keychain.d.ts +14 -0
- package/dist/auth/keychain.js +267 -0
- package/dist/auth/keychain.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +170 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +183 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +2 -0
- package/dist/mcp/tools.js +120 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +26 -0
- package/dist/mcp/types.js +3 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/project-map/astHelpers.d.ts +89 -0
- package/dist/project-map/astHelpers.js +468 -0
- package/dist/project-map/astHelpers.js.map +1 -0
- package/dist/project-map/cache.d.ts +11 -0
- package/dist/project-map/cache.js +86 -0
- package/dist/project-map/cache.js.map +1 -0
- package/dist/project-map/confidence.d.ts +50 -0
- package/dist/project-map/confidence.js +87 -0
- package/dist/project-map/confidence.js.map +1 -0
- package/dist/project-map/crossFile.d.ts +73 -0
- package/dist/project-map/crossFile.js +33 -0
- package/dist/project-map/crossFile.js.map +1 -0
- package/dist/project-map/detectors.d.ts +83 -0
- package/dist/project-map/detectors.js +376 -0
- package/dist/project-map/detectors.js.map +1 -0
- package/dist/project-map/layer1.d.ts +74 -0
- package/dist/project-map/layer1.js +928 -0
- package/dist/project-map/layer1.js.map +1 -0
- package/dist/project-map/layer2.d.ts +30 -0
- package/dist/project-map/layer2.js +249 -0
- package/dist/project-map/layer2.js.map +1 -0
- package/dist/project-map/mapBuilder.d.ts +17 -0
- package/dist/project-map/mapBuilder.js +164 -0
- package/dist/project-map/mapBuilder.js.map +1 -0
- package/dist/project-map/parserLoader.d.ts +61 -0
- package/dist/project-map/parserLoader.js +175 -0
- package/dist/project-map/parserLoader.js.map +1 -0
- package/dist/project-map/schemas.d.ts +28 -0
- package/dist/project-map/schemas.js +131 -0
- package/dist/project-map/schemas.js.map +1 -0
- package/dist/project-map/types.d.ts +232 -0
- package/dist/project-map/types.js +61 -0
- package/dist/project-map/types.js.map +1 -0
- package/dist/tools/attack.d.ts +2 -0
- package/dist/tools/attack.js +80 -0
- package/dist/tools/attack.js.map +1 -0
- package/dist/tools/fix.d.ts +2 -0
- package/dist/tools/fix.js +60 -0
- package/dist/tools/fix.js.map +1 -0
- package/dist/tools/map.d.ts +2 -0
- package/dist/tools/map.js +46 -0
- package/dist/tools/map.js.map +1 -0
- package/dist/tools/scan.d.ts +2 -0
- package/dist/tools/scan.js +55 -0
- package/dist/tools/scan.js.map +1 -0
- package/dist/utils/files.d.ts +8 -0
- package/dist/utils/files.js +79 -0
- package/dist/utils/files.js.map +1 -0
- package/package.json +53 -0
- package/resources/tree-sitter/tree-sitter-javascript.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-python.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-tsx.wasm +0 -0
- package/resources/tree-sitter/tree-sitter-typescript.wasm +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.executeHttpRequest = executeHttpRequest;
|
|
37
|
+
const http = __importStar(require("http"));
|
|
38
|
+
const https = __importStar(require("https"));
|
|
39
|
+
const policy_1 = require("./policy");
|
|
40
|
+
async function executeHttpRequest(req, budget, signal) {
|
|
41
|
+
const startTime = Date.now();
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const bodyData = req.body ? JSON.stringify(req.body) : undefined;
|
|
44
|
+
const isHttps = false; // localhost only, HTTP by default
|
|
45
|
+
const lib = isHttps ? https : http;
|
|
46
|
+
const requestOptions = {
|
|
47
|
+
hostname: req.host,
|
|
48
|
+
port: req.port,
|
|
49
|
+
path: req.path,
|
|
50
|
+
method: req.method,
|
|
51
|
+
headers: {
|
|
52
|
+
...(req.headers || {}),
|
|
53
|
+
...(bodyData ? { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(bodyData) } : {}),
|
|
54
|
+
},
|
|
55
|
+
timeout: budget.requestTimeoutMs,
|
|
56
|
+
};
|
|
57
|
+
const onRequest = (res) => {
|
|
58
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400) {
|
|
59
|
+
const location = res.headers.location;
|
|
60
|
+
if ((0, policy_1.isRedirectToNonLocal)(res.statusCode, location)) {
|
|
61
|
+
resolve({
|
|
62
|
+
statusCode: res.statusCode,
|
|
63
|
+
headers: res.headers,
|
|
64
|
+
body: '',
|
|
65
|
+
latencyMs: Date.now() - startTime,
|
|
66
|
+
error: `Redirect to non-localhost blocked: ${location}`,
|
|
67
|
+
});
|
|
68
|
+
res.destroy();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
let body = '';
|
|
73
|
+
let aborted = false;
|
|
74
|
+
let totalBytes = 0;
|
|
75
|
+
res.on('data', (chunk) => {
|
|
76
|
+
totalBytes += chunk.length;
|
|
77
|
+
if (totalBytes > budget.maxResponseBytes) {
|
|
78
|
+
aborted = true;
|
|
79
|
+
res.destroy();
|
|
80
|
+
resolve({
|
|
81
|
+
statusCode: res.statusCode || 0,
|
|
82
|
+
headers: res.headers,
|
|
83
|
+
body: body + chunk.toString('utf8').slice(0, budget.maxResponseBytes - body.length),
|
|
84
|
+
latencyMs: Date.now() - startTime,
|
|
85
|
+
error: `Response exceeded ${budget.maxResponseBytes} bytes`,
|
|
86
|
+
});
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
body += chunk.toString('utf8');
|
|
90
|
+
});
|
|
91
|
+
res.on('end', () => {
|
|
92
|
+
if (aborted)
|
|
93
|
+
return;
|
|
94
|
+
resolve({
|
|
95
|
+
statusCode: res.statusCode || 0,
|
|
96
|
+
headers: res.headers,
|
|
97
|
+
body,
|
|
98
|
+
latencyMs: Date.now() - startTime,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
res.on('error', (err) => {
|
|
102
|
+
if (aborted)
|
|
103
|
+
return;
|
|
104
|
+
resolve({
|
|
105
|
+
statusCode: 0,
|
|
106
|
+
headers: {},
|
|
107
|
+
body: '',
|
|
108
|
+
latencyMs: Date.now() - startTime,
|
|
109
|
+
error: err.message,
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const request = lib.request(requestOptions, onRequest);
|
|
114
|
+
request.on('error', (err) => {
|
|
115
|
+
resolve({
|
|
116
|
+
statusCode: 0,
|
|
117
|
+
headers: {},
|
|
118
|
+
body: '',
|
|
119
|
+
latencyMs: Date.now() - startTime,
|
|
120
|
+
error: err.message,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
request.on('timeout', () => {
|
|
124
|
+
request.destroy();
|
|
125
|
+
resolve({
|
|
126
|
+
statusCode: 0,
|
|
127
|
+
headers: {},
|
|
128
|
+
body: '',
|
|
129
|
+
latencyMs: Date.now() - startTime,
|
|
130
|
+
error: `Request timed out after ${budget.requestTimeoutMs}ms`,
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
if (signal) {
|
|
134
|
+
if (signal.aborted) {
|
|
135
|
+
request.destroy();
|
|
136
|
+
resolve({
|
|
137
|
+
statusCode: 0,
|
|
138
|
+
headers: {},
|
|
139
|
+
body: '',
|
|
140
|
+
latencyMs: Date.now() - startTime,
|
|
141
|
+
error: 'Cancelled by abort signal',
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
signal.addEventListener('abort', () => {
|
|
146
|
+
request.destroy();
|
|
147
|
+
resolve({
|
|
148
|
+
statusCode: 0,
|
|
149
|
+
headers: {},
|
|
150
|
+
body: '',
|
|
151
|
+
latencyMs: Date.now() - startTime,
|
|
152
|
+
error: 'Cancelled by abort signal',
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (bodyData) {
|
|
157
|
+
request.write(bodyData);
|
|
158
|
+
}
|
|
159
|
+
request.end();
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/attack/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface AttackBudget {
|
|
2
|
+
maxSteps: number;
|
|
3
|
+
maxRequests: number;
|
|
4
|
+
wallClockMs: number;
|
|
5
|
+
maxResponseBytes: number;
|
|
6
|
+
requestTimeoutMs: number;
|
|
7
|
+
}
|
|
8
|
+
export declare const DEFAULT_BUDGET: AttackBudget;
|
|
9
|
+
export declare class PolicyError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
export declare function isLocalhostHost(host: string): boolean;
|
|
13
|
+
export declare function validateTarget(target: {
|
|
14
|
+
host: string;
|
|
15
|
+
port: number;
|
|
16
|
+
path: string;
|
|
17
|
+
}): void;
|
|
18
|
+
export declare function isRedirectToNonLocal(statusCode: number, location: string | undefined): boolean;
|
|
19
|
+
export declare function checkBudget(budget: AttackBudget, state: {
|
|
20
|
+
stepsTaken: number;
|
|
21
|
+
requestsMade: number;
|
|
22
|
+
startTime: number;
|
|
23
|
+
}): {
|
|
24
|
+
exhausted: boolean;
|
|
25
|
+
reason?: string;
|
|
26
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PolicyError = exports.DEFAULT_BUDGET = void 0;
|
|
4
|
+
exports.isLocalhostHost = isLocalhostHost;
|
|
5
|
+
exports.validateTarget = validateTarget;
|
|
6
|
+
exports.isRedirectToNonLocal = isRedirectToNonLocal;
|
|
7
|
+
exports.checkBudget = checkBudget;
|
|
8
|
+
exports.DEFAULT_BUDGET = {
|
|
9
|
+
maxSteps: 12,
|
|
10
|
+
maxRequests: 50,
|
|
11
|
+
wallClockMs: 90_000,
|
|
12
|
+
maxResponseBytes: 1_000_000,
|
|
13
|
+
requestTimeoutMs: 10_000,
|
|
14
|
+
};
|
|
15
|
+
const ALLOWED_HOSTS = new Set(['127.0.0.1', 'localhost', '::1', '0:0:0:0:0:0:0:1']);
|
|
16
|
+
class PolicyError extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'PolicyError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.PolicyError = PolicyError;
|
|
23
|
+
function isLocalhostHost(host) {
|
|
24
|
+
const lower = host.toLowerCase();
|
|
25
|
+
return ALLOWED_HOSTS.has(lower);
|
|
26
|
+
}
|
|
27
|
+
function validateTarget(target) {
|
|
28
|
+
if (!isLocalhostHost(target.host)) {
|
|
29
|
+
throw new PolicyError(`Target host '${target.host}' is not allowed. Only localhost targets (127.0.0.1, localhost, ::1) are permitted.`);
|
|
30
|
+
}
|
|
31
|
+
if (!target.port || target.port < 1 || target.port > 65535) {
|
|
32
|
+
throw new PolicyError(`Port ${target.port} is invalid. Must be 1-65535.`);
|
|
33
|
+
}
|
|
34
|
+
if (!target.path.startsWith('/')) {
|
|
35
|
+
throw new PolicyError(`Path '${target.path}' must start with '/'.`);
|
|
36
|
+
}
|
|
37
|
+
if (target.path.includes('..')) {
|
|
38
|
+
throw new PolicyError(`Path '${target.path}' contains path traversal sequence.`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isRedirectToNonLocal(statusCode, location) {
|
|
42
|
+
if (!location)
|
|
43
|
+
return false;
|
|
44
|
+
if (statusCode < 300 || statusCode >= 400)
|
|
45
|
+
return false;
|
|
46
|
+
try {
|
|
47
|
+
if (location.startsWith('http://') || location.startsWith('https://')) {
|
|
48
|
+
const parsed = new URL(location);
|
|
49
|
+
return !isLocalhostHost(parsed.hostname);
|
|
50
|
+
}
|
|
51
|
+
if (location.startsWith('//')) {
|
|
52
|
+
const host = location.slice(2).split('/')[0].split(':')[0];
|
|
53
|
+
return !isLocalhostHost(host);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
function checkBudget(budget, state) {
|
|
62
|
+
if (state.stepsTaken >= budget.maxSteps) {
|
|
63
|
+
return { exhausted: true, reason: `Max steps (${budget.maxSteps}) reached.` };
|
|
64
|
+
}
|
|
65
|
+
if (state.requestsMade >= budget.maxRequests) {
|
|
66
|
+
return { exhausted: true, reason: `Max requests (${budget.maxRequests}) reached.` };
|
|
67
|
+
}
|
|
68
|
+
if (Date.now() - state.startTime > budget.wallClockMs) {
|
|
69
|
+
return { exhausted: true, reason: `Wall clock limit (${budget.wallClockMs}ms) exceeded.` };
|
|
70
|
+
}
|
|
71
|
+
return { exhausted: false };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/attack/policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type AgentHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
2
|
+
export interface AgentHttpRequestAction {
|
|
3
|
+
type: 'http_request';
|
|
4
|
+
method: AgentHttpMethod;
|
|
5
|
+
path: string;
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
body?: unknown;
|
|
8
|
+
rationale: string;
|
|
9
|
+
}
|
|
10
|
+
export interface AgentFinding {
|
|
11
|
+
category: string;
|
|
12
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
evidenceStepIndex: number;
|
|
16
|
+
}
|
|
17
|
+
export interface AgentFinishAction {
|
|
18
|
+
type: 'finish';
|
|
19
|
+
findings: AgentFinding[];
|
|
20
|
+
summary: string;
|
|
21
|
+
}
|
|
22
|
+
export type AgentAction = AgentHttpRequestAction | AgentFinishAction;
|
|
23
|
+
export interface AgentObservation {
|
|
24
|
+
statusCode: number;
|
|
25
|
+
headers: Record<string, string>;
|
|
26
|
+
body: string;
|
|
27
|
+
latencyMs: number;
|
|
28
|
+
error?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface AgentTranscriptStep {
|
|
31
|
+
action: AgentHttpRequestAction;
|
|
32
|
+
observation: AgentObservation;
|
|
33
|
+
}
|
|
34
|
+
export interface AgentStartResponse {
|
|
35
|
+
runId: string;
|
|
36
|
+
budget: {
|
|
37
|
+
stepsRemaining: number;
|
|
38
|
+
costSpentUsd: number;
|
|
39
|
+
costCapUsd: number;
|
|
40
|
+
};
|
|
41
|
+
attackerCredits: number;
|
|
42
|
+
}
|
|
43
|
+
export interface AgentStepRequest {
|
|
44
|
+
runId: string;
|
|
45
|
+
endpointContext: unknown;
|
|
46
|
+
language: string;
|
|
47
|
+
framework?: string;
|
|
48
|
+
handlerSource?: string;
|
|
49
|
+
transcript: AgentTranscriptStep[];
|
|
50
|
+
budget: {
|
|
51
|
+
stepsRemaining: number;
|
|
52
|
+
costSpentUsd: number;
|
|
53
|
+
costCapUsd: number;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export interface AgentStepResponse {
|
|
57
|
+
next: AgentAction | null;
|
|
58
|
+
costUsd: number;
|
|
59
|
+
tokens: number;
|
|
60
|
+
degraded: boolean;
|
|
61
|
+
costCapped: boolean;
|
|
62
|
+
stepsRemaining: number;
|
|
63
|
+
}
|
|
64
|
+
export type AgentRunStatus = 'completed' | 'capped' | 'degraded' | 'spawn_failed' | 'cancelled';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/attack/protocol.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentTranscriptStep, AgentFinding, AgentRunStatus } from './protocol';
|
|
2
|
+
export interface ReportedAgentFinding extends AgentFinding {
|
|
3
|
+
confirmation: 'confirmed' | 'suspected';
|
|
4
|
+
rule?: string;
|
|
5
|
+
reason?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AttackReport {
|
|
8
|
+
status: AgentRunStatus;
|
|
9
|
+
findings: ReportedAgentFinding[];
|
|
10
|
+
transcript: AgentTranscriptStep[];
|
|
11
|
+
summary?: string;
|
|
12
|
+
stepsUsed: number;
|
|
13
|
+
costSpentUsd: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function redactText(text: string): string;
|
|
16
|
+
export declare function buildReport(status: AgentRunStatus, findings: AgentFinding[], transcript: AgentTranscriptStep[], stepsUsed: number, costSpentUsd: number, summary?: string): AttackReport;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.redactText = redactText;
|
|
4
|
+
exports.buildReport = buildReport;
|
|
5
|
+
const JWT_RE = /eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
|
|
6
|
+
const API_KEY_RE = /\b[A-Za-z0-9]{32,}\b/g;
|
|
7
|
+
const EMAIL_RE = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
|
|
8
|
+
const BEARER_RE = /Bearer\s+[A-Za-z0-9._-]+/gi;
|
|
9
|
+
function redactText(text) {
|
|
10
|
+
return text
|
|
11
|
+
.replace(BEARER_RE, 'Bearer [REDACTED]')
|
|
12
|
+
.replace(JWT_RE, '[JWT_REDACTED]')
|
|
13
|
+
.replace(EMAIL_RE, '[EMAIL_REDACTED]')
|
|
14
|
+
.replace(API_KEY_RE, (match) => (match.length === 32 || match.length === 40 || match.length === 64 ? '[REDACTED]' : match));
|
|
15
|
+
}
|
|
16
|
+
function buildReport(status, findings, transcript, stepsUsed, costSpentUsd, summary) {
|
|
17
|
+
return {
|
|
18
|
+
status,
|
|
19
|
+
findings: findings.map((f) => ({
|
|
20
|
+
...f,
|
|
21
|
+
confirmation: 'suspected',
|
|
22
|
+
reason: 'Agent-reported finding (deterministic verification not yet implemented)',
|
|
23
|
+
})),
|
|
24
|
+
transcript: transcript.map((step) => ({
|
|
25
|
+
action: {
|
|
26
|
+
...step.action,
|
|
27
|
+
headers: redactHeaders(step.action.headers),
|
|
28
|
+
},
|
|
29
|
+
observation: {
|
|
30
|
+
...step.observation,
|
|
31
|
+
headers: redactHeaders(step.observation.headers),
|
|
32
|
+
body: redactText(step.observation.body),
|
|
33
|
+
},
|
|
34
|
+
})),
|
|
35
|
+
summary,
|
|
36
|
+
stepsUsed,
|
|
37
|
+
costSpentUsd,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function redactHeaders(headers) {
|
|
41
|
+
if (!headers)
|
|
42
|
+
return {};
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
45
|
+
if (/authorization|cookie|x-api-key|api-key/i.test(k)) {
|
|
46
|
+
out[k] = '[REDACTED]';
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
out[k] = v;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/attack/report.ts"],"names":[],"mappings":";;AAsBA,gCAMC;AAED,kCA8BC;AA3CD,MAAM,MAAM,GAAG,oDAAoD,CAAC;AACpE,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAC3C,MAAM,QAAQ,GAAG,iDAAiD,CAAC;AACnE,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAE/C,SAAgB,UAAU,CAAC,IAAY;IACnC,OAAO,IAAI;SACN,OAAO,CAAC,SAAS,EAAE,mBAAmB,CAAC;SACvC,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC;SACjC,OAAO,CAAC,QAAQ,EAAE,kBAAkB,CAAC;SACrC,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACpI,CAAC;AAED,SAAgB,WAAW,CACvB,MAAsB,EACtB,QAAwB,EACxB,UAAiC,EACjC,SAAiB,EACjB,YAAoB,EACpB,OAAgB;IAEhB,OAAO;QACH,MAAM;QACN,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,GAAG,CAAC;YACJ,YAAY,EAAE,WAAoB;YAClC,MAAM,EAAE,yEAAyE;SACpF,CAAC,CAAC;QACH,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAClC,MAAM,EAAE;gBACJ,GAAG,IAAI,CAAC,MAAM;gBACd,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;aAC9C;YACD,WAAW,EAAE;gBACT,GAAG,IAAI,CAAC,WAAW;gBACnB,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;gBAChD,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;aAC1C;SACJ,CAAC,CAAC;QACH,OAAO;QACP,SAAS;QACT,YAAY;KACf,CAAC;AACN,CAAC;AAED,SAAS,aAAa,CAAC,OAAgC;IACnD,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,IAAI,yCAAyC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC;QAC1B,CAAC;aAAM,CAAC;YACJ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface StoredCredentials {
|
|
2
|
+
apiToken: string;
|
|
3
|
+
apiUrl: string;
|
|
4
|
+
storedAt: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class CredentialStore {
|
|
7
|
+
static get(): StoredCredentials | null;
|
|
8
|
+
static save(credentials: StoredCredentials): {
|
|
9
|
+
method: string;
|
|
10
|
+
warning?: string;
|
|
11
|
+
};
|
|
12
|
+
static clear(): boolean;
|
|
13
|
+
static getOrThrow(): StoredCredentials;
|
|
14
|
+
private static saveMetadata;
|
|
15
|
+
static getMetadata(): {
|
|
16
|
+
apiUrl: string;
|
|
17
|
+
storedAt: string;
|
|
18
|
+
method: string;
|
|
19
|
+
} | null;
|
|
20
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CredentialStore = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const keychain_1 = require("./keychain");
|
|
41
|
+
const CRED_DIR = path.join(os.homedir(), '.securecode');
|
|
42
|
+
const CRED_FILE = path.join(CRED_DIR, 'credentials.json');
|
|
43
|
+
const DEFAULT_API_URL = 'https://api.usesecurecode.tech';
|
|
44
|
+
class CredentialStore {
|
|
45
|
+
static get() {
|
|
46
|
+
const envToken = process.env.SECURECODE_API_TOKEN;
|
|
47
|
+
const envUrl = process.env.SECURECODE_API_URL || DEFAULT_API_URL;
|
|
48
|
+
if (envToken) {
|
|
49
|
+
return { apiToken: envToken, apiUrl: envUrl, storedAt: 'env' };
|
|
50
|
+
}
|
|
51
|
+
const token = keychain_1.Keychain.get();
|
|
52
|
+
if (token) {
|
|
53
|
+
return {
|
|
54
|
+
apiToken: token,
|
|
55
|
+
apiUrl: DEFAULT_API_URL,
|
|
56
|
+
storedAt: 'keychain',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
if (!fs.existsSync(CRED_FILE))
|
|
61
|
+
return null;
|
|
62
|
+
const stat = fs.statSync(CRED_FILE);
|
|
63
|
+
if (stat.mode & 0o077) {
|
|
64
|
+
console.error(`[securecode] Warning: ${CRED_FILE} is group/world accessible. Run: chmod 600 ${CRED_FILE}`);
|
|
65
|
+
}
|
|
66
|
+
const raw = fs.readFileSync(CRED_FILE, 'utf8');
|
|
67
|
+
const parsed = JSON.parse(raw);
|
|
68
|
+
if (!parsed.apiToken || !parsed.apiUrl)
|
|
69
|
+
return null;
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
static save(credentials) {
|
|
77
|
+
const kcResult = keychain_1.Keychain.set(credentials.apiToken);
|
|
78
|
+
if (kcResult.success) {
|
|
79
|
+
this.saveMetadata(credentials);
|
|
80
|
+
return { method: 'keychain' };
|
|
81
|
+
}
|
|
82
|
+
if (!fs.existsSync(CRED_DIR)) {
|
|
83
|
+
fs.mkdirSync(CRED_DIR, { recursive: true, mode: 0o700 });
|
|
84
|
+
}
|
|
85
|
+
fs.writeFileSync(CRED_FILE, JSON.stringify(credentials, null, 2), { mode: 0o600 });
|
|
86
|
+
return {
|
|
87
|
+
method: 'file',
|
|
88
|
+
warning: kcResult.error
|
|
89
|
+
? `OS keychain unavailable (${kcResult.error}). Credentials stored in ${CRED_FILE} (mode 0600).`
|
|
90
|
+
: undefined,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
static clear() {
|
|
94
|
+
let removed = keychain_1.Keychain.delete();
|
|
95
|
+
try {
|
|
96
|
+
if (fs.existsSync(CRED_FILE)) {
|
|
97
|
+
fs.unlinkSync(CRED_FILE);
|
|
98
|
+
removed = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// best effort
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const metaFile = path.join(CRED_DIR, 'metadata.json');
|
|
106
|
+
if (fs.existsSync(metaFile)) {
|
|
107
|
+
fs.unlinkSync(metaFile);
|
|
108
|
+
removed = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// best effort
|
|
113
|
+
}
|
|
114
|
+
return removed;
|
|
115
|
+
}
|
|
116
|
+
static getOrThrow() {
|
|
117
|
+
const creds = CredentialStore.get();
|
|
118
|
+
if (!creds) {
|
|
119
|
+
throw new Error('Not authenticated. Run `securecode-mcp login` or set SECURECODE_API_TOKEN environment variable.');
|
|
120
|
+
}
|
|
121
|
+
return creds;
|
|
122
|
+
}
|
|
123
|
+
static saveMetadata(credentials) {
|
|
124
|
+
if (!fs.existsSync(CRED_DIR)) {
|
|
125
|
+
fs.mkdirSync(CRED_DIR, { recursive: true, mode: 0o700 });
|
|
126
|
+
}
|
|
127
|
+
const metaFile = path.join(CRED_DIR, 'metadata.json');
|
|
128
|
+
const metadata = {
|
|
129
|
+
apiUrl: credentials.apiUrl,
|
|
130
|
+
storedAt: credentials.storedAt,
|
|
131
|
+
method: 'keychain',
|
|
132
|
+
};
|
|
133
|
+
fs.writeFileSync(metaFile, JSON.stringify(metadata, null, 2), { mode: 0o600 });
|
|
134
|
+
}
|
|
135
|
+
static getMetadata() {
|
|
136
|
+
const metaFile = path.join(CRED_DIR, 'metadata.json');
|
|
137
|
+
try {
|
|
138
|
+
if (!fs.existsSync(metaFile))
|
|
139
|
+
return null;
|
|
140
|
+
return JSON.parse(fs.readFileSync(metaFile, 'utf8'));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.CredentialStore = CredentialStore;
|
|
148
|
+
//# sourceMappingURL=credentialStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentialStore.js","sourceRoot":"","sources":["../../src/auth/credentialStore.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AACzB,yCAAsC;AAEtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AACxD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AAQ1D,MAAM,eAAe,GAAG,gCAAgC,CAAC;AAEzD,MAAa,eAAe;IACxB,MAAM,CAAC,GAAG;QACN,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,eAAe,CAAC;QACjE,IAAI,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACnE,CAAC;QAED,MAAM,KAAK,GAAG,mBAAQ,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,KAAK,EAAE,CAAC;YACR,OAAO;gBACH,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,eAAe;gBACvB,QAAQ,EAAE,UAAU;aACvB,CAAC;QACN,CAAC;QAED,IAAI,CAAC;YACD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC3C,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,IAAI,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,yBAAyB,SAAS,8CAA8C,SAAS,EAAE,CAAC,CAAC;YAC/G,CAAC;YACD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;YACpD,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACpD,OAAO,MAAM,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,WAA8B;QACtC,MAAM,QAAQ,GAAG,mBAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACpD,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACnB,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YAC/B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAClC,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACnF,OAAO;YACH,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,QAAQ,CAAC,KAAK;gBACnB,CAAC,CAAC,4BAA4B,QAAQ,CAAC,KAAK,4BAA4B,SAAS,eAAe;gBAChG,CAAC,CAAC,SAAS;SAClB,CAAC;IACN,CAAC;IAED,MAAM,CAAC,KAAK;QACR,IAAI,OAAO,GAAG,mBAAQ,CAAC,MAAM,EAAE,CAAC;QAChC,IAAI,CAAC;YACD,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3B,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;gBACzB,OAAO,GAAG,IAAI,CAAC;YACnB,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,cAAc;QAClB,CAAC;QACD,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;YACtD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,GAAG,IAAI,CAAC;YACnB,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,cAAc;QAClB,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,UAAU;QACb,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACX,iGAAiG,CACpG,CAAC;QACN,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,MAAM,CAAC,YAAY,CAAC,WAA8B;QACtD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG;YACb,MAAM,EAAE,WAAW,CAAC,MAAM;YAC1B,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,MAAM,EAAE,UAAU;SACrB,CAAC;QACF,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,CAAC,WAAW;QACd,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACtD,IAAI,CAAC;YACD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;CACJ;AAzGD,0CAyGC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type Platform = 'darwin' | 'win32' | 'linux';
|
|
2
|
+
export interface KeychainResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
method: 'keychain' | 'file';
|
|
5
|
+
platform: Platform;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class Keychain {
|
|
9
|
+
static isAvailable(): boolean;
|
|
10
|
+
static get(): string | null;
|
|
11
|
+
static set(token: string): KeychainResult;
|
|
12
|
+
static delete(): boolean;
|
|
13
|
+
static getPlatform(): Platform;
|
|
14
|
+
}
|