feat: browser headers on audit fetches + verified clone furnidata sources
This commit is contained in:
1 parent
080dc34e23
commit
2fba923a3a
8 files changed
+97
-32
No files matched your search
@@ -0,0 +1,49 @@
|
||||
export type BrowserFetchDest =
|
||||
| "document"
|
||||
| "image"
|
||||
| "script"
|
||||
| "style"
|
||||
| "empty";
|
||||
|
||||
const CHROME_UA =
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36";
|
||||
|
||||
const SEC_CH_UA =
|
||||
'"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"';
|
||||
|
||||
/**
|
||||
* Realistic browser request headers so CDNs (Cloudflare, etc.) treat the
|
||||
* server-side fetches as a normal browser instead of a bot/curl and block us.
|
||||
*/
|
||||
export function browserHeaders(
|
||||
dest: BrowserFetchDest = "empty",
|
||||
extra: Record<string, string> = {},
|
||||
): Record<string, string> {
|
||||
const accept =
|
||||
dest === "document"
|
||||
? "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
|
||||
: dest === "image"
|
||||
? "image/avif,image/webp,image/apng,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"
|
||||
: dest === "script"
|
||||
? "*/*"
|
||||
: "application/json,text/plain,*/*;q=0.9";
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"User-Agent": CHROME_UA,
|
||||
"sec-ch-ua": SEC_CH_UA,
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
Accept: accept,
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"Sec-Fetch-Mode":
|
||||
dest === "document" ? "navigate" : dest === "image" ? "no-cors" : "cors",
|
||||
"Sec-Fetch-Dest": dest,
|
||||
"Cache-Control": "no-cache",
|
||||
Pragma: "no-cache",
|
||||
};
|
||||
|
||||
if (dest === "document") headers["Upgrade-Insecure-Requests"] = "1";
|
||||
|
||||
return { ...headers, ...extra };
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import { promises as fs } from "node:fs";
|
||||
|
||||
import { browserHeaders } from "./browser-headers";
|
||||
|
||||
export function validateSwfBytes(buffer: Buffer): boolean {
|
||||
if (buffer.length < 8) return false;
|
||||
const sig = buffer.toString("ascii", 0, 3);
|
||||
@@ -31,11 +33,9 @@ export async function downloadFile(
|
||||
}
|
||||
const res = await fetch(url, {
|
||||
signal: AbortSignal.timeout(15000),
|
||||
headers: {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0 Safari/537.36",
|
||||
headers: browserHeaders("image", {
|
||||
Accept: "image/png,image/*,*/*;q=0.8",
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const deterministic =
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { browserHeaders } from "./browser-headers";
|
||||
|
||||
const EXTERNAL_VARIABLES_URL =
|
||||
"https://www.habbo.com/gamedata/external_variables/1";
|
||||
const CACHE_TTL = 30 * 60 * 1000;
|
||||
@@ -14,6 +16,7 @@ export async function resolveGordonBuildUrl(): Promise<string> {
|
||||
if (gordonCache && now - gordonCache.ts < CACHE_TTL) return gordonCache.url;
|
||||
const res = await fetch(EXTERNAL_VARIABLES_URL, {
|
||||
signal: AbortSignal.timeout(20000),
|
||||
headers: browserHeaders("document"),
|
||||
});
|
||||
if (!res.ok)
|
||||
throw new Error(`external_variables fetch failed: ${res.status}`);
|
||||
|
||||
Reference in new issue
Block a user