@askalf/dario 1.0.1 → 1.0.3

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 CHANGED
@@ -146,7 +146,7 @@ curl http://localhost:3456/v1/messages \
146
146
  -H "Content-Type: application/json" \
147
147
  -H "anthropic-version: 2023-06-01" \
148
148
  -d '{
149
- "model": "claude-sonnet-4-6",
149
+ "model": "claude-opus-4-6",
150
150
  "max_tokens": 1024,
151
151
  "stream": true,
152
152
  "messages": [{"role": "user", "content": "Write a haiku about APIs"}]
package/dist/cli.js CHANGED
@@ -152,7 +152,7 @@ async function help() {
152
152
  Example with curl:
153
153
  curl http://localhost:3456/v1/messages \\
154
154
  -H "Content-Type: application/json" \\
155
- -d '{"model":"claude-sonnet-4-6","max_tokens":1024,"messages":[{"role":"user","content":"Hello"}]}'
155
+ -d '{"model":"claude-opus-4-6","max_tokens":1024,"messages":[{"role":"user","content":"Hello"}]}'
156
156
 
157
157
  Your subscription handles the billing. No API key needed.
158
158
  Tokens auto-refresh in the background — set it and forget it.
package/dist/proxy.js CHANGED
@@ -62,9 +62,9 @@ export async function startProxy(opts = {}) {
62
62
  res.end(JSON.stringify(s));
63
63
  return;
64
64
  }
65
- // Only allow proxying to /v1/* paths — block path traversal
65
+ // Only allow proxying to /v1/* paths — block path traversal and SSRF
66
66
  const urlPath = req.url?.split('?')[0] ?? '';
67
- if (!urlPath.startsWith(ALLOWED_PATH_PREFIX)) {
67
+ if (!urlPath.startsWith(ALLOWED_PATH_PREFIX) || urlPath.includes('..') || urlPath.includes('//')) {
68
68
  res.writeHead(403, { 'Content-Type': 'application/json' });
69
69
  res.end(JSON.stringify({ error: 'Forbidden', message: `Only ${ALLOWED_PATH_PREFIX}* paths are proxied` }));
70
70
  return;
@@ -96,8 +96,18 @@ export async function startProxy(opts = {}) {
96
96
  if (verbose) {
97
97
  console.log(`[dario] #${requestCount} ${req.method} ${req.url}`);
98
98
  }
99
- // Forward to Anthropic with OAuth token + required beta flag
100
- const targetUrl = `${ANTHROPIC_API}${req.url}`;
99
+ // Forward to Anthropic construct URL safely to prevent SSRF
100
+ const targetUrl = new URL(urlPath, ANTHROPIC_API);
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
+ }
101
111
  // Merge any client-provided beta flags with the required oauth flag
102
112
  const clientBeta = req.headers['anthropic-beta'];
103
113
  const betaFlags = new Set(['oauth-2025-04-20']);
@@ -115,7 +125,7 @@ export async function startProxy(opts = {}) {
115
125
  'anthropic-beta': [...betaFlags].join(','),
116
126
  'x-app': 'cli',
117
127
  };
118
- const upstream = await fetch(targetUrl, {
128
+ const upstream = await fetch(targetUrl.toString(), {
119
129
  method: req.method ?? 'POST',
120
130
  headers,
121
131
  body: body.length > 0 ? body : undefined,
@@ -173,9 +183,10 @@ export async function startProxy(opts = {}) {
173
183
  }
174
184
  }
175
185
  catch (err) {
186
+ // Log full error server-side, return generic message to client
176
187
  console.error('[dario] Proxy error:', sanitizeError(err));
177
188
  res.writeHead(502, { 'Content-Type': 'application/json' });
178
- res.end(JSON.stringify({ error: 'Proxy error', message: sanitizeError(err) }));
189
+ res.end(JSON.stringify({ error: 'Proxy error', message: 'Failed to reach upstream API' }));
179
190
  }
180
191
  });
181
192
  server.listen(port, LOCALHOST, () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Use your Claude subscription as an API. Two commands, no API key. OAuth bridge for Claude Max/Pro.",
5
5
  "type": "module",
6
6
  "bin": {