UNPKG

11.9 kBSource Map (JSON)View Raw
1{"version":3,"sources":["extract.ts"],"names":["request","options","cb","response","statusCode","headers","encoding","res","url","method","compress","gzip","status","headersRaw","raw","headersObject","p","Object","keys","join","data","buffer","toString","then","err","requestP","req","r","Promise","resolve","reject","error","body","createSandbox","ctxObj","create","Error","ctx","vm","createContext","run","code","opts","runInContext","entries","map","a","JSON","stringify","script","parse","codeWindow","WINDOW","extract","uri","requester","bodyType","sandbox","timeout","info","scripts","includes","result","dlbutton","u","URL","download","href","filename","decodeURI","pathname","split","pop"],"mappings":"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","sourcesContent":["import vm from 'vm';\nimport url from 'url';\n\nimport fetch from 'node-fetch';\n\nimport {WINDOW} from './data';\n\nexport interface IRequestOptions {\n\t//\n\t/**\n\t * URL string.\n\t */\n\turl: string;\n\n\t/**\n\t * Request method.\n\t */\n\tmethod?: string;\n\n\t/**\n\t * Request headers.\n\t */\n\theaders?: {[key: string]: string};\n\n\t/**\n\t * Gzip compression.\n\t */\n\tgzip?: boolean;\n\n\t/**\n\t * Body encoding used for callback functions.\n\t */\n\tencoding?: string | null;\n}\n\nexport interface IRequestResponse {\n\t//\n\t/**\n\t * Status code.\n\t */\n\tstatusCode: number;\n\n\t/**\n\t * Response headers, all lowercase.\n\t */\n\theaders: {[key: string]: string};\n}\n\nexport type IRequestCallback = (\n\terror: any,\n\tresponse: IRequestResponse,\n\tbody: any\n) => void;\n\nexport type IRequest = (options: IRequestOptions, cb?: IRequestCallback) => any;\n\n/**\n * The default request implementation.\n *\n * @param options Options object.\n * @param cb Callback function.\n */\nfunction request(options: IRequestOptions, cb: IRequestCallback) {\n\tlet response: IRequestResponse = {\n\t\tstatusCode: 0,\n\t\theaders: {}\n\t};\n\tconst {encoding} = options;\n\t(async () => {\n\t\tconst res = await fetch(options.url, {\n\t\t\tmethod: options.method || 'GET',\n\t\t\theaders: {\n\t\t\t\t'User-Agent': '-',\n\t\t\t\t...(options.headers || {})\n\t\t\t},\n\t\t\tcompress: !!options.gzip\n\t\t});\n\t\tconst {status, headers} = res;\n\t\tconst headersRaw = headers.raw();\n\t\tconst headersObject: {[key: string]: string} = {};\n\t\tfor (const p of Object.keys(headersRaw)) {\n\t\t\theadersObject[p] = headersRaw[p].join(', ');\n\t\t}\n\t\tresponse = {\n\t\t\tstatusCode: status,\n\t\t\theaders: headersObject\n\t\t};\n\t\tconst data = await res.buffer();\n\t\treturn encoding === null ? data : data.toString(encoding as any);\n\t})().then(\n\t\tdata => {\n\t\t\tcb(null, response, data);\n\t\t},\n\t\terr => {\n\t\t\tcb(err, response, null);\n\t\t}\n\t);\n}\n\n/**\n * A request promise wrapper.\n *\n * @param req Request function.\n * @param options Request options.\n * @returns Request response and body.\n */\nasync function requestP(req: IRequest, options: IRequestOptions) {\n\tconst r = await new Promise<{\n\t\t//\n\t\t/**\n\t\t * Response object.\n\t\t */\n\t\tresponse: IRequestResponse;\n\n\t\t/**\n\t\t * Response body.\n\t\t */\n\t\tbody: Buffer | string;\n\t}>((resolve, reject) => {\n\t\treq(options, (error, response, body: Buffer | string) => {\n\t\t\tif (error) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresolve({\n\t\t\t\tresponse,\n\t\t\t\tbody\n\t\t\t});\n\t\t});\n\t});\n\treturn r;\n}\n\n/**\n * Create a VM sandbox safe from context leakage.\n *\n * @returns Methods to run code in the VM sandbox.\n */\nfunction createSandbox() {\n\t// Create a context with which to run code in.\n\t// Creating the object with a null prototype is very important.\n\t// Prevents host variables from leaking into the sanbox.\n\tconst ctxObj = Object.create(null) as {toString?: () => string};\n\tif (ctxObj.toString) {\n\t\tthrow new Error('Failed to create object without prototype');\n\t}\n\tconst ctx = vm.createContext(ctxObj);\n\treturn {\n\t\t/**\n\t\t * Run code, no return.\n\t\t *\n\t\t * @param code Code string.\n\t\t * @param opts VM options.\n\t\t */\n\t\trun: (code: string, opts: vm.RunningScriptOptions) => {\n\t\t\tlet error = false;\n\t\t\ttry {\n\t\t\t\tvm.runInContext(code, ctx, opts);\n\t\t\t} catch (err) {\n\t\t\t\terror = true;\n\t\t\t}\n\t\t\tif (error) {\n\t\t\t\tthrow new Error('Error running sandboxed script');\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run code, return data.\n\t\t *\n\t\t * @param data The data to get.\n\t\t * @param opts VM options.\n\t\t * @returns Data object.\n\t\t */\n\t\tdata: (data: {[k: string]: string}, opts: vm.RunningScriptOptions) => {\n\t\t\tconst body = Object.entries(data)\n\t\t\t\t.map(a => `${JSON.stringify(a[0])}:${a[1]}`)\n\t\t\t\t.join(',');\n\t\t\tconst script = `(\"\"+JSON.stringify({${body}}))`;\n\t\t\tlet r: {[k: string]: any} | null = null;\n\t\t\ttry {\n\t\t\t\t// Force return value string with concatenation, NOT casting.\n\t\t\t\t// This prevents any funny business from sandboxed code.\n\t\t\t\tr = JSON.parse(\n\t\t\t\t\t// eslint-disable-next-line\n\t\t\t\t\t'' + vm.runInContext(script, ctx, opts)\n\t\t\t\t) as {[k: string]: any} | null;\n\t\t\t} catch (err) {\n\t\t\t\t// Do nothing.\n\t\t\t}\n\t\t\tif (!r) {\n\t\t\t\tthrow new Error('Error running sandboxed script');\n\t\t\t}\n\t\t\treturn r;\n\t\t}\n\t};\n}\n\n/**\n * Code to create window.\n *\n * @param body HTML body.\n * @returns JavaScript code.\n */\nfunction codeWindow(body: string) {\n\treturn `(${WINDOW})(this,${JSON.stringify(body)})`;\n}\n\n/**\n * Extract file info from a URL.\n *\n * @param uri The URI to extract info from.\n * @param req Optional custom request function or null.\n * @returns File info.\n */\nexport async function extract(uri: string, req: IRequest | null = null) {\n\tconst requester = req || (request as IRequest);\n\tconst {response, body} = await requestP(requester, {\n\t\turl: uri,\n\t\tgzip: true\n\t});\n\tconst {statusCode} = response;\n\tif (statusCode !== 200) {\n\t\tthrow new Error(`Invalid status code: ${statusCode}`);\n\t}\n\tconst bodyType = typeof body;\n\tif (bodyType !== 'string') {\n\t\tthrow new Error(`Invalid body type: ${bodyType}`);\n\t}\n\n\tconst sandbox = createSandbox();\n\tconst timeout = 1000;\n\n\t// Setup environment.\n\tsandbox.run(codeWindow(body.toString()), {});\n\n\t// Extract info from environment.\n\tconst info = sandbox.data(\n\t\t{\n\t\t\tscripts:\n\t\t\t\t'(function(i,r,l){' +\n\t\t\t\t'while(++i<l.length){' +\n\t\t\t\t'r.push(l[i].textContent)' +\n\t\t\t\t'}' +\n\t\t\t\t'return r' +\n\t\t\t\t'})(-1,[],document.getElementsByTagName(\"script\"))'\n\t\t},\n\t\t{\n\t\t\ttimeout\n\t\t}\n\t);\n\n\t// Run the scripts that modify the download button.\n\tfor (const script of info.scripts) {\n\t\tif ((script as string).includes('dlbutton')) {\n\t\t\tsandbox.run(script, {\n\t\t\t\ttimeout\n\t\t\t});\n\t\t}\n\t}\n\n\t// Extract info about environment.\n\tconst result = sandbox.data(\n\t\t{\n\t\t\tdlbutton: 'document.getElementById(\"dlbutton\").href'\n\t\t},\n\t\t{\n\t\t\ttimeout\n\t\t}\n\t);\n\n\t// Check result.\n\tif (!result.dlbutton) {\n\t\tthrow new Error('Failed to extract info');\n\t}\n\n\t// Parse download link and file name.\n\tconst u = new url.URL(result.dlbutton, uri);\n\treturn {\n\t\tdownload: u.href,\n\t\tfilename: decodeURI(u.pathname.split('/').pop() || '') || null\n\t};\n}\n"],"file":"extract.js","sourceRoot":"../src"}
\No newline at end of file