openzoo 0.29.0 → 0.29.2
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/lib/cursorbackend.js +21 -7
- package/lib/setup.js +31 -2
- package/package.json +1 -1
package/lib/cursorbackend.js
CHANGED
|
@@ -126,23 +126,37 @@ function respond(req, res, method, models) {
|
|
|
126
126
|
*/
|
|
127
127
|
export function startCursorBackend({ port = 8443, models, log = () => {} } = {}) {
|
|
128
128
|
const { cert, key } = ensureCert(log);
|
|
129
|
+
let conns = 0;
|
|
129
130
|
const server = https.createServer(
|
|
130
|
-
{
|
|
131
|
+
{
|
|
132
|
+
cert: fs.readFileSync(cert),
|
|
133
|
+
key: fs.readFileSync(key),
|
|
134
|
+
// Log which hostname the editor asked for on the TLS handshake — this is
|
|
135
|
+
// the single clearest proof the redirect is working and the editor is
|
|
136
|
+
// reaching US instead of the real backend.
|
|
137
|
+
SNICallback: (servername, cb) => { log(`cursor-tls: <- ClientHello SNI=${servername}`); cb(null); },
|
|
138
|
+
},
|
|
131
139
|
async (req, res) => {
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
140
|
+
conns += 1;
|
|
141
|
+
const full = req.url || '';
|
|
142
|
+
const method = full.split('/').filter(Boolean).pop() || '';
|
|
143
|
+
const ct = req.headers['content-type'] || '?';
|
|
144
|
+
const body = await readBody(req);
|
|
145
|
+
log(`cursor-backend: #${conns} ${req.method} ${full} ct=${ct} body=${body.length}b`);
|
|
135
146
|
try {
|
|
136
147
|
respond(req, res, method, models);
|
|
137
|
-
|
|
148
|
+
log(`cursor-backend: -> ${method === 'AvailableModels' ? `AvailableModels (${models.length} models, gates open)` : 'empty-ok'}`);
|
|
138
149
|
} catch (e) {
|
|
139
150
|
res.writeHead(200, { 'content-type': 'application/proto', 'grpc-status': '0' });
|
|
140
151
|
res.end(Buffer.alloc(0));
|
|
141
|
-
log(`cursor-backend:
|
|
152
|
+
log(`cursor-backend: -> empty-ok (err ${e.message})`);
|
|
142
153
|
}
|
|
143
154
|
},
|
|
144
155
|
);
|
|
145
|
-
|
|
156
|
+
// NEVER swallow this — a rejected handshake is exactly the failure to see.
|
|
157
|
+
server.on('tlsClientError', (e, sock) => {
|
|
158
|
+
log(`cursor-tls: HANDSHAKE FAILED ${e.code || e.message} (peer ${sock?.remoteAddress || '?'})`);
|
|
159
|
+
});
|
|
146
160
|
server.listen(port, '127.0.0.1', () => log(`cursor-backend: listening on 127.0.0.1:${port} as ${CURSOR_HOSTS[0]}`));
|
|
147
161
|
return { server, port };
|
|
148
162
|
}
|
package/lib/setup.js
CHANGED
|
@@ -448,7 +448,11 @@ export async function setupEditor(which, target) {
|
|
|
448
448
|
// ourselves: catalog with every gate open, empty-valid for the rest. No CA
|
|
449
449
|
// install — the editor is launched with --ignore-certificate-errors below,
|
|
450
450
|
// and it does not pin certs (verified), so a self-signed cert is accepted.
|
|
451
|
-
|
|
451
|
+
// DEFAULT ON. Takeover is what makes a plan-less account route, and it is
|
|
452
|
+
// harmless on an entitled one (the editor just reads our catalog instead of
|
|
453
|
+
// theirs), so it runs unless explicitly disabled with --no-takeover.
|
|
454
|
+
const doTakeover = target0 === 'cursor' && !process.argv.includes('--no-takeover');
|
|
455
|
+
if (doTakeover) {
|
|
452
456
|
try {
|
|
453
457
|
const { startCursorBackend } = await import('./cursorbackend.js');
|
|
454
458
|
const { redirect443 } = await import('./hosts.js');
|
|
@@ -458,6 +462,31 @@ export async function setupEditor(which, target) {
|
|
|
458
462
|
console.log(rr.ok ? 'takeover: 443 -> 8443 redirect installed (npx openzoo unblock reverts)'
|
|
459
463
|
: rr.manual ? 'takeover: apply the redirect above, then relaunch'
|
|
460
464
|
: 'takeover: could NOT install the 443 redirect — impersonation will not receive traffic');
|
|
465
|
+
|
|
466
|
+
// SELF-TEST — prove the whole path (hosts -> redirect -> our server) works
|
|
467
|
+
// NOW, at startup, so a failure is a loud line here instead of a silent
|
|
468
|
+
// "still gated" in the editor. We dial api2.cursor.sh exactly as the editor
|
|
469
|
+
// will; if our backend logs the ClientHello and answers, it is wired.
|
|
470
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
471
|
+
try {
|
|
472
|
+
const https = await import('node:https');
|
|
473
|
+
const ok = await new Promise((resolve) => {
|
|
474
|
+
const rq = https.request({
|
|
475
|
+
host: 'api2.cursor.sh', port: 443, method: 'POST',
|
|
476
|
+
path: '/aiserver.v1.AiService/AvailableModels',
|
|
477
|
+
headers: { 'content-type': 'application/grpc-web+proto' },
|
|
478
|
+
rejectUnauthorized: false, timeout: 4000,
|
|
479
|
+
}, (rp) => { rp.on('data', () => {}); rp.on('end', () => resolve(rp.statusCode === 200)); });
|
|
480
|
+
rq.on('error', () => resolve(false));
|
|
481
|
+
rq.on('timeout', () => { rq.destroy(); resolve(false); });
|
|
482
|
+
rq.end();
|
|
483
|
+
});
|
|
484
|
+
console.log(ok
|
|
485
|
+
? 'takeover: SELF-TEST PASS — api2.cursor.sh:443 reaches our backend. The editor will too.'
|
|
486
|
+
: 'takeover: SELF-TEST FAIL — api2.cursor.sh:443 did NOT reach our backend.\n'
|
|
487
|
+
+ ' The 443->8443 redirect is not delivering (pfctl/loopback). Tell me and I switch to a root-bound 443.');
|
|
488
|
+
} catch (e) { console.log(`takeover: self-test error (${e.message})`); }
|
|
489
|
+
|
|
461
490
|
console.log('takeover: launching with --ignore-certificate-errors so the self-signed cert is trusted (no CA install)');
|
|
462
491
|
} catch (e) {
|
|
463
492
|
console.log(`takeover: failed to start (${e.message}) — falling back to plain routing`);
|
|
@@ -497,7 +526,7 @@ export async function setupEditor(which, target) {
|
|
|
497
526
|
const args = [cwd];
|
|
498
527
|
// Trust our self-signed impersonation cert without any CA install — this flag
|
|
499
528
|
// is the entire reason no trust prompt is needed. Only added under --takeover.
|
|
500
|
-
if (target0 === 'cursor' && process.argv.includes('--takeover')) args.unshift('--ignore-certificate-errors');
|
|
529
|
+
if (target0 === 'cursor' && !process.argv.includes('--no-takeover')) args.unshift('--ignore-certificate-errors');
|
|
501
530
|
if (useProfile) {
|
|
502
531
|
fs.mkdirSync(PROFILE_DIR, { recursive: true });
|
|
503
532
|
args.unshift(`--user-data-dir=${PROFILE_DIR}`, `--extensions-dir=${path.join(PROFILE_DIR, 'extensions')}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.2",
|
|
4
4
|
"description": "Local x402-paying proxy + MCP server for openzoo.fun — point any OpenAI-compatible harness (Cursor, Claude Code, aider, SDKs) at localhost and it pays per call from a local burner wallet. Solana and Base rails live; Robinhood experimental.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|