mcp4openapi 0.3.1 → 0.3.4
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 +7 -0
- package/dist/src/auth/oauth-provider.d.ts +1 -0
- package/dist/src/auth/oauth-provider.d.ts.map +1 -1
- package/dist/src/auth/oauth-provider.js +17 -0
- package/dist/src/auth/oauth-provider.js.map +1 -1
- package/dist/src/core/cli-config.d.ts.map +1 -1
- package/dist/src/core/cli-config.js +2 -0
- package/dist/src/core/cli-config.js.map +1 -1
- package/dist/src/core/index.d.ts.map +1 -1
- package/dist/src/core/index.js +18 -3
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/index.js +0 -0
- package/dist/src/profile/profile-allowlist.d.ts +18 -0
- package/dist/src/profile/profile-allowlist.d.ts.map +1 -0
- package/dist/src/profile/profile-allowlist.js +68 -0
- package/dist/src/profile/profile-allowlist.js.map +1 -0
- package/dist/src/profile/profile-registry.d.ts +5 -0
- package/dist/src/profile/profile-registry.d.ts.map +1 -1
- package/dist/src/profile/profile-registry.js +38 -14
- package/dist/src/profile/profile-registry.js.map +1 -1
- package/dist/src/security/ssrf-validator.d.ts +31 -0
- package/dist/src/security/ssrf-validator.d.ts.map +1 -0
- package/dist/src/security/ssrf-validator.js +190 -0
- package/dist/src/security/ssrf-validator.js.map +1 -0
- package/package.json +2 -2
- package/profiles/gitlab/developer-profile-oauth.json +445 -81
- package/profiles/gitlab/developer-profile-oauth.test.json +1037 -12
- package/profiles/gitlab/openapi.yaml +1420 -165
- package/profiles/gitlab/profile-optimized-oauth.json +928 -0
- package/profiles/gitlab/profile-optimized-oauth.test.json +1606 -0
- package/profiles/grafana/openapi.json +28078 -0
- package/profiles/grafana/profile.json +1083 -0
- package/profiles/grafana/profile.test.json +235 -0
- package/profiles/mattermost/openapi.yaml +27434 -0
- package/profiles/mattermost/profile.json +463 -0
- package/profiles/mattermost/profile.test.json +607 -0
- package/profiles/n8n/profile-optimized.json +1002 -364
- package/profiles/n8n/profile-optimized.test.json +43 -43
- package/dist/src/argument-normalizer.d.ts +0 -5
- package/dist/src/argument-normalizer.d.ts.map +0 -1
- package/dist/src/argument-normalizer.js +0 -61
- package/dist/src/argument-normalizer.js.map +0 -1
- package/dist/src/cli-config.d.ts +0 -9
- package/dist/src/cli-config.d.ts.map +0 -1
- package/dist/src/cli-config.js +0 -111
- package/dist/src/cli-config.js.map +0 -1
- package/dist/src/composite-executor.d.ts +0 -77
- package/dist/src/composite-executor.d.ts.map +0 -1
- package/dist/src/composite-executor.js +0 -193
- package/dist/src/composite-executor.js.map +0 -1
- package/dist/src/constants.d.ts +0 -85
- package/dist/src/constants.d.ts.map +0 -1
- package/dist/src/constants.js +0 -85
- package/dist/src/constants.js.map +0 -1
- package/dist/src/dag-executor.d.ts +0 -49
- package/dist/src/dag-executor.d.ts.map +0 -1
- package/dist/src/dag-executor.js +0 -138
- package/dist/src/dag-executor.js.map +0 -1
- package/dist/src/errors.d.ts +0 -59
- package/dist/src/errors.d.ts.map +0 -1
- package/dist/src/errors.js +0 -119
- package/dist/src/errors.js.map +0 -1
- package/dist/src/filtering.d.ts +0 -19
- package/dist/src/filtering.d.ts.map +0 -1
- package/dist/src/filtering.js +0 -292
- package/dist/src/filtering.js.map +0 -1
- package/dist/src/http-client-factory.d.ts +0 -62
- package/dist/src/http-client-factory.d.ts.map +0 -1
- package/dist/src/http-client-factory.js +0 -133
- package/dist/src/http-client-factory.js.map +0 -1
- package/dist/src/http-transport-config.d.ts +0 -6
- package/dist/src/http-transport-config.d.ts.map +0 -1
- package/dist/src/http-transport-config.js +0 -47
- package/dist/src/http-transport-config.js.map +0 -1
- package/dist/src/http-transport.d.ts +0 -316
- package/dist/src/http-transport.d.ts.map +0 -1
- package/dist/src/http-transport.js +0 -2412
- package/dist/src/http-transport.js.map +0 -1
- package/dist/src/interceptors.d.ts +0 -116
- package/dist/src/interceptors.d.ts.map +0 -1
- package/dist/src/interceptors.js +0 -392
- package/dist/src/interceptors.js.map +0 -1
- package/dist/src/jsonrpc-validator.d.ts +0 -27
- package/dist/src/jsonrpc-validator.d.ts.map +0 -1
- package/dist/src/jsonrpc-validator.js +0 -58
- package/dist/src/jsonrpc-validator.js.map +0 -1
- package/dist/src/logger.d.ts +0 -59
- package/dist/src/logger.d.ts.map +0 -1
- package/dist/src/logger.js +0 -177
- package/dist/src/logger.js.map +0 -1
- package/dist/src/mcp-server-manager.d.ts +0 -20
- package/dist/src/mcp-server-manager.d.ts.map +0 -1
- package/dist/src/mcp-server-manager.js +0 -38
- package/dist/src/mcp-server-manager.js.map +0 -1
- package/dist/src/mcp-server.d.ts +0 -203
- package/dist/src/mcp-server.d.ts.map +0 -1
- package/dist/src/mcp-server.js +0 -1369
- package/dist/src/mcp-server.js.map +0 -1
- package/dist/src/metrics.d.ts +0 -97
- package/dist/src/metrics.d.ts.map +0 -1
- package/dist/src/metrics.js +0 -273
- package/dist/src/metrics.js.map +0 -1
- package/dist/src/naming-warnings.d.ts +0 -23
- package/dist/src/naming-warnings.d.ts.map +0 -1
- package/dist/src/naming-warnings.js +0 -83
- package/dist/src/naming-warnings.js.map +0 -1
- package/dist/src/naming.d.ts +0 -58
- package/dist/src/naming.d.ts.map +0 -1
- package/dist/src/naming.js +0 -510
- package/dist/src/naming.js.map +0 -1
- package/dist/src/oauth-provider.d.ts +0 -131
- package/dist/src/oauth-provider.d.ts.map +0 -1
- package/dist/src/oauth-provider.js +0 -836
- package/dist/src/oauth-provider.js.map +0 -1
- package/dist/src/openapi-parser.d.ts +0 -70
- package/dist/src/openapi-parser.d.ts.map +0 -1
- package/dist/src/openapi-parser.js +0 -436
- package/dist/src/openapi-parser.js.map +0 -1
- package/dist/src/profile-loader.d.ts +0 -78
- package/dist/src/profile-loader.d.ts.map +0 -1
- package/dist/src/profile-loader.js +0 -483
- package/dist/src/profile-loader.js.map +0 -1
- package/dist/src/profile-registry.d.ts +0 -18
- package/dist/src/profile-registry.d.ts.map +0 -1
- package/dist/src/profile-registry.js +0 -26
- package/dist/src/profile-registry.js.map +0 -1
- package/dist/src/profile-resolver.d.ts +0 -19
- package/dist/src/profile-resolver.d.ts.map +0 -1
- package/dist/src/profile-resolver.js +0 -167
- package/dist/src/profile-resolver.js.map +0 -1
- package/dist/src/proxy-executor.d.ts +0 -86
- package/dist/src/proxy-executor.d.ts.map +0 -1
- package/dist/src/proxy-executor.js +0 -497
- package/dist/src/proxy-executor.js.map +0 -1
- package/dist/src/schema-validator.d.ts +0 -30
- package/dist/src/schema-validator.d.ts.map +0 -1
- package/dist/src/schema-validator.js +0 -128
- package/dist/src/schema-validator.js.map +0 -1
- package/dist/src/startup-profile.d.ts +0 -17
- package/dist/src/startup-profile.d.ts.map +0 -1
- package/dist/src/startup-profile.js +0 -30
- package/dist/src/startup-profile.js.map +0 -1
- package/dist/src/startup-validation.d.ts +0 -11
- package/dist/src/startup-validation.d.ts.map +0 -1
- package/dist/src/startup-validation.js +0 -21
- package/dist/src/startup-validation.js.map +0 -1
- package/dist/src/tool-filter.d.ts +0 -65
- package/dist/src/tool-filter.d.ts.map +0 -1
- package/dist/src/tool-filter.js +0 -471
- package/dist/src/tool-filter.js.map +0 -1
- package/dist/src/tool-generator.d.ts +0 -67
- package/dist/src/tool-generator.d.ts.map +0 -1
- package/dist/src/tool-generator.js +0 -182
- package/dist/src/tool-generator.js.map +0 -1
- package/dist/src/validation-utils.d.ts +0 -49
- package/dist/src/validation-utils.d.ts.map +0 -1
- package/dist/src/validation-utils.js +0 -138
- package/dist/src/validation-utils.js.map +0 -1
- package/profiles/gitlab/developer-profile.json +0 -1508
- package/profiles/gitlab/developer-profile.test.json +0 -3432
|
@@ -1,497 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Proxy download executor for fetching binary content through API
|
|
3
|
-
*
|
|
4
|
-
* Why: LLM needs file content but URLs require authentication.
|
|
5
|
-
* This executor fetches metadata, extracts URL, downloads content,
|
|
6
|
-
* and returns base64-encoded result.
|
|
7
|
-
*/
|
|
8
|
-
import { NetworkError, ValidationError } from './errors.js';
|
|
9
|
-
import { isSafePropertyName } from './validation-utils.js';
|
|
10
|
-
import { isIP } from 'node:net';
|
|
11
|
-
import { lookup } from 'node:dns/promises';
|
|
12
|
-
const DEFAULT_MAX_SIZE = 10 * 1024 * 1024; // 10MB
|
|
13
|
-
const DEFAULT_TIMEOUT = 30000; // 30s
|
|
14
|
-
const MAX_REDIRECTS = 5;
|
|
15
|
-
export class ProxyDownloadExecutor {
|
|
16
|
-
constructor(httpClient, logger = { debug: () => { } }) {
|
|
17
|
-
this.httpClient = httpClient;
|
|
18
|
-
this.logger = logger;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Execute proxy download operation
|
|
22
|
-
*
|
|
23
|
-
* @param operation Proxy download configuration
|
|
24
|
-
* @param path API path with substituted parameters
|
|
25
|
-
* @param authCredentials Auth credentials (headers + query params) for download
|
|
26
|
-
*/
|
|
27
|
-
async execute(operation, metadataRequest, authCredentials, directDownloadRequest) {
|
|
28
|
-
const maxSize = this.resolveMaxSize(operation);
|
|
29
|
-
const timeout = operation.timeout_ms ?? DEFAULT_TIMEOUT;
|
|
30
|
-
const urlField = operation.url_field ?? 'url';
|
|
31
|
-
const baseOrigin = this.getBaseOrigin();
|
|
32
|
-
// Step 1: Fetch metadata
|
|
33
|
-
const metadataResponse = await this.httpClient.request(metadataRequest.method, metadataRequest.path);
|
|
34
|
-
const metadata = metadataResponse.body;
|
|
35
|
-
// File metadata helpers
|
|
36
|
-
const fileName = this.extractNestedString(metadata, 'artifacts_file.filename') ||
|
|
37
|
-
metadata['file_name'] ||
|
|
38
|
-
metadata['filename'] ||
|
|
39
|
-
metadata['name'];
|
|
40
|
-
const reportedSize = this.extractNestedNumber(metadata, 'artifacts_file.size') ||
|
|
41
|
-
metadata['size'];
|
|
42
|
-
const metadataMime = metadata['mimeType'] ||
|
|
43
|
-
metadata['content_type'] ||
|
|
44
|
-
'application/octet-stream';
|
|
45
|
-
// Step 2A: Direct download endpoint path (preferred when configured)
|
|
46
|
-
if (directDownloadRequest) {
|
|
47
|
-
const skipAuth = operation.skip_auth ?? false;
|
|
48
|
-
const downloadUrl = this.resolveHttpUrl(directDownloadRequest.path);
|
|
49
|
-
const { content, size, mimeType } = await this.downloadWithAuth(downloadUrl, authCredentials, maxSize, timeout, baseOrigin, skipAuth, directDownloadRequest.method, operation);
|
|
50
|
-
if (reportedSize && reportedSize > maxSize) {
|
|
51
|
-
throw new ValidationError(`File size ${reportedSize} exceeds maximum ${maxSize} bytes`);
|
|
52
|
-
}
|
|
53
|
-
const finalMimeType = mimeType || metadataMime;
|
|
54
|
-
if (operation.allowed_mime_types) {
|
|
55
|
-
if (!this.isMimeTypeAllowed(finalMimeType, operation.allowed_mime_types)) {
|
|
56
|
-
throw new ValidationError(`MIME type '${finalMimeType}' not in whitelist: ${operation.allowed_mime_types.join(', ')}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
metadata,
|
|
61
|
-
content,
|
|
62
|
-
mimeType: finalMimeType,
|
|
63
|
-
size,
|
|
64
|
-
fileName,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
// Step 2: Extract URL from metadata
|
|
68
|
-
const url = this.extractUrl(metadata, urlField);
|
|
69
|
-
if (!url) {
|
|
70
|
-
throw new ValidationError(`URL field '${urlField}' not found in metadata response`);
|
|
71
|
-
}
|
|
72
|
-
// Step 3: Check MIME type whitelist (from metadata if available)
|
|
73
|
-
const mimeType = metadataMime;
|
|
74
|
-
if (operation.allowed_mime_types) {
|
|
75
|
-
if (!this.isMimeTypeAllowed(mimeType, operation.allowed_mime_types)) {
|
|
76
|
-
throw new ValidationError(`MIME type '${mimeType}' not in whitelist: ${operation.allowed_mime_types.join(', ')}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
// Step 4: Check file size (from metadata if available)
|
|
80
|
-
if (reportedSize && reportedSize > maxSize) {
|
|
81
|
-
throw new ValidationError(`File size ${reportedSize} exceeds maximum ${maxSize} bytes`);
|
|
82
|
-
}
|
|
83
|
-
// Step 5: Download binary content (supports HTTP(S) and data URLs)
|
|
84
|
-
if (url.startsWith('data:')) {
|
|
85
|
-
const { content, size, mimeType: inferredMime } = this.downloadFromDataUrl(url, maxSize);
|
|
86
|
-
return {
|
|
87
|
-
metadata,
|
|
88
|
-
content,
|
|
89
|
-
mimeType: inferredMime || mimeType,
|
|
90
|
-
size,
|
|
91
|
-
fileName,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
const skipAuth = operation.skip_auth ?? false;
|
|
95
|
-
const downloadUrl = this.resolveHttpUrl(url);
|
|
96
|
-
const { content, size, mimeType: responseMime } = await this.downloadWithAuth(downloadUrl, authCredentials, maxSize, timeout, baseOrigin, skipAuth, 'GET', operation);
|
|
97
|
-
return {
|
|
98
|
-
metadata,
|
|
99
|
-
content,
|
|
100
|
-
mimeType: responseMime || mimeType,
|
|
101
|
-
size,
|
|
102
|
-
fileName,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
resolveMaxSize(operation) {
|
|
106
|
-
const envKeys = [operation.max_size_bytes_from_env, 'MCP4_PROXY_MAX_BYTES'].filter(Boolean);
|
|
107
|
-
for (const key of envKeys) {
|
|
108
|
-
const rawValue = process.env[key];
|
|
109
|
-
if (rawValue !== undefined) {
|
|
110
|
-
const parsed = Number(rawValue);
|
|
111
|
-
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
112
|
-
throw new ValidationError(`Invalid max size from env ${key}: expected positive integer, got '${rawValue}'`);
|
|
113
|
-
}
|
|
114
|
-
return parsed;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (operation.max_size_bytes !== undefined) {
|
|
118
|
-
return operation.max_size_bytes;
|
|
119
|
-
}
|
|
120
|
-
return DEFAULT_MAX_SIZE;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Extract URL from metadata using dot-notation path
|
|
124
|
-
*/
|
|
125
|
-
extractUrl(metadata, urlField) {
|
|
126
|
-
const parts = urlField.split('.');
|
|
127
|
-
let current = metadata;
|
|
128
|
-
for (const part of parts) {
|
|
129
|
-
if (current === null || typeof current !== 'object') {
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
if (!isSafePropertyName(part)) {
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
current = current[part];
|
|
136
|
-
}
|
|
137
|
-
return typeof current === 'string' ? current : null;
|
|
138
|
-
}
|
|
139
|
-
extractNestedString(metadata, path) {
|
|
140
|
-
const value = this.extractNestedValue(metadata, path);
|
|
141
|
-
return typeof value === 'string' ? value : undefined;
|
|
142
|
-
}
|
|
143
|
-
extractNestedNumber(metadata, path) {
|
|
144
|
-
const value = this.extractNestedValue(metadata, path);
|
|
145
|
-
return typeof value === 'number' ? value : undefined;
|
|
146
|
-
}
|
|
147
|
-
extractNestedValue(metadata, path) {
|
|
148
|
-
const parts = path.split('.');
|
|
149
|
-
let current = metadata;
|
|
150
|
-
for (const part of parts) {
|
|
151
|
-
if (current === null || typeof current !== 'object') {
|
|
152
|
-
return undefined;
|
|
153
|
-
}
|
|
154
|
-
if (!isSafePropertyName(part)) {
|
|
155
|
-
return undefined;
|
|
156
|
-
}
|
|
157
|
-
current = current[part];
|
|
158
|
-
}
|
|
159
|
-
return current;
|
|
160
|
-
}
|
|
161
|
-
getBaseOrigin() {
|
|
162
|
-
try {
|
|
163
|
-
return new URL(this.httpClient.getBaseUrl()).origin;
|
|
164
|
-
}
|
|
165
|
-
catch {
|
|
166
|
-
throw new ValidationError('Invalid API base URL - expected absolute http(s) URL');
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
resolveHttpUrl(input) {
|
|
170
|
-
// Absolute URL
|
|
171
|
-
let absoluteUrl;
|
|
172
|
-
try {
|
|
173
|
-
absoluteUrl = new URL(input);
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
this.logger.debug('resolveHttpUrl: input is not an absolute URL, resolving relative', {
|
|
177
|
-
error: error instanceof Error ? error.message : String(error),
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
if (absoluteUrl) {
|
|
181
|
-
if (absoluteUrl.protocol === 'http:' || absoluteUrl.protocol === 'https:') {
|
|
182
|
-
return absoluteUrl.toString();
|
|
183
|
-
}
|
|
184
|
-
throw new ValidationError(`Unsupported download URL scheme: '${absoluteUrl.protocol}'`);
|
|
185
|
-
}
|
|
186
|
-
const baseUrl = this.httpClient.getBaseUrl();
|
|
187
|
-
let base;
|
|
188
|
-
try {
|
|
189
|
-
base = new URL(baseUrl);
|
|
190
|
-
}
|
|
191
|
-
catch {
|
|
192
|
-
throw new ValidationError('Invalid API base URL - expected absolute http(s) URL');
|
|
193
|
-
}
|
|
194
|
-
if (base.protocol !== 'http:' && base.protocol !== 'https:') {
|
|
195
|
-
throw new ValidationError(`Unsupported API base URL scheme: '${base.protocol}'`);
|
|
196
|
-
}
|
|
197
|
-
try {
|
|
198
|
-
if (input.startsWith('/')) {
|
|
199
|
-
// Preserve base URL path segments (e.g., https://host/api/v4 + /projects -> https://host/api/v4/projects)
|
|
200
|
-
const combined = `${baseUrl.replace(/\/$/, '')}${input}`;
|
|
201
|
-
return new URL(combined).toString();
|
|
202
|
-
}
|
|
203
|
-
// Relative (no leading slash) uses URL resolution semantics
|
|
204
|
-
const baseForRelative = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
205
|
-
return new URL(input, baseForRelative).toString();
|
|
206
|
-
}
|
|
207
|
-
catch {
|
|
208
|
-
throw new ValidationError(`Invalid download URL: '${input}'`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
async enforceDownloadPolicy(downloadUrl, baseOrigin, operation, skipAuth) {
|
|
212
|
-
const downloadOrigin = new URL(downloadUrl).origin;
|
|
213
|
-
if (!skipAuth) {
|
|
214
|
-
if (downloadOrigin !== baseOrigin) {
|
|
215
|
-
throw new ValidationError(`Cross-origin download URL not allowed with authentication (base origin '${baseOrigin}', download origin '${downloadOrigin}'). Set skip_auth=true or use a same-origin download endpoint.`);
|
|
216
|
-
}
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
// With skip_auth, allow same-origin without additional restrictions
|
|
220
|
-
if (downloadOrigin === baseOrigin)
|
|
221
|
-
return;
|
|
222
|
-
await this.enforceAllowedDownloadTarget(downloadUrl, operation);
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Check if MIME type matches whitelist (supports wildcards like 'image/*')
|
|
226
|
-
*/
|
|
227
|
-
isMimeTypeAllowed(mimeType, whitelist) {
|
|
228
|
-
return whitelist.some(pattern => {
|
|
229
|
-
if (pattern.endsWith('/*')) {
|
|
230
|
-
const prefix = pattern.slice(0, -1); // 'image/*' -> 'image/'
|
|
231
|
-
return mimeType.startsWith(prefix);
|
|
232
|
-
}
|
|
233
|
-
return mimeType === pattern;
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Download binary content and return base64
|
|
238
|
-
*
|
|
239
|
-
* @param skipAuth If true, download URL is fetched without authentication headers/params
|
|
240
|
-
* Metadata endpoint still requires auth, only the final download is unauthenticated
|
|
241
|
-
*/
|
|
242
|
-
async downloadWithAuth(url, authCredentials, maxSize, timeout, baseOrigin, skipAuth = false, method = 'GET', operation) {
|
|
243
|
-
const controller = new AbortController();
|
|
244
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
245
|
-
try {
|
|
246
|
-
const initialUrl = this.buildDownloadUrlWithOptionalQueryAuth(url, authCredentials, skipAuth);
|
|
247
|
-
let currentUrl = initialUrl;
|
|
248
|
-
let currentMethod = method;
|
|
249
|
-
let currentHeaders = skipAuth ? {} : authCredentials.headers;
|
|
250
|
-
if (operation) {
|
|
251
|
-
await this.enforceDownloadPolicy(currentUrl, baseOrigin, operation, skipAuth);
|
|
252
|
-
}
|
|
253
|
-
for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects++) {
|
|
254
|
-
const response = await fetch(currentUrl, {
|
|
255
|
-
method: currentMethod,
|
|
256
|
-
headers: currentHeaders,
|
|
257
|
-
signal: controller.signal,
|
|
258
|
-
redirect: 'manual',
|
|
259
|
-
});
|
|
260
|
-
if (this.isRedirectStatus(response.status)) {
|
|
261
|
-
if (redirects === MAX_REDIRECTS) {
|
|
262
|
-
throw new NetworkError(`Too many redirects (max ${MAX_REDIRECTS})`);
|
|
263
|
-
}
|
|
264
|
-
const location = response.headers.get('location');
|
|
265
|
-
if (!location) {
|
|
266
|
-
throw new NetworkError(`Redirect without Location header: HTTP ${response.status}`);
|
|
267
|
-
}
|
|
268
|
-
const nextUrl = this.resolveRedirectTarget(currentUrl, location);
|
|
269
|
-
if (operation) {
|
|
270
|
-
// Enforce the same policy on every redirect hop
|
|
271
|
-
await this.enforceDownloadPolicy(nextUrl, baseOrigin, operation, skipAuth);
|
|
272
|
-
}
|
|
273
|
-
const isCrossOrigin = new URL(nextUrl).origin !== new URL(currentUrl).origin;
|
|
274
|
-
if (isCrossOrigin) {
|
|
275
|
-
currentHeaders = {};
|
|
276
|
-
}
|
|
277
|
-
if (response.status === 303 ||
|
|
278
|
-
((response.status === 301 || response.status === 302) &&
|
|
279
|
-
currentMethod !== 'GET' &&
|
|
280
|
-
currentMethod !== 'HEAD')) {
|
|
281
|
-
currentMethod = 'GET';
|
|
282
|
-
}
|
|
283
|
-
currentUrl = nextUrl;
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
if (!response.ok) {
|
|
287
|
-
throw new NetworkError(`Download failed: HTTP ${response.status}`, response.status);
|
|
288
|
-
}
|
|
289
|
-
// Check content-length header
|
|
290
|
-
const contentLength = response.headers.get('content-length');
|
|
291
|
-
if (contentLength && parseInt(contentLength, 10) > maxSize) {
|
|
292
|
-
throw new ValidationError(`File size ${contentLength} exceeds maximum ${maxSize} bytes`);
|
|
293
|
-
}
|
|
294
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
295
|
-
// Final size check
|
|
296
|
-
if (arrayBuffer.byteLength > maxSize) {
|
|
297
|
-
throw new ValidationError(`Downloaded file size ${arrayBuffer.byteLength} exceeds maximum ${maxSize} bytes`);
|
|
298
|
-
}
|
|
299
|
-
// Convert to base64
|
|
300
|
-
const content = Buffer.from(arrayBuffer).toString('base64');
|
|
301
|
-
return {
|
|
302
|
-
content,
|
|
303
|
-
size: arrayBuffer.byteLength,
|
|
304
|
-
mimeType: response.headers.get('content-type') || undefined,
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
throw new NetworkError('Download failed: unexpected redirect handling state');
|
|
308
|
-
}
|
|
309
|
-
finally {
|
|
310
|
-
clearTimeout(timeoutId);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
buildDownloadUrlWithOptionalQueryAuth(url, authCredentials, skipAuth) {
|
|
314
|
-
if (skipAuth || !authCredentials.queryParams)
|
|
315
|
-
return url;
|
|
316
|
-
const urlObj = new URL(url);
|
|
317
|
-
const { key, value } = authCredentials.queryParams;
|
|
318
|
-
// Only add if not already present (URL may have pre-signed token)
|
|
319
|
-
if (!urlObj.searchParams.has(key)) {
|
|
320
|
-
urlObj.searchParams.set(key, value);
|
|
321
|
-
}
|
|
322
|
-
return urlObj.toString();
|
|
323
|
-
}
|
|
324
|
-
isRedirectStatus(status) {
|
|
325
|
-
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
326
|
-
}
|
|
327
|
-
resolveRedirectTarget(currentUrl, location) {
|
|
328
|
-
let resolved;
|
|
329
|
-
try {
|
|
330
|
-
resolved = new URL(location, currentUrl);
|
|
331
|
-
}
|
|
332
|
-
catch {
|
|
333
|
-
throw new NetworkError(`Invalid redirect URL: '${location}'`);
|
|
334
|
-
}
|
|
335
|
-
if (resolved.protocol !== 'http:' && resolved.protocol !== 'https:') {
|
|
336
|
-
throw new ValidationError(`Unsupported redirect URL scheme: '${resolved.protocol}'`);
|
|
337
|
-
}
|
|
338
|
-
return resolved.toString();
|
|
339
|
-
}
|
|
340
|
-
async enforceAllowedDownloadTarget(targetUrl, operation) {
|
|
341
|
-
const url = new URL(targetUrl);
|
|
342
|
-
const hostnameRaw = url.hostname.toLowerCase();
|
|
343
|
-
const hostname = hostnameRaw.startsWith('[') && hostnameRaw.endsWith(']')
|
|
344
|
-
? hostnameRaw.slice(1, -1)
|
|
345
|
-
: hostnameRaw;
|
|
346
|
-
const allowPrivateNetwork = operation.allow_private_network ?? false;
|
|
347
|
-
if (operation.allowed_hosts && operation.allowed_hosts.length > 0) {
|
|
348
|
-
if (!this.isAllowedHost(hostname, operation.allowed_hosts)) {
|
|
349
|
-
this.logger.warn?.('proxy_download blocked: host not in allowlist', {
|
|
350
|
-
hostname,
|
|
351
|
-
allowed_hosts: operation.allowed_hosts,
|
|
352
|
-
how_to_fix: "Add hostname to allowed_hosts, or use same-origin download endpoint.",
|
|
353
|
-
});
|
|
354
|
-
throw new ValidationError(`Download host not in allowlist: '${hostname}' (allowed_hosts: ${operation.allowed_hosts.join(', ')})`);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
if (allowPrivateNetwork)
|
|
358
|
-
return;
|
|
359
|
-
if (hostname === 'localhost') {
|
|
360
|
-
this.logger.warn?.('proxy_download blocked: localhost target', {
|
|
361
|
-
hostname,
|
|
362
|
-
how_to_fix: "If you really need localhost, set allow_private_network=true (and consider allowed_hosts).",
|
|
363
|
-
});
|
|
364
|
-
throw new ValidationError('Download hostname not allowed');
|
|
365
|
-
}
|
|
366
|
-
const ipVersion = isIP(hostname);
|
|
367
|
-
if (ipVersion === 4) {
|
|
368
|
-
if (this.isDisallowedIPv4(hostname)) {
|
|
369
|
-
this.logger.warn?.('proxy_download blocked: private/loopback/link-local IPv4 target', {
|
|
370
|
-
hostname,
|
|
371
|
-
how_to_fix: "If you really need private IPs, set allow_private_network=true (and consider allowed_hosts).",
|
|
372
|
-
});
|
|
373
|
-
throw new ValidationError('Download IP not allowed');
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
else if (ipVersion === 6) {
|
|
377
|
-
if (this.isDisallowedIPv6(hostname)) {
|
|
378
|
-
this.logger.warn?.('proxy_download blocked: private/loopback/link-local IPv6 target', {
|
|
379
|
-
hostname,
|
|
380
|
-
how_to_fix: "If you really need private IPs, set allow_private_network=true (and consider allowed_hosts).",
|
|
381
|
-
});
|
|
382
|
-
throw new ValidationError('Download IP not allowed');
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
else {
|
|
386
|
-
// Hostname: resolve to all IPs and block if any are private/loopback/link-local (SSRF defense)
|
|
387
|
-
const addresses = await this.lookupAllIpAddresses(hostname);
|
|
388
|
-
const disallowed = addresses.find(address => {
|
|
389
|
-
const family = isIP(address);
|
|
390
|
-
if (family === 4)
|
|
391
|
-
return this.isDisallowedIPv4(address);
|
|
392
|
-
if (family === 6)
|
|
393
|
-
return this.isDisallowedIPv6(address);
|
|
394
|
-
return false;
|
|
395
|
-
});
|
|
396
|
-
if (disallowed) {
|
|
397
|
-
this.logger.warn?.('proxy_download blocked: hostname resolves to private/loopback/link-local IP', {
|
|
398
|
-
hostname,
|
|
399
|
-
resolved_addresses: addresses,
|
|
400
|
-
how_to_fix: "If this hostname must be allowed, set allow_private_network=true and restrict with allowed_hosts.",
|
|
401
|
-
});
|
|
402
|
-
throw new ValidationError('Download hostname resolves to disallowed IP');
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
async lookupAllIpAddresses(hostname) {
|
|
407
|
-
const timeoutMs = 1000;
|
|
408
|
-
let results = [];
|
|
409
|
-
try {
|
|
410
|
-
results = (await Promise.race([
|
|
411
|
-
lookup(hostname, { all: true, verbatim: true }),
|
|
412
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error(`DNS lookup timeout after ${timeoutMs}ms`)), timeoutMs)),
|
|
413
|
-
]));
|
|
414
|
-
}
|
|
415
|
-
catch (error) {
|
|
416
|
-
this.logger.warn?.('proxy_download blocked: DNS lookup failed', {
|
|
417
|
-
hostname,
|
|
418
|
-
error: error instanceof Error ? error.message : String(error),
|
|
419
|
-
how_to_fix: "If you need to allow internal hostnames, set allow_private_network=true and restrict with allowed_hosts.",
|
|
420
|
-
});
|
|
421
|
-
throw new ValidationError(`DNS lookup failed for hostname '${hostname}'`);
|
|
422
|
-
}
|
|
423
|
-
const addresses = results.map(r => r.address).filter(Boolean);
|
|
424
|
-
if (addresses.length === 0) {
|
|
425
|
-
this.logger.warn?.('proxy_download blocked: DNS lookup returned no addresses', {
|
|
426
|
-
hostname,
|
|
427
|
-
how_to_fix: "If you need to allow internal hostnames, set allow_private_network=true and restrict with allowed_hosts.",
|
|
428
|
-
});
|
|
429
|
-
throw new ValidationError(`DNS lookup returned no addresses for hostname '${hostname}'`);
|
|
430
|
-
}
|
|
431
|
-
return addresses;
|
|
432
|
-
}
|
|
433
|
-
isAllowedHost(hostname, allowedHosts) {
|
|
434
|
-
const lower = hostname.toLowerCase();
|
|
435
|
-
return allowedHosts.some(patternRaw => {
|
|
436
|
-
const pattern = patternRaw.toLowerCase().trim();
|
|
437
|
-
if (!pattern)
|
|
438
|
-
return false;
|
|
439
|
-
if (pattern.startsWith('*.')) {
|
|
440
|
-
const suffix = pattern.slice(2);
|
|
441
|
-
if (!suffix)
|
|
442
|
-
return false;
|
|
443
|
-
return lower.endsWith(`.${suffix}`);
|
|
444
|
-
}
|
|
445
|
-
return lower === pattern;
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
isDisallowedIPv4(ip) {
|
|
449
|
-
const parts = ip.split('.').map(p => Number(p));
|
|
450
|
-
if (parts.length !== 4 || parts.some(p => !Number.isInteger(p) || p < 0 || p > 255))
|
|
451
|
-
return true;
|
|
452
|
-
const [a, b] = parts;
|
|
453
|
-
if (a === 127)
|
|
454
|
-
return true; // loopback
|
|
455
|
-
if (a === 10)
|
|
456
|
-
return true; // private
|
|
457
|
-
if (a === 172 && b >= 16 && b <= 31)
|
|
458
|
-
return true; // private
|
|
459
|
-
if (a === 192 && b === 168)
|
|
460
|
-
return true; // private
|
|
461
|
-
if (a === 169 && b === 254)
|
|
462
|
-
return true; // link-local
|
|
463
|
-
if (a === 0)
|
|
464
|
-
return true; // "this network"
|
|
465
|
-
return false;
|
|
466
|
-
}
|
|
467
|
-
isDisallowedIPv6(ip) {
|
|
468
|
-
const normalized = ip.toLowerCase();
|
|
469
|
-
if (normalized === '::1' || normalized === '0:0:0:0:0:0:0:1')
|
|
470
|
-
return true; // loopback
|
|
471
|
-
if (normalized === '::' || normalized === '0:0:0:0:0:0:0:0')
|
|
472
|
-
return true; // unspecified
|
|
473
|
-
if (normalized.startsWith('fe8') || normalized.startsWith('fe9') || normalized.startsWith('fea') || normalized.startsWith('feb')) {
|
|
474
|
-
return true; // link-local fe80::/10 (approx by prefix)
|
|
475
|
-
}
|
|
476
|
-
if (normalized.startsWith('fc') || normalized.startsWith('fd'))
|
|
477
|
-
return true; // unique local fc00::/7 (approx by prefix)
|
|
478
|
-
return false;
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Handle inline data URLs (data:mime;base64,...)
|
|
482
|
-
*/
|
|
483
|
-
downloadFromDataUrl(url, maxSize) {
|
|
484
|
-
const match = url.match(/^data:(.*?);base64,(.*)$/);
|
|
485
|
-
if (!match) {
|
|
486
|
-
throw new ValidationError(`Unsupported data URL format`);
|
|
487
|
-
}
|
|
488
|
-
const mimeType = match[1] || 'application/octet-stream';
|
|
489
|
-
const base64Data = match[2];
|
|
490
|
-
const size = Buffer.from(base64Data, 'base64').length;
|
|
491
|
-
if (size > maxSize) {
|
|
492
|
-
throw new ValidationError(`Downloaded file size ${size} exceeds maximum ${maxSize} bytes`);
|
|
493
|
-
}
|
|
494
|
-
return { content: base64Data, size, mimeType };
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
//# sourceMappingURL=proxy-executor.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"proxy-executor.js","sourceRoot":"","sources":["../../src/proxy-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request body schema validator
|
|
3
|
-
*
|
|
4
|
-
* Why: Catch invalid requests before sending to API. Better error messages for users.
|
|
5
|
-
* Validates against OpenAPI schema definitions.
|
|
6
|
-
*/
|
|
7
|
-
import type { SchemaInfo, OperationInfo } from './types/openapi.js';
|
|
8
|
-
export interface ValidationResult {
|
|
9
|
-
valid: boolean;
|
|
10
|
-
errors?: ValidationError[];
|
|
11
|
-
}
|
|
12
|
-
export interface ValidationError {
|
|
13
|
-
path: string;
|
|
14
|
-
message: string;
|
|
15
|
-
schema: SchemaInfo;
|
|
16
|
-
value: unknown;
|
|
17
|
-
}
|
|
18
|
-
export declare class SchemaValidator {
|
|
19
|
-
/**
|
|
20
|
-
* Validate request body against OpenAPI schema
|
|
21
|
-
*
|
|
22
|
-
* Why: Prevents sending malformed requests. OpenAPI schema is the source of truth.
|
|
23
|
-
*/
|
|
24
|
-
validateRequestBody(operation: OperationInfo, body: Record<string, unknown>): ValidationResult;
|
|
25
|
-
/**
|
|
26
|
-
* Recursively validate data against schema
|
|
27
|
-
*/
|
|
28
|
-
private validateAgainstSchema;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=schema-validator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-validator.d.ts","sourceRoot":"","sources":["../../src/schema-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGpE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,qBAAa,eAAe;IAC1B;;;;OAIG;IACH,mBAAmB,CACjB,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,gBAAgB;IAgBnB;;OAEG;IACH,OAAO,CAAC,qBAAqB;CA2H9B"}
|