@askalf/dario 1.0.2 → 1.0.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 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
@@ -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
- // Only allow proxying to /v1/* paths block path traversal
66
- const urlPath = req.url?.split('?')[0] ?? '';
67
- if (!urlPath.startsWith(ALLOWED_PATH_PREFIX)) {
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: `Only ${ALLOWED_PATH_PREFIX}* paths are proxied` }));
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, etc)
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,8 +101,8 @@ export async function startProxy(opts = {}) {
96
101
  if (verbose) {
97
102
  console.log(`[dario] #${requestCount} ${req.method} ${req.url}`);
98
103
  }
99
- // Forward to Anthropic with OAuth token + required beta flag
100
- const targetUrl = `${ANTHROPIC_API}${req.url}`;
104
+ // Build target URL from allowlist (no user input in URL construction)
105
+ const targetUrl = targetBase;
101
106
  // Merge any client-provided beta flags with the required oauth flag
102
107
  const clientBeta = req.headers['anthropic-beta'];
103
108
  const betaFlags = new Set(['oauth-2025-04-20']);
@@ -173,9 +178,10 @@ export async function startProxy(opts = {}) {
173
178
  }
174
179
  }
175
180
  catch (err) {
181
+ // Log full error server-side, return generic message to client
176
182
  console.error('[dario] Proxy error:', sanitizeError(err));
177
183
  res.writeHead(502, { 'Content-Type': 'application/json' });
178
- res.end(JSON.stringify({ error: 'Proxy error', message: sanitizeError(err) }));
184
+ res.end(JSON.stringify({ error: 'Proxy error', message: 'Failed to reach upstream API' }));
179
185
  }
180
186
  });
181
187
  server.listen(port, LOCALHOST, () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
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": {