添加whatshub工单
This commit is contained in:
Executable
+121
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 会话 Cookie 持久化:按 sessionKey 保存 cf_clearance 等,降低重复过盾概率
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const { RUNTIME_DIR, SESSION_TTL_MS } = require('./constants');
|
||||
|
||||
const SESSIONS_DIR = path.join(RUNTIME_DIR, 'sessions');
|
||||
|
||||
/**
|
||||
* 确保 sessions 目录存在
|
||||
*/
|
||||
function ensureSessionsDir() {
|
||||
fs.mkdirSync(SESSIONS_DIR, { recursive: true, mode: 0o777 });
|
||||
}
|
||||
|
||||
/**
|
||||
* sessionKey 转安全文件名
|
||||
* @param {string} sessionKey
|
||||
* @returns {string}
|
||||
*/
|
||||
function keyToFilename(sessionKey) {
|
||||
const hash = crypto.createHash('md5').update(sessionKey).digest('hex');
|
||||
return `${hash}.json`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} StoredSession
|
||||
* @property {string} sessionKey
|
||||
* @property {number} savedAt
|
||||
* @property {number} expiresAt
|
||||
* @property {Array<{name:string,value:string,domain?:string,path?:string}>} cookies
|
||||
*/
|
||||
|
||||
/**
|
||||
* 加载已保存的会话 cookies
|
||||
* @param {string} sessionKey
|
||||
* @returns {StoredSession|null}
|
||||
*/
|
||||
function loadSession(sessionKey) {
|
||||
if (!sessionKey) return null;
|
||||
ensureSessionsDir();
|
||||
const filePath = path.join(SESSIONS_DIR, keyToFilename(sessionKey));
|
||||
if (!fs.existsSync(filePath)) return null;
|
||||
|
||||
try {
|
||||
const raw = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
if (!raw || !Array.isArray(raw.cookies)) return null;
|
||||
if (raw.expiresAt && Date.now() > raw.expiresAt) {
|
||||
fs.unlinkSync(filePath);
|
||||
return null;
|
||||
}
|
||||
return raw;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存会话 cookies(优先保留 CF 相关 cookie)
|
||||
* @param {string} sessionKey
|
||||
* @param {Array<{name:string,value:string,domain?:string,path?:string}>} cookies
|
||||
* @param {number} [ttlMs]
|
||||
*/
|
||||
function saveSession(sessionKey, cookies, ttlMs = SESSION_TTL_MS) {
|
||||
if (!sessionKey || !Array.isArray(cookies) || cookies.length === 0) return;
|
||||
ensureSessionsDir();
|
||||
|
||||
const cfRelated = cookies.filter((c) =>
|
||||
['cf_clearance', '__cf_bm', 'cf_chl_2'].includes(c.name)
|
||||
|| c.name.startsWith('__cf')
|
||||
);
|
||||
|
||||
const toSave = cfRelated.length > 0 ? cfRelated : cookies;
|
||||
const now = Date.now();
|
||||
const payload = {
|
||||
sessionKey,
|
||||
savedAt: now,
|
||||
expiresAt: now + ttlMs,
|
||||
cookies: toSave.map((c) => ({
|
||||
name: c.name,
|
||||
value: c.value,
|
||||
domain: c.domain,
|
||||
path: c.path || '/',
|
||||
})),
|
||||
};
|
||||
|
||||
const filePath = path.join(SESSIONS_DIR, keyToFilename(sessionKey));
|
||||
fs.writeFileSync(filePath, JSON.stringify(payload, null, 0), { mode: 0o666 });
|
||||
}
|
||||
|
||||
/**
|
||||
* 将会话 cookies 转为 puppeteer setCookie 格式
|
||||
* @param {StoredSession|null} session
|
||||
* @param {string} pageUrl
|
||||
* @returns {Array<{name:string,value:string,domain?:string,path?:string,url?:string}>}
|
||||
*/
|
||||
function sessionCookiesForPage(session, pageUrl) {
|
||||
if (!session || !Array.isArray(session.cookies)) return [];
|
||||
let hostname = '';
|
||||
try {
|
||||
hostname = new URL(pageUrl).hostname;
|
||||
} catch (_) {
|
||||
return session.cookies;
|
||||
}
|
||||
|
||||
return session.cookies.map((c) => {
|
||||
const cookie = { ...c };
|
||||
if (!cookie.domain && hostname) {
|
||||
cookie.url = `https://${hostname}/`;
|
||||
}
|
||||
return cookie;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
loadSession,
|
||||
saveSession,
|
||||
sessionCookiesForPage,
|
||||
};
|
||||
Reference in New Issue
Block a user