const express = require("express"); const router = express.Router(); const {jsdomFromText, browser} = require("sdenv"); const {Script} = require("node:vm"); const fs = require("node:fs"); const crypto = require("node:crypto") const AreaNameEnum = require('../enums/AreaNameEnum'); const Store = require("../utils/Store"); let store = new Store(); router.post('/rsCookie', async (req, res) => { let start = new Date(); try { let url = req.body['url']; let areaName = req.body['areaName']; let htmlStr = req.body['htmlBase64']; let jsStr = req.body['cookieBase64']; let cookie = req.body['cookieBase64']; let userAgent = req.body['userAgentBase64']; console.log(`接收到 ${areaName} 请求:${url}`) if (url == null || url === '') { return res.status(500).send('error url') } if (htmlStr == null || htmlStr === '') { return res.status(500).send('error html') } let jsText; if (jsStr == null || jsStr === "") { let jsPath = AreaNameEnum.getByAreaName(areaName).JS_FILE if (jsPath == null) { console.error('未找到js文件') return res.send('未找到js文件') } jsText = fs.readFileSync(jsPath).toString('utf8'); } else { jsText = Buffer.from(jsStr, 'base64').toString('utf-8') } let cookies = await handle(url, Buffer.from(htmlStr, 'base64').toString('utf-8'), jsText, cookie != null && cookie !== "" ? Buffer.from(cookie, 'base64').toString('utf-8') : null, userAgent != null && userAgent !== "" ? Buffer.from(userAgent, 'base64').toString('utf-8') : null) res.status(200).send(cookies); } catch (e) { console.error(e) return res.status(500).send(e.toString()) } finally { console.log(`rsCookie ${new Date() - start} ms`) } }) function loadJs(window, jsText) { // 加载js let js = ''; // 加载 页面上的js const allScript = window.document.querySelectorAll('script[r="m"]'); allScript.forEach(script => { let attr = script.textContent; if (attr) { js += attr } else { js += jsText } js += ";\n" }) return js; } async function handle(url, htmlStr, jsText, cookie, userAgent) { let uuid = crypto.randomUUID() // 获取 origin let baseUrl = new URL(url).origin; // 初始化 jsDom 和 cookieJar const [jsDom, cookieJar] = await jsdomFromText({ url: url, referrer: url, userAgent: userAgent, contentType: "text/html", runScripts: "outside-only", // runScripts: 'dangerously'/'outside-only' }) // 设置 cookie if (cookie != null) { cookieJar.setCookieSync(cookie, baseUrl); } // 加载dom let dom = await jsDom(htmlStr); console.log('html 加载--->', dom.serialize()) window = dom.window // js执行成功后的瑞树会跳转页面 会触发onbeforeunload钩子 window.onbeforeunload = async (url) => { const cookies = cookieJar.getCookieStringSync(baseUrl); // console.debug(`${url} 生成cookie:`, cookies); store.set(uuid, cookies) // window.close(); } // 初始化浏览器 browser(window, 'chrome'); // 加载js let js = loadJs(window, jsText); // 执行 js let script = new Script(js); console.log('js 加载--->', jsText) let internalVMContext = dom.getInternalVMContext(); script.runInContext(internalVMContext); // 等待 onbeforeunload 钩子触发后的回掉 let timeout = -1; let reTry = -1; if (process.env.NODE_ENV === 'prod') { timeout = 100 reTry = 10 } let val = await store.waitGetAndDelete(uuid, timeout, reTry) internalVMContext.close() window.close() dom = null if (val != null) { return val; } throw new Error('执行超时') } module.exports = router