123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- 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.checkChannelListKey = function(url,key_list) {
- for (let index = 0; index < key_list.length; index++) {
- const key = key_list[index];
- if(!this.checkChannel(url,key)){
- return false
- }
- }
- return true
- }
- 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&key=${key}`,
- // 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',
- 'cookie': `sessionid=${sid_tt};`,
- '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.getMfFqRequestOpt = function(key,sid_tt='85486acb04e1918afbee91a9466a9fdc'){
- const options = {
- // url: `https://sdksaleapi.hubeidehuic.com/open_sdk/reader/directory/list/v1?novelsale_aid=40017686&novelsdk_aid=638505&novelsdk_version_code=230&novelsdk_device_type=V2049A&promotion_code=${key}&novelsdk_device_platform=android&version_code=290400&device_type=V2049A&sale_app_id=40017686&book_id&force_no_user_id=true&novelsdk_app_name=undefined&app_name=aweme&device_brand=vivo&device_platform=android&aid=1128&mini_app_version=2.3.0&iid=2936130190182979&device_id=825067091580075&ac=wifi&channel=douyin-huidu-gw-huidu-2940&version_name=29.4.0&os=android&ssmix=a&language=zh&os_api=31&os_version=12&manifest_version_code=290400&resolution=1080*2193&dpi=480&update_version_code=29400100&_rticket=1735289341306&first_launch_timestamp=1733382087&last_deeplink_update_version_code=0&cpu_support64=true&host_abi=arm64-v8a&is_guest_mode=0&app_type=normal&minor_status=0&appTheme=light&is_preinstall=0&need_personal_recommend=1&is_android_pad=0&is_android_fold=0&ts=1735289340&cdid=623fd2d5-5680-4aa4-95e8-78378a2ac7c5`,
- url: `https://sdksaleapi.hubeidehuic.com/open_sdk/reader/directory/list/v1?novelsale_aid=40017686&novelsdk_aid=638505&promotion_code=${key}`,
- headers: {
- 'Connection': 'keep-alive',
- 'Cookie': `sessionid=${sid_tt};`,
- // 'Cookie': `sid_tt=${sid_tt};ssid_ucp_v1=1.0.0-KDVhZTIzM2QyOGFlMGE1MWRhMGIzNmI1MzFmZjlmMTVlODhjYmJiOTkKFQjr19Cz7syDAxC9zrm7Bhip_CY4CBoCbGYiIDg1NDg2YWNiMDRlMTkxOGFmYmVlOTFhOTQ2NmE5ZmRj;is_staff_user=false;sid_ucp_v1=1.0.0-KDVhZTIzM2QyOGFlMGE1MWRhMGIzNmI1MzFmZjlmMTVlODhjYmJiOTkKFQjr19Cz7syDAxC9zrm7Bhip_CY4CBoCbGYiIDg1NDg2YWNiMDRlMTkxOGFmYmVlOTFhOTQ2NmE5ZmRj;sessionid=${sid_tt};sessionid_ss=${sid_tt};uid_tt=88e8f06afa51aef4fac18f5d77607921;sid_guard=${sid_tt}%7C1735288637%7C5184000%7CTue%2C+25-Feb-2025+08%3A37%3A17+GMT;passport_csrf_token=08c2b9062233b43ce0e2dd24171203b1;odin_tt=9783bbcf8f09663820810574a01f08b307b6e74c90aa3d8a3b4a80faa9a7d4b197d7e807043c111dcbabde8551e1111145cc87c65fce067f3c532bd796b3681a;uid_tt_ss=88e8f06afa51aef4fac18f5d77607921;passport_csrf_token_default=08c2b9062233b43ce0e2dd24171203b1;store-region=cn-gd;store-region-src=uid;n_mh=9-mIeuD4wZnlYrrOvfzG3MuT6aQmCUtmr8FxV8Kl8xY`,
- 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; V2049A Build/SP1A.210812.003; 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',
- 'bdp-sec-uid': 'MS4wLjABAAAA1M_29BGiEjsgNHMP-bmblk-9qGkx5vN7Y3HgltXiFghmy1mfPlH3eonnTWpXANjE',
- 'bdp-did': '825067091580075',
- 'bdp-channel': 'douyin-huidu-gw-huidu-2940',
- 'bdp-device-timezone-offset': '28800',
- 'bdp-os-version': '12',
- 'bdp-os-name': 'Android',
- 'bdp-uid': '1788263942327546',
- 'bdp-version-code': '290400',
- 'bdp-device-platform': 'Android',
- 'bdp-aid': '1128',
- 'bdp-device-manufacturer': 'vivo',
- 'bdp-app-id': 'tt26e45059b9d1239401',
- 'bdp-device-model': 'V2049A',
- 'Content-Type': 'application/json',
- 'activity_now_client': '0',
- 'x-bd-kmsv': '1',
- 'x-tt-request-tag': 's=-1;p=1',
- 'x-tt-trace-id': '00-074e072b0d2ee64e6e8d4abbf55d0468-074e072b0d2ee64e-01',
- 'X-Argus': '/WluZw==',
- 'X-Gorgon': '8404f06a00014b0d761b864b2932a41f362b9276f3488e7700de',
- 'X-Helios': 'AkKvNQvLH57rNKMEdZDNQPlc89Q1Zrs974uhRy+IDcTR/y8Z',
- 'X-Khronos': '1735289341',
- 'X-Ladon': 'Z25p/Q==',
- 'X-Medusa': '/mluZwqBMZ0qvrJcK0OmF6qmD3/QqgABDTUpyT1IA9+MOFfCQlYXoNnb+C/rkhLwH0AzGIam8DGpfzu3MFDs3fD3Jx12yo1AKxmV8ar5cQEJ+yz2srKfjMWVZhnlSHsA8UOdYdeclol6hoyOKCcvD9k+84icb0lW39sUS4b+3c/ZdQ2g/VnINn0Bpn+V99xK211ut9hvj+pP6zAVmrqx+c86fuUyOPwBgmLtJdoya9Z5ChWFBUpxgDZiurbYqGWHG1vDjIJSnKdKLRBhRNCmsvXf7lPifdINI8I3UOlRrZJW4m/sbQ46JlozT8Dza62mFCUJaMXSVXxrPdVxq9C06cZiwamtMQw6cnQZxcI0B2R2i65Ct45ohgrJE2g4z+nZRVrpBO9ApgIXQ/sp6jPKfbkSXHFzykdk75Ktwz67Vji7puQOOUUlyeMkaBGvEaq9EZnwOyJ3VxggUaqaH5CtKfYD7lnAM4TbjtLE3SMfZZNviajoNh7ouLeyNLUab/Qd9+MBMbWsTN49BwVlOUHKn9hp56XqRNWIWyrA55jDqL6iicuXtb8Xx//kvkccyUByLEde72oGf2/IRBIAgCvfVXH/hP6wJy1f6XjL0Or6I1qX98gWSGvN9HYObpKNGm/64vtoSpHDC1JWtcuf5ZzlsA4R8XbZKS/Tn0Y9kC89pmPnHYLscWtOFoirIRJ0DXqF/PM3kB4jilEe5Y26cvQK2LaSYcuKX7iL4rWLlVrWIh7EkoFH9Un4f8hruVSbhJMWbN+dXZyNn5BHq/+rASd0pCts3fz05xX4dYlfawDeX74MhFxnKcPZu9pS2hjqDZAPmuqKo/DWWDcsO2wT0R0Fd5k/rwtXFOxQgH07cDVkeIDpLjlT3jBdxQ6X9eDfC/EP+nQv+9WgwKkeG5FXDiIbd1++iS6Mb9V4OHmUowZDopiRFqCD5GeBQTkwEe8w05QJ4Dhdu5a5l1y3CzpS/hGgwr9Sos0QrrVXJI7x6Ah1+U05c4TNHXRe8lBUPJNWUHWBXgKznDKBh1+O+Y+jqKxTyIldTfkfXP/5H13/3Hk='
- }
- };
- 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;
- }
- helper.parseJsonP = function(jsonpStr){
- // 去除JSONP包装,提取纯JSON字符串
- const jsonStr = jsonpStr.replace(/^_aq_88765\((.*)\)$/, '$1');
- // 解析JSON
- try {
- const data = JSON.parse(jsonStr);
-
- // 现在可以访问解析后的数据
- console.log('Status:', data.state);
- console.log('Session:', data.sess);
-
- // 访问验证码配置
- const captchaConfig = data.data.comm_captcha_cfg;
- console.log('TDC Path:', captchaConfig.tdc_path);
-
- // 访问显示信息
- const showInfo = data.data.dyn_show_info;
- console.log('Language:', showInfo.lang);
- console.log('Instruction:', showInfo.instruction);
-
- // 访问背景元素配置
- const bgConfig = showInfo.bg_elem_cfg;
- const img_url_1 = bgConfig.img_url
- // const img_url_1 = showInfo.sprite_url.replace('img_index=0', 'img_index=1');
- const img_url_0 = showInfo.sprite_url
- console.log('Background Size:', bgConfig.size_2d);
-
- // 访问前景元素列表
- showInfo.fg_elem_list.forEach((elem, index) => {
- console.log(`Element ${index + 1}:`, {
- id: elem.id,
- size: elem.size_2d,
- position: elem.init_pos
- });
- });
-
- // 访问绑定配置
- showInfo.fg_binding_list.forEach((binding, index) => {
- console.log(`Binding ${index + 1}:`, {
- master: binding.master,
- slave: binding.slave,
- type: binding.bind_type
- });
- });
- return {img_url_1:img_url_1.match(/image=([^&]+)/)[1],img_url_0:img_url_0.match(/image=([^&]+)/)[1]}
- } catch (error) {
- console.error('Error parsing JSON:', error);
- return null
- }
- }
- helper.generateSign = function(map, appSecret) {
- const keyArray = Object.keys(map).sort();
- const parts = [];
-
- for (const key of keyArray) {
- if (key === 'sign') {
- continue;
- }
-
- const value = map[key];
- if (!value || value.toString().trim().length <= 0) {
- continue;
- }
-
- parts.push(`${key}=${value.toString().trim()}`);
- }
-
- parts.push(`key=${appSecret}`);
- const signStr = parts.join('&');
-
- // Using crypto module for MD5 hash
- const crypto = require('crypto');
- return crypto.createHash('md5')
- .update(signStr)
- .digest('hex')
- .toUpperCase();
- }
- helper.getDate7DaysBefore = function(dateString, inputFormat, outputFormat) {
- const inputDate = new Date(dateString);
-
- if (isNaN(inputDate.getTime())) {
- // 如果默认解析失败,尝试手动解析
- // 这里可以添加更多格式的解析逻辑
- throw new Error('Unsupported date format - consider using moment.js for complex formats');
- }
-
- const date7DaysBefore = new Date(inputDate);
- date7DaysBefore.setDate(date7DaysBefore.getDate() + 0);
-
- // 简单格式化函数
- function formatDate(date, format) {
- if (!format || format.toLowerCase() === 'iso') {
- return date.toISOString();
- }
-
- const pad = num => num.toString().padStart(2, '0');
-
- const year = date.getFullYear();
- const month = pad(date.getMonth() + 1);
- const day = pad(date.getDate());
- const hours = pad(date.getHours());
- const minutes = pad(date.getMinutes());
- const seconds = pad(date.getSeconds());
-
- return format
- .replace('YYYY', year)
- .replace('MM', month)
- .replace('DD', day)
- .replace('HH', hours)
- .replace('mm', minutes)
- .replace('ss', seconds);
- }
-
- return formatDate(date7DaysBefore, outputFormat);
- }
- module.exports = helper;
|