Fix : Antigravity MITM
This commit is contained in:
@@ -1,19 +1,31 @@
|
||||
const { err } = require("../logger");
|
||||
const { err, createResponseDumper } = require("../logger");
|
||||
const { fetchRouter, pipeSSE } = require("./base");
|
||||
|
||||
/**
|
||||
* Intercept Antigravity (Gemini) request — replace model and forward to router
|
||||
* Intercept Antigravity request — forward Gemini body as-is to /v1/chat/completions.
|
||||
* Router auto-detects format via body.userAgent==="antigravity" + body.request.contents,
|
||||
* runs antigravity→openai→provider→openai→antigravity translators internally.
|
||||
*/
|
||||
async function intercept(req, res, bodyBuffer, mappedModel) {
|
||||
const dumper = createResponseDumper(req, "intercept-antigravity");
|
||||
const isStream = req.url.includes(":streamGenerateContent");
|
||||
try {
|
||||
const body = JSON.parse(bodyBuffer.toString());
|
||||
body.model = mappedModel;
|
||||
if (body.model) body.model = mappedModel;
|
||||
|
||||
const routerRes = await fetchRouter(body, "/v1/chat/completions", req.headers);
|
||||
await pipeSSE(routerRes, res);
|
||||
await pipeSSE(routerRes, res, dumper);
|
||||
} catch (error) {
|
||||
err(`[antigravity] ${error.message}`);
|
||||
if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ error: { message: error.message, type: "mitm_error" } }));
|
||||
if (dumper) { dumper.writeChunk(`\n[ERROR] ${error.message}\n`); dumper.end(); }
|
||||
// For stream endpoint, send SSE error chunk so SDK doesn't hang waiting
|
||||
if (isStream) {
|
||||
if (!res.headersSent) res.writeHead(200, { "Content-Type": "text/event-stream" });
|
||||
res.end(`data: ${JSON.stringify({ error: { message: error.message } })}\r\n\r\n`);
|
||||
} else {
|
||||
if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ error: { message: error.message, type: "mitm_error" } }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-10
@@ -32,25 +32,26 @@ async function fetchRouter(openaiBody, path = "/v1/chat/completions", clientHead
|
||||
body: JSON.stringify(openaiBody)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errText = await response.text().catch(() => "");
|
||||
throw new Error(`[${response.status}]: ${errText}`);
|
||||
}
|
||||
|
||||
// Forward response as-is (status + body). pipeSSE will propagate status.
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pipe SSE stream from router directly to client response
|
||||
* Pipe SSE stream from router directly to client response.
|
||||
* Optional dumper tees the stream into a debug file.
|
||||
*/
|
||||
async function pipeSSE(routerRes, res) {
|
||||
async function pipeSSE(routerRes, res, dumper) {
|
||||
const ct = routerRes.headers.get("content-type") || "application/json";
|
||||
const status = routerRes.status || 200;
|
||||
const resHeaders = { "Content-Type": ct, "Cache-Control": "no-cache", "Connection": "keep-alive" };
|
||||
if (ct.includes("text/event-stream")) resHeaders["X-Accel-Buffering"] = "no";
|
||||
res.writeHead(200, resHeaders);
|
||||
res.writeHead(status, resHeaders);
|
||||
if (dumper) dumper.writeHeader(routerRes.status, Object.fromEntries(routerRes.headers));
|
||||
|
||||
if (!routerRes.body) {
|
||||
res.end(await routerRes.text().catch(() => ""));
|
||||
const text = await routerRes.text().catch(() => "");
|
||||
if (dumper) { dumper.writeChunk(text); dumper.end(); }
|
||||
res.end(text);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,7 +59,8 @@ async function pipeSSE(routerRes, res) {
|
||||
const decoder = new TextDecoder();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) { res.end(); break; }
|
||||
if (done) { if (dumper) dumper.end(); res.end(); break; }
|
||||
if (dumper) dumper.writeChunk(value);
|
||||
res.write(decoder.decode(value, { stream: true }));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user