import { Platform } from "./platform"; const obj = execution_mode == "chrome_api" ? chrome : browser; type Methods = { // eslint-disable-next-line @typescript-eslint/ban-types [k in Exclude]: T[k] extends Function ? T[k] : never; }; const types = [ "csp_report", "font", "image", "main_frame", "media", "object", "other", "ping", "script", "stylesheet", "sub_frame", "websocket", "xmlhttprequest" ] as browser.webRequest.ResourceType[]; const filts = { urls: ["https://boards.4channel.org/*", "https://boards.4chan.org/*", "https://desuarchive.org/*", "https://archived.moe/*", "https://archive.nyafuu.org/*", "https://arch.b4k.co/*", "https://archive.wakarimasen.moe/*", "https://fireden.net/*", "https://thebarchive.com/*", "https://files.catbox.moe/*", "https://de.catbox.moe/*", "https://based.coom.tech/*", "https://archiveofsins.com/*"], types: ["main_frame", "sub_frame", "csp_report", "object", "other", "ping"] as browser.webRequest.ResourceType[] }; if (manifest == 2) obj.webRequest.onHeadersReceived.addListener(details => { if (details.url.startsWith('https://arch.b4k.co/') && details.type == "main_frame") { const e = details.responseHeaders!.findIndex(e => e.name.toLowerCase() == "content-security-policy"); if (e >= 0) details.responseHeaders![e].value = ""; return { responseHeaders: [ ...details.responseHeaders!, { name: 'access-control-allow-origin', value: '*' } ] } as browser.webRequest.BlockingResponse; } }, filts, ['blocking', 'responseHeaders', ...(execution_mode == "chrome_api" ? ['extraHeaders' as 'blocking'] : [])]); async function bravedeserialize(src: any): Promise { if (typeof src != "object") return src; switch (src.cls) { case 'FormData': { const ret = new FormData(); for (const [key, items] of src.value) { for (const item of items) { ret.append(key, await bravedeserialize(item)); } } return ret; } case 'File': { return new File([src.value], src.name, { lastModified: src.lastModified, type: src.type }); } case 'Blob': { return new Blob([src.value], { type: src.type }); } case 'Object': { const ret = {} as any; for (const prop in src.value) { ret[prop] = await bravedeserialize(src.value[prop]); } return ret; } } } const bgCorsFetch = async (c: MessagePort, pendingFetches: Map, id: number, input: string, init?: RequestInit) => { if (input.startsWith('//')) // firefox?? input = 'https:' + input; if (init?.body && execution_mode == "chrome_api") { init.body = await bravedeserialize(init.body); } try { const k = await fetch(input, init); let headersStr = ''; const headerObj = {} as any; k.headers.forEach((v, k) => { headerObj[k] = v; headersStr += `${k}: ${v}\n`; }); c.postMessage({ id, setRes: true, ok: k.ok, headers: headerObj, responseHeaders: headersStr, redirected: k.redirected, type: k.type, url: k.url, status: k.status, bodyUsed: k.bodyUsed, statusText: k.statusText, }); pendingFetches.set(c, { [id]: { fetchFully: false }, ...(pendingFetches.get(c) || {}) }); let buff: Buffer[] = []; const ctotal = +headerObj['content-length'] || 0; // content total let ltotal = 0; // loaded total // sequence number, required to reorder messages client-side // if they get processed out of order let s = 0; const e = { write(chunk: Uint8Array) { ltotal += chunk.byteLength; c.postMessage({ id, progress: [ltotal, ctotal] }); if (!pendingFetches.get(c)![id].fetchFully) { //const url = new Blob([chunk]); c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]); } else { buff.push(Buffer.from(chunk)); } }, close() { if (buff.length > 0) { const chunk = Buffer.concat(buff); c.postMessage({ id, s: s++, pushData: { data: chunk } }, [chunk.buffer]); buff = []; } const obj = pendingFetches.get(c)!; delete obj[id]; if (Object.keys(obj).length == 0) pendingFetches.delete(c); c.postMessage({ id, s: s++, pushData: {} }); } }; const reader = k.body?.getReader(); let res: ReadableStreamDefaultReadResult; for (; ;) { res = await reader!.read(); if (res.done) break; e.write(res.value); } e.close(); reader?.releaseLock(); } catch (e) { const err = e as Error; c.postMessage({ id, setRes: true, ok: false, url: input, status: err.message }); } }; const meself = new URL(obj.runtime.getURL('')).origin; const waitConnect = (cb: any) => { window.addEventListener("message", (msg) => { //if (msg.origin === meself) { cb(msg.ports[0]); //} }, { once: true }); }; const onMessage = (c: MessagePort, cb: any) => c.onmessage = (e) => { cb(e.data); }; (async () => { // eslint-disable-next-line no-constant-condition while (true) { const c = await new Promise(waitConnect); console.log('New connection'); const pendingFetches = new Map(); onMessage(c, async (obj: any) => { const { id, name, args, sid, fid, url } = obj as any; if (name == "keepAlive") { console.log('im alive, tho?'); return; } if (name == "abortCorsFetch") { //chrome.runtime.sendMessage({ name, sid }); return; } if (name == "corsFetch") { // this handles the reply (bgCorsFetch as any)(c, pendingFetches, id, ...args); return; } if (name == "revoke") { URL.revokeObjectURL(url!); c.postMessage({ id, ok: 1 }); return; } if (name == "fullyRead") { const obj = pendingFetches.get(c)!; if (obj && fid! in obj) obj[fid!].fetchFully = true; c.postMessage({ id, ok: 1 }); return; } const res = await (Platform as any)[name](...args); c.postMessage({ id, res }); }); } })();