You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
3.7 KiB
137 lines
3.7 KiB
const express = require("express"); |
|
const router = express.Router(); |
|
|
|
const {jsdomFromText, browser} = require("sdenv"); |
|
const {Script} = require("vm"); |
|
const fs = require("node:fs"); |
|
const path = require("node:path"); |
|
const crypto = require("crypto") |
|
|
|
|
|
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); |
|
|
|
|
|
const storeCookie = new Map; |
|
|
|
const areaJsMap = { |
|
"yunnan": path.resolve(__dirname, '../public/yunnan/MO5zzCMcub4d.b4c45da.js'), |
|
"hubei": path.resolve(__dirname, '../public/hubei/5PXGXoOF7eGJ.ed63b8f.js'), |
|
} |
|
|
|
|
|
router.post('/rsCookie', async (req, res) => { |
|
console.time('rsCookie') |
|
let url = req.body['url']; |
|
let htmlStr = req.body['htmlStr']; |
|
let jsStr = req.body['jsText']; |
|
let areaName = req.body['areaName']; |
|
let cookie = req.body['cookie']; |
|
let userAgent = req.body['userAgent']; |
|
|
|
if (url == null || url === '') { |
|
return res.send('error url') |
|
} |
|
if (htmlStr == null || htmlStr === '') { |
|
return res.send('error html') |
|
} |
|
|
|
try { |
|
let jsText; |
|
if (jsStr == null) { |
|
let jsPath = areaJsMap[areaName]; |
|
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 ? Buffer.from(cookie, 'base64').toString('utf-8') : null, |
|
userAgent != null ? Buffer.from(userAgent, 'base64').toString('utf-8') : null) |
|
res.send(cookies); |
|
} catch (e) { |
|
console.error(e) |
|
return res.send(e.toString()) |
|
} finally { |
|
console.timeEnd('rsCookie') |
|
} |
|
|
|
}) |
|
|
|
async function handle(url, htmlStr, jsText, cookie, userAgent) { |
|
let uuid = crypto.randomUUID() |
|
|
|
// 获取 origin |
|
let baseUrl = new URL(url).origin; |
|
|
|
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 |
|
const dom = await jsDom(htmlStr); |
|
|
|
window = dom.window |
|
// 加载 页面上的js |
|
const allScript = window.document.querySelectorAll('script[r="m"]'); |
|
|
|
// let $ = cheerio.load(htmlStr); |
|
// let nextAll = $('script[r=m]'); |
|
|
|
let js = ''; |
|
allScript.forEach(script=>{ |
|
let attr = script.textContent; |
|
if (attr) { |
|
js += attr |
|
} else { |
|
js += jsText |
|
} |
|
js += ";\n" |
|
}) |
|
// allScript.each((script) => { |
|
// |
|
// }) |
|
|
|
// 执行完成后的钩子 |
|
window.onbeforeunload = async (url) => { |
|
const cookies = cookieJar.getCookieStringSync(baseUrl); |
|
// console.debug(`${url} 生成cookie:`, cookies); |
|
storeCookie.set(uuid, cookies) |
|
// window.close(); |
|
return cookies; |
|
} |
|
|
|
browser(dom.window, 'chrome'); |
|
|
|
let script = new Script(js); |
|
let internalVMContext = dom.getInternalVMContext(); |
|
// 执行 js |
|
script.runInContext(internalVMContext); |
|
|
|
for (let i = 0; i < 10; i++) { |
|
await sleep(100) |
|
let hasCookie = storeCookie.has(uuid) |
|
if (hasCookie) { |
|
let newVar = storeCookie.get(uuid); |
|
storeCookie.delete(uuid) |
|
return newVar; |
|
} |
|
} |
|
throw new Error('执行超时') |
|
} |
|
|
|
|
|
module.exports = router |