const helper = {} const crypto = require('crypto'); const dns = require('dns'); helper.base64 = function(str){ return Buffer.from(str).toString('base64') } // '&channel=rd' helper.checkChannel = function(url,key) { return url.includes(key); } helper.capitalize_string = function(K) { // 将字符串按 "-" 分割,对每个单词首字母大写,然后重新用 "-" 连接 return K.split("-") .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join("-"); } helper.query_raw_text = function(K) { if (!K || typeof K !== 'object') { return ""; } const result = []; const replace_dict = { "'": "%27", "/": "%2F", "+": "%2B", "=": "%3D", "&": "%26", "@": "%40", "#": "%23", ";": "%3B", "?": "%3F", "%5B": "[", "%5D": "]", "%20": "+" }; // 自定义编码函数 function customEncode(str) { let encoded = encodeURIComponent(str); for (const [char, encoding] of Object.entries(replace_dict)) { encoded = encoded.replace(new RegExp(escapeRegExp(char), 'g'), encoding); } return encoded; } // 转义正则表达式特殊字符 function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } for (const [et, value] of Object.entries(K)) { if (value === null || value === undefined) { continue; } if (Array.isArray(value)) { // 处理数组 for (const nt of value) { result.push(`${et}[]=${customEncode(String(nt))}`); } } else if (typeof value === 'object') { // 处理对象 let nt = `${et}=${customEncode(JSON.stringify(value))}`; nt = nt.replace(/%5B/g, "[").replace(/%5D/g, "]"); result.push(nt); } else { // 处理普通值 result.push(`${et}=${customEncode(String(value))}`); } } return result.join("&"); } helper.get_signature = function(token,K, O = 'agentd3dGiJc651gSQ28w9', H = 'https://new-media-fx.qimao.com/api') { // 构建 Authorization 对象 const et = { "Authorization": token }; // 获取排序后的参数字符串 const nt = helper.params_sort(et); const at = helper.params_sort(K.get('data'), false); const it = helper.query_raw_text(K.get('params')); // 确定连接符 const ot = K['url'].includes('?') ? '&' : '?'; // 构建URL let st = K.get('url') + (it ? ot + it : ''); if (H && st.startsWith(H)) { st = st.substring(H.length); } // 构建最终签名字符串 const ct = `${st}&${nt}&${at}&${O}`; // 调试输出 /* console.log('nt:', nt); console.log('at:', at); console.log('it:', it); console.log('ot:', ot); console.log('st:', st); console.log('ct:', ct); */ return helper.sha256_hash(ct); } helper.params_sort = function(K, O = true) { if (!K || typeof K !== 'object') { return ""; } // 按照键的字母顺序排序 const sorted_keys = Object.keys(K).sort(); const result = []; for (const et of sorted_keys) { if (K[et] !== null && K[et] !== undefined) { // 根据 O 决定是否首字母大写 const nt = O ? helper.capitalize_string(et) : et; // 使用 JSON.stringify 来转换为 JSON 格式的字符串 result.push(`${nt}=${JSON.stringify(K[et])}`); } } // 拼接成查询字符串 return result.join("&"); } helper.sha256_hash = function(data) { const crypto = require('crypto'); // 创建一个 sha256 哈希对象 const hash = crypto.createHash('sha256'); // 更新哈希对象,传入数据 hash.update(data, 'utf-8'); // 获取最终的哈希值,返回一个十六进制字符串 return hash.digest('hex'); } helper.resolveDomain = async function(domain) { // 创建新的DNS解析器实例 const resolver = new dns.promises.Resolver(); // 尝试不同的DNS服务器 const dnsServers = [ '8.8.8.8', // Google DNS '8.8.4.4', // Google DNS备用 '1.1.1.1', // Cloudflare DNS '1.0.0.1', // Cloudflare DNS备用 '223.5.5.5', // 阿里DNS '223.6.6.6', // 阿里DNS备用 '119.29.29.29', // 腾讯DNS '114.114.114.114' // 114 DNS ]; for (const dnsServer of dnsServers) { try { console.log(`\nTrying DNS server: ${dnsServer}`); resolver.setServers([dnsServer]); const addresses = await resolver.resolve4(domain); console.log(`Success with DNS server ${dnsServer}:`); console.log('IP Addresses:', addresses); // 如果成功找到IP,尝试ping或TCP连接测试 for (const ip of addresses) { console.log(`Testing connectivity to IP: ${ip}`); // 这里可以添加连接测试代码 } return addresses; } catch (error) { console.error(`Failed with DNS server ${dnsServer}:`, error.message); } } throw new Error('Failed to resolve domain with all DNS servers'); } helper.md5 = function(text) { return crypto.createHash('md5').update(text).digest('hex'); } helper.getSign = function(distributorId,secretKey) { const params = [distributorId, secretKey, helper.getCurrentUnixTimestamp()]; // 将参数数组中的每个元素转换为字符串并连接成一个单一的字符串 const paramStr = params.map(String).join(''); // 使用 MD5 算法生成哈希值 const hash = crypto.createHash('md5'); hash.update(paramStr); // 返回哈希值的十六进制表示 return hash.digest('hex'); } helper.getCurrentUnixTimestamp = function() { return Math.floor(Date.now() / 1000) } helper.getFqRequestOpt = function(key,sid_tt='b0390e26648a71801795b3b13c9d7d20'){ const options = { url: `https://api.whbfxb.cn/api/novelsale/reader/get/content/v1/?aid=40013183&device_brand=realme&device_platform=android&device_type=RMX2020&mp_sdk_version=3.21.0&novelsale_app_scene=023001&version_code=230&key=${key}&item_source=1&module_name=ad_link&click_id=__CLICKID__&clickid=__CLICKID__&creativetype=__CTYPE__&demand_id=0&item_id=&media_source=1&mid1=__MID1__&mid2=__MID2__&mid3=__MID3__&mid4=__MID4__&mid5=__MID5__&projectid=__PROJECT_ID__&promotionid=__PROMOTION_ID__&request_id=__REQUESTID__&book_id=&host_novelsale_app_id=40013183`, headers: { 'cookie': `sid_tt=${sid_tt}; ` + 'ssid_ucp_v1=1.0.0-KDU0Nzc2NjZmZjRhNTZkYWM5YTMwN2ZmNzAyODMwNjFjZmQyMzA4OTYKFQjkktCcvMz_ARDGw7W6Bhjv6CA4CBoCbHEiIDhjOTg2NjgwY2Q4NzE2YmEzMmJhMjBjM2MwMmEwOTJk; ' + 'is_staff_user=false; ' + 'sid_ucp_v1=1.0.0-KDU0Nzc2NjZmZjRhNTZkYWM5YTMwN2ZmNzAyODMwNjFjZmQyMzA4OTYKFQjkktCcvMz_ARDGw7W6Bhjv6CA4CBoCbHEiIDhjOTg2NjgwY2Q4NzE2YmEzMmJhMjBjM2MwMmEwOTJk; ' + `sessionid=${sid_tt}; ` + 'ttwid=1%7CdTM3VEQ9KwlMsV2FV6Gaxv5CBXmd5i44fjDoZV_a8g8%7C1733124580%7Cc0952b31723a2f5d5e4b9f84a1c29cb7cbde5592906de58798b92a695d3fb292; ' + `sessionid_ss=${sid_tt}; ` + `sid_guard=${sid_tt}%7C1733124550%7C5184000%7CFri%2C+31-Jan-2025+07%3A29%3A10+GMT; ` + 'uid_tt=3361cf574bbdd82820371b4667fc9b91; ' + 'passport_csrf_token=f7e1da8668d26b8509725bcf7fa95628; ' + 'uid_tt_ss=3361cf574bbdd82820371b4667fc9b91; ' + 'passport_csrf_token_default=f7e1da8668d26b8509725bcf7fa95628; ' + 'store-region=cn-gs; ' + 'store-region-src=uid; ' + 'n_mh=9-mIeuD4wZnlYrrOvfzG3MuT6aQmCUtmr8FxV8Kl8xY', 'user-agent': 'Mozilla/5.0 (Linux; Android 9; Mi Note 3 Build/PKQ1.181007.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/120.0.6099.193 Mobile Safari/537.36 aweme/29.4.0 ToutiaoMicroApp/3.21.0 PluginVersion/29409006', 'content-type': 'application/json', 'referer': 'https://tmaservice.developer.toutiao.com/?appid=tt1b316d8c8401e42101&version=2.7.0' } }; return options } helper.getHyCreateLinkOpt = function(token){ const options = { url: `https://ms.zhangwenpindu.cn/manage/distribution/createLink`, headers: { 'Accept': 'application/json, text/plain, */*', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', 'Origin': 'https://manage.zhangwenpindu.cn', 'Pragma': 'no-cache', 'Referer': 'https://manage.zhangwenpindu.cn/', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-site', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', 'sec-ch-ua': '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"' } }; options.headers['Authorization'] = `Bearer ${token}` return options } helper.getTimeStampByHourMinute = function(timeStr,otherStr=null) { // 解析时间字符串 const [hours, minutes] = timeStr.split(':').map(Number); let date; if (otherStr) { // 如果提供了日期字符串,解析完整的日期时间 date = new Date(otherStr); // 设置时分秒 date.setHours(hours, minutes, 0, 0); } else { // 如果没有提供日期,使用今天的日期 date = new Date(); date.setHours(hours, minutes, 0, 0); } return date; } helper.getLocalDate = function() { const d = new Date(); const year = d.getFullYear(); const month = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } helper.getPaginationParams = function(total, pageSize = 500) { const pages = Math.ceil(total / pageSize); const result = []; for(let page = 0; page < pages; page++) { const offset = page * pageSize; const limit = Math.min(pageSize, total - offset); result.push({ page, offset, limit }); } return result; } module.exports = helper;