76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
/**
|
|
* Antigravity header scrubbing.
|
|
*
|
|
* Real Antigravity is a Node.js app. Its outbound HTTP requests never include
|
|
* proxy tracing headers, Stainless SDK headers, or Chromium Sec-Ch-* headers.
|
|
* Sending any of these reveals the request came through a third-party proxy.
|
|
*
|
|
* Based on CLIProxyAPI's ScrubProxyAndFingerprintHeaders (misc/header_utils.go).
|
|
*/
|
|
|
|
const HEADERS_TO_REMOVE = [
|
|
// Proxy tracing
|
|
"x-forwarded-for",
|
|
"x-forwarded-host",
|
|
"x-forwarded-proto",
|
|
"x-forwarded-port",
|
|
"x-real-ip",
|
|
"forwarded",
|
|
"via",
|
|
// Client identity (Stainless SDK — Claude Code specific, not Antigravity)
|
|
"x-title",
|
|
"x-stainless-lang",
|
|
"x-stainless-package-version",
|
|
"x-stainless-os",
|
|
"x-stainless-arch",
|
|
"x-stainless-runtime",
|
|
"x-stainless-runtime-version",
|
|
"x-stainless-timeout",
|
|
"x-stainless-retry-count",
|
|
"x-stainless-helper-method",
|
|
"http-referer",
|
|
"referer",
|
|
// Browser / Chromium fingerprint (Electron clients, NOT Node.js)
|
|
"sec-ch-ua",
|
|
"sec-ch-ua-mobile",
|
|
"sec-ch-ua-platform",
|
|
"sec-fetch-mode",
|
|
"sec-fetch-site",
|
|
"sec-fetch-dest",
|
|
"priority",
|
|
// Encoding: Antigravity (Node.js) sends "gzip, deflate, br" by default;
|
|
// Electron clients add "zstd" which is a fingerprint mismatch.
|
|
"accept-encoding",
|
|
];
|
|
|
|
/**
|
|
* Remove headers that reveal proxy infrastructure or non-native client identity
|
|
* from an outgoing request to Antigravity's upstream API.
|
|
*/
|
|
export function scrubProxyAndFingerprintHeaders(
|
|
headers: Record<string, string>
|
|
): Record<string, string> {
|
|
const cleaned: Record<string, string> = {};
|
|
let authorizationValue: string | undefined;
|
|
for (const [key, value] of Object.entries(headers)) {
|
|
const lowerKey = key.toLowerCase();
|
|
if (lowerKey.startsWith("x-omniroute-") || HEADERS_TO_REMOVE.includes(lowerKey)) {
|
|
continue;
|
|
}
|
|
if (lowerKey === "authorization") {
|
|
// Defer Authorization so it lands last in the serialized order — matches
|
|
// the native Antigravity fingerprint where Authorization
|
|
// is the final header before the body.
|
|
authorizationValue = value;
|
|
continue;
|
|
}
|
|
cleaned[key] = value;
|
|
}
|
|
// Set the standard Node.js accept-encoding
|
|
cleaned["Accept-Encoding"] = "gzip, deflate, br";
|
|
if (authorizationValue !== undefined) {
|
|
cleaned["Authorization"] = authorizationValue;
|
|
}
|
|
return cleaned;
|
|
}
|