@askalf/dario 1.0.3 → 1.0.5
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/proxy.js +14 -19
- package/package.json +1 -1
package/dist/proxy.js
CHANGED
|
@@ -12,7 +12,6 @@ import { getAccessToken, getStatus } from './oauth.js';
|
|
|
12
12
|
const ANTHROPIC_API = 'https://api.anthropic.com';
|
|
13
13
|
const DEFAULT_PORT = 3456;
|
|
14
14
|
const MAX_BODY_BYTES = 10 * 1024 * 1024; // 10 MB — generous for large prompts, prevents abuse
|
|
15
|
-
const ALLOWED_PATH_PREFIX = '/v1/'; // Only proxy Anthropic API paths
|
|
16
15
|
const LOCALHOST = '127.0.0.1';
|
|
17
16
|
const CORS_ORIGIN = 'http://localhost';
|
|
18
17
|
function sanitizeError(err) {
|
|
@@ -62,14 +61,20 @@ export async function startProxy(opts = {}) {
|
|
|
62
61
|
res.end(JSON.stringify(s));
|
|
63
62
|
return;
|
|
64
63
|
}
|
|
65
|
-
//
|
|
66
|
-
const
|
|
67
|
-
|
|
64
|
+
// Allowlisted API paths — only these are proxied (prevents SSRF)
|
|
65
|
+
const rawPath = req.url?.split('?')[0] ?? '';
|
|
66
|
+
const allowedPaths = {
|
|
67
|
+
'/v1/messages': `${ANTHROPIC_API}/v1/messages`,
|
|
68
|
+
'/v1/models': `${ANTHROPIC_API}/v1/models`,
|
|
69
|
+
'/v1/complete': `${ANTHROPIC_API}/v1/complete`,
|
|
70
|
+
};
|
|
71
|
+
const targetBase = allowedPaths[rawPath];
|
|
72
|
+
if (!targetBase) {
|
|
68
73
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
69
|
-
res.end(JSON.stringify({ error: 'Forbidden', message:
|
|
74
|
+
res.end(JSON.stringify({ error: 'Forbidden', message: 'Path not allowed' }));
|
|
70
75
|
return;
|
|
71
76
|
}
|
|
72
|
-
// Only allow POST (Messages API) and GET (models
|
|
77
|
+
// Only allow POST (Messages API) and GET (models)
|
|
73
78
|
if (req.method !== 'POST' && req.method !== 'GET') {
|
|
74
79
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
|
75
80
|
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
@@ -96,18 +101,8 @@ export async function startProxy(opts = {}) {
|
|
|
96
101
|
if (verbose) {
|
|
97
102
|
console.log(`[dario] #${requestCount} ${req.method} ${req.url}`);
|
|
98
103
|
}
|
|
99
|
-
//
|
|
100
|
-
const targetUrl =
|
|
101
|
-
// Preserve query string from original request
|
|
102
|
-
const queryString = req.url?.includes('?') ? req.url.split('?')[1] : '';
|
|
103
|
-
if (queryString)
|
|
104
|
-
targetUrl.search = queryString;
|
|
105
|
-
// Verify the constructed URL still points to Anthropic (defense in depth)
|
|
106
|
-
if (targetUrl.origin !== ANTHROPIC_API) {
|
|
107
|
-
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
108
|
-
res.end(JSON.stringify({ error: 'Forbidden' }));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
104
|
+
// Build target URL from allowlist (no user input in URL construction)
|
|
105
|
+
const targetUrl = targetBase;
|
|
111
106
|
// Merge any client-provided beta flags with the required oauth flag
|
|
112
107
|
const clientBeta = req.headers['anthropic-beta'];
|
|
113
108
|
const betaFlags = new Set(['oauth-2025-04-20']);
|
|
@@ -125,7 +120,7 @@ export async function startProxy(opts = {}) {
|
|
|
125
120
|
'anthropic-beta': [...betaFlags].join(','),
|
|
126
121
|
'x-app': 'cli',
|
|
127
122
|
};
|
|
128
|
-
const upstream = await fetch(targetUrl
|
|
123
|
+
const upstream = await fetch(targetUrl, {
|
|
129
124
|
method: req.method ?? 'POST',
|
|
130
125
|
headers,
|
|
131
126
|
body: body.length > 0 ? body : undefined,
|