From 3ca6ccb45ad55801e51ef832f1e444883c2678ef Mon Sep 17 00:00:00 2001 From: cmliu Date: Fri, 27 Dec 2024 21:20:27 +0800 Subject: [PATCH] debug --- README.md | 4 +- _worker.js | 154 ++++++++++++++++++++++++++--------------------------- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 217ca5b..ed4ace9 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ - 添加 `TOKEN` 变量,快速订阅访问入口,默认值为: `auto` ,获取订阅器默认节点订阅地址即 `/auto` ,例如 `https://sub.fuck.cloudns.biz/auto` ### 4. 添加你的节点和订阅链接: - 1. 绑定名为`KV`的KV空间; + 1. 绑定**变量名称**为`KV`的**KV命名空间**; 2. 访问 `https://sub.fuck.cloudns.biz/auto`,添加你的自建节点链接和机场订阅链接,确保每行一个链接,例如: ``` vless://b7a392e2-4ef0-4496-90bc-1c37bb234904@cf.090227.xyz:443?encryption=none&security=tls&sni=edgetunnel-2z2.pages.dev&fp=random&type=ws&host=edgetunnel-2z2.pages.dev&path=%2F%3Fed%3D2048#%E5%8A%A0%E5%85%A5%E6%88%91%E7%9A%84%E9%A2%91%E9%81%93t.me%2FCMLiussss%E8%A7%A3%E9%94%81%E6%9B%B4%E5%A4%9A%E4%BC%98%E9%80%89%E8%8A%82%E7%82%B9 @@ -53,7 +53,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ ### 3. 添加你的节点或订阅链接: - 1. 绑定名为`KV`的KV空间; + 1. 绑定**变量名称**为`KV`的**KV命名空间**; 2. 访问 `https://sub.cmliussss.workers.dev/auto`,添加你的自建节点链接和机场订阅链接,确保每行一个链接,例如: ``` vless://b7a392e2-4ef0-4496-90bc-1c37bb234904@cf.090227.xyz:443?encryption=none&security=tls&sni=edgetunnel-2z2.pages.dev&fp=random&type=ws&host=edgetunnel-2z2.pages.dev&path=%2F%3Fed%3D2048#%E5%8A%A0%E5%85%A5%E6%88%91%E7%9A%84%E9%A2%91%E9%81%93t.me%2FCMLiussss%E8%A7%A3%E9%94%81%E6%9B%B4%E5%A4%9A%E4%BC%98%E9%80%89%E8%8A%82%E7%82%B9 diff --git a/_worker.js b/_worker.js index eb0136b..0310600 100644 --- a/_worker.js +++ b/_worker.js @@ -2,8 +2,8 @@ // 部署完成后在网址后面加上这个,获取自建节点和机场聚合节点,/?token=auto或/auto或 let mytoken = 'auto'; //可以随便取,或者uuid生成,https://1024tools.com/uuid -let BotToken =''; //可以为空,或者@BotFather中输入/start,/newbot,并关注机器人 -let ChatID =''; //可以为空,或者@userinfobot中获取,/start +let BotToken = ''; //可以为空,或者@BotFather中输入/start,/newbot,并关注机器人 +let ChatID = ''; //可以为空,或者@userinfobot中获取,/start let TG = 0; //小白勿动, 开发者专用,1 为推送所有的访问信息,0 为不推送订阅转换后端的访问信息与异常访问 let FileName = 'CF-Workers-SUB'; let SUBUpdateTime = 6; //自定义订阅更新时间,单位小时 @@ -22,17 +22,17 @@ let subConfig = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/conf let subProtocol = 'https'; export default { - async fetch (request,env) { + async fetch(request, env) { const userAgentHeader = request.headers.get('User-Agent'); const userAgent = userAgentHeader ? userAgentHeader.toLowerCase() : "null"; const url = new URL(request.url); const token = url.searchParams.get('token'); mytoken = env.TOKEN || mytoken; BotToken = env.TGTOKEN || BotToken; - ChatID = env.TGID || ChatID; - TG = env.TG || TG; + ChatID = env.TGID || ChatID; + TG = env.TG || TG; subConverter = env.SUBAPI || subConverter; - if( subConverter.includes("http://") ){ + if (subConverter.includes("http://")) { subConverter = subConverter.split("//")[1]; subProtocol = 'http'; } else { @@ -42,22 +42,22 @@ export default { FileName = env.SUBNAME || FileName; const currentDate = new Date(); - currentDate.setHours(0, 0, 0, 0); + currentDate.setHours(0, 0, 0, 0); const timeTemp = Math.ceil(currentDate.getTime() / 1000); const fakeToken = await MD5MD5(`${mytoken}${timeTemp}`); //console.log(`${fakeUserID}\n${fakeHostName}`); // 打印fakeID - let UD = Math.floor(((timestamp - Date.now())/timestamp * total * 1099511627776 )/2); - total = total * 1099511627776 ; - let expire= Math.floor(timestamp / 1000) ; + let UD = Math.floor(((timestamp - Date.now()) / timestamp * total * 1099511627776) / 2); + total = total * 1099511627776; + let expire = Math.floor(timestamp / 1000); SUBUpdateTime = env.SUBUPTIME || SUBUpdateTime; - if ( !(token == mytoken || token == fakeToken || url.pathname == ("/"+ mytoken) || url.pathname.includes("/"+ mytoken + "?")) ) { - if ( TG == 1 && url.pathname !== "/" && url.pathname !== "/favicon.ico" ) await sendMessage(`#异常访问 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgent}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); + if (!(token == mytoken || token == fakeToken || url.pathname == ("/" + mytoken) || url.pathname.includes("/" + mytoken + "?"))) { + if (TG == 1 && url.pathname !== "/" && url.pathname !== "/favicon.ico") await sendMessage(`#异常访问 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgent}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); if (env.URL302) return Response.redirect(env.URL302, 302); else if (env.URL) return await proxyURL(env.URL, url); - else return new Response(await nginx(), { - status: 200 , + else return new Response(await nginx(), { + status: 200, headers: { 'Content-Type': 'text/html; charset=UTF-8', }, @@ -65,7 +65,7 @@ export default { } else { if (env.KV) { await 迁移地址列表(env, 'LINK.txt'); - if (userAgent.includes('mozilla') && !url.search){ + if (userAgent.includes('mozilla') && !url.search) { await sendMessage(`#编辑订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgentHeader}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); return await KV(request, env, 'LINK.txt'); } else { @@ -76,8 +76,8 @@ export default { if (env.LINKSUB) urls = await ADD(env.LINKSUB); } let 重新汇总所有链接 = await ADD(MainData + '\n' + urls.join('\n')); - let 自建节点 =""; - let 订阅链接 =""; + let 自建节点 = ""; + let 订阅链接 = ""; for (let x of 重新汇总所有链接) { if (x.toLowerCase().startsWith('http')) { 订阅链接 += x + '\n'; @@ -90,38 +90,38 @@ export default { await sendMessage(`#获取订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${userAgentHeader}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); let 订阅格式 = 'base64'; - if (userAgent.includes('null') || userAgent.includes('subconverter') || userAgent.includes('nekobox') || userAgent.includes(('CF-Workers-SUB').toLowerCase())){ + if (userAgent.includes('null') || userAgent.includes('subconverter') || userAgent.includes('nekobox') || userAgent.includes(('CF-Workers-SUB').toLowerCase())) { 订阅格式 = 'base64'; - } else if (userAgent.includes('clash') || ( url.searchParams.has('clash') && !userAgent.includes('subconverter'))){ + } else if (userAgent.includes('clash') || (url.searchParams.has('clash') && !userAgent.includes('subconverter'))) { 订阅格式 = 'clash'; - } else if (userAgent.includes('sing-box') || userAgent.includes('singbox') || ( (url.searchParams.has('sb') || url.searchParams.has('singbox')) && !userAgent.includes('subconverter'))){ + } else if (userAgent.includes('sing-box') || userAgent.includes('singbox') || ((url.searchParams.has('sb') || url.searchParams.has('singbox')) && !userAgent.includes('subconverter'))) { 订阅格式 = 'singbox'; - } else if (userAgent.includes('surge') || ( url.searchParams.has('surge') && !userAgent.includes('subconverter'))){ + } else if (userAgent.includes('surge') || (url.searchParams.has('surge') && !userAgent.includes('subconverter'))) { 订阅格式 = 'surge'; - } else if (userAgent.includes('quantumult%20x') || (url.searchParams.has('quanx') && !userAgent.includes('subconverter'))){ + } else if (userAgent.includes('quantumult%20x') || (url.searchParams.has('quanx') && !userAgent.includes('subconverter'))) { 订阅格式 = 'quanx'; - } else if (userAgent.includes('loon') || (url.searchParams.has('loon') && !userAgent.includes('subconverter'))){ + } else if (userAgent.includes('loon') || (url.searchParams.has('loon') && !userAgent.includes('subconverter'))) { 订阅格式 = 'loon'; } - let subConverterUrl ; + let subConverterUrl; let 订阅转换URL = `${url.origin}/${await MD5MD5(fakeToken)}?token=${fakeToken}`; //console.log(订阅转换URL); let req_data = MainData; let 追加UA = 'v2rayn'; if (url.searchParams.has('clash')) 追加UA = 'clash'; - else if(url.searchParams.has('singbox')) 追加UA = 'singbox'; - else if(url.searchParams.has('surge')) 追加UA = 'surge'; - else if(url.searchParams.has('quanx')) 追加UA = 'Quantumult%20X'; - else if(url.searchParams.has('loon')) 追加UA = 'Loon'; - - const 请求订阅响应内容 = await getSUB(urls ,request ,追加UA, userAgentHeader); + else if (url.searchParams.has('singbox')) 追加UA = 'singbox'; + else if (url.searchParams.has('surge')) 追加UA = 'surge'; + else if (url.searchParams.has('quanx')) 追加UA = 'Quantumult%20X'; + else if (url.searchParams.has('loon')) 追加UA = 'Loon'; + + const 请求订阅响应内容 = await getSUB(urls, request, 追加UA, userAgentHeader); console.log(请求订阅响应内容); req_data += 请求订阅响应内容[0].join('\n'); 订阅转换URL += "|" + 请求订阅响应内容[1]; - if(env.WARP) 订阅转换URL += "|" + (await ADD(env.WARP)).join("|"); + if (env.WARP) 订阅转换URL += "|" + (await ADD(env.WARP)).join("|"); //修复中文错误 const utf8Encoder = new TextEncoder(); const encodedData = utf8Encoder.encode(req_data); @@ -133,7 +133,7 @@ export default { const uniqueLines = new Set(text.split('\n')); const result = [...uniqueLines].join('\n'); //console.log(result); - + let base64Data; try { base64Data = btoa(result); @@ -142,51 +142,51 @@ export default { const binary = new TextEncoder().encode(data); let base64 = ''; const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - + for (let i = 0; i < binary.length; i += 3) { const byte1 = binary[i]; const byte2 = binary[i + 1] || 0; const byte3 = binary[i + 2] || 0; - + base64 += chars[byte1 >> 2]; base64 += chars[((byte1 & 3) << 4) | (byte2 >> 4)]; base64 += chars[((byte2 & 15) << 2) | (byte3 >> 6)]; base64 += chars[byte3 & 63]; } - + const padding = 3 - (binary.length % 3 || 3); return base64.slice(0, base64.length - padding) + '=='.slice(0, padding); } - + base64Data = encodeBase64(result); } - if (订阅格式 == 'base64' || token == fakeToken){ - return new Response(base64Data ,{ - headers: { + if (订阅格式 == 'base64' || token == fakeToken) { + return new Response(base64Data, { + headers: { "content-type": "text/plain; charset=utf-8", "Profile-Update-Interval": `${SUBUpdateTime}`, "Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, } }); - } else if (订阅格式 == 'clash'){ + } else if (订阅格式 == 'clash') { subConverterUrl = `${subProtocol}://${subConverter}/sub?target=clash&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; - } else if (订阅格式 == 'singbox'){ + } else if (订阅格式 == 'singbox') { subConverterUrl = `${subProtocol}://${subConverter}/sub?target=singbox&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; - } else if (订阅格式 == 'surge'){ + } else if (订阅格式 == 'surge') { subConverterUrl = `${subProtocol}://${subConverter}/sub?target=surge&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; - } else if (订阅格式 == 'quanx'){ + } else if (订阅格式 == 'quanx') { subConverterUrl = `${subProtocol}://${subConverter}/sub?target=quanx&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&udp=true`; - } else if (订阅格式 == 'loon'){ + } else if (订阅格式 == 'loon') { subConverterUrl = `${subProtocol}://${subConverter}/sub?target=loon&url=${encodeURIComponent(订阅转换URL)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false`; } //console.log(订阅转换URL); try { const subConverterResponse = await fetch(subConverterUrl); - + if (!subConverterResponse.ok) { - return new Response(base64Data ,{ - headers: { + return new Response(base64Data, { + headers: { "content-type": "text/plain; charset=utf-8", "Profile-Update-Interval": `${SUBUpdateTime}`, "Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, @@ -195,22 +195,22 @@ export default { //throw new Error(`Error fetching subConverterUrl: ${subConverterResponse.status} ${subConverterResponse.statusText}`); } let subConverterContent = await subConverterResponse.text(); - if (订阅格式 == 'clash') subConverterContent =await clashFix(subConverterContent); + if (订阅格式 == 'clash') subConverterContent = await clashFix(subConverterContent); return new Response(subConverterContent, { - headers: { + headers: { "Content-Disposition": `attachment; filename*=utf-8''${encodeURIComponent(FileName)}; filename=${FileName}`, "content-type": "text/plain; charset=utf-8", "Profile-Update-Interval": `${SUBUpdateTime}`, - "Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, + //"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, }, }); } catch (error) { - return new Response(base64Data ,{ - headers: { + return new Response(base64Data, { + headers: { "content-type": "text/plain; charset=utf-8", "Profile-Update-Interval": `${SUBUpdateTime}`, - "Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, + //"Subscription-Userinfo": `upload=${UD}; download=${UD}; total=${total}; expire=${expire}`, } }); } @@ -222,10 +222,10 @@ async function ADD(envadd) { var addtext = envadd.replace(/[ "'|\r\n]+/g, ',').replace(/,+/g, ','); // 将空格、双引号、单引号和换行符替换为逗号 //console.log(addtext); if (addtext.charAt(0) == ',') addtext = addtext.slice(1); - if (addtext.charAt(addtext.length -1) == ',') addtext = addtext.slice(0, addtext.length - 1); + if (addtext.charAt(addtext.length - 1) == ',') addtext = addtext.slice(0, addtext.length - 1); const add = addtext.split(','); //console.log(add); - return add ; + return add; } async function nginx() { @@ -256,11 +256,11 @@ async function nginx() { ` - return text ; + return text; } async function sendMessage(type, ip, add_data = "") { - if ( BotToken !== '' && ChatID !== ''){ + if (BotToken !== '' && ChatID !== '') { let msg = ""; const response = await fetch(`http://ip-api.com/json/${ip}?lang=zh-CN`); if (response.status == 200) { @@ -269,8 +269,8 @@ async function sendMessage(type, ip, add_data = "") { } else { msg = `${type}\nIP: ${ip}\n${add_data}`; } - - let url = "https://api.telegram.org/bot"+ BotToken +"/sendMessage?chat_id=" + ChatID + "&parse_mode=HTML&text=" + encodeURIComponent(msg); + + let url = "https://api.telegram.org/bot" + BotToken + "/sendMessage?chat_id=" + ChatID + "&parse_mode=HTML&text=" + encodeURIComponent(msg); return fetch(url, { method: 'get', headers: { @@ -290,7 +290,7 @@ function base64Decode(str) { async function MD5MD5(text) { const encoder = new TextEncoder(); - + const firstPass = await crypto.subtle.digest('MD5', encoder.encode(text)); const firstPassArray = Array.from(new Uint8Array(firstPass)); const firstHex = firstPassArray.map(b => b.toString(16).padStart(2, '0')).join(''); @@ -298,19 +298,19 @@ async function MD5MD5(text) { const secondPass = await crypto.subtle.digest('MD5', encoder.encode(firstHex.slice(7, 27))); const secondPassArray = Array.from(new Uint8Array(secondPass)); const secondHex = secondPassArray.map(b => b.toString(16).padStart(2, '0')).join(''); - + return secondHex.toLowerCase(); } function clashFix(content) { - if(content.includes('wireguard') && !content.includes('remote-dns-resolve')){ + if (content.includes('wireguard') && !content.includes('remote-dns-resolve')) { let lines; - if (content.includes('\r\n')){ + if (content.includes('\r\n')) { lines = content.split('\r\n'); } else { lines = content.split('\n'); } - + let result = ""; for (let line of lines) { if (line.includes('type: wireguard')) { @@ -421,7 +421,7 @@ async function getSUB(api, request, 追加UA, userAgentHeader) { 订阅转换URLs += "|" + response.apiUrl; // Singbox 配置 } else if (content.includes('://')) { newapi += content + '\n'; // 追加内容 - } else if (isValidBase64(content)){ + } else if (isValidBase64(content)) { newapi += base64Decode(content) + '\n'; // 解码并追加内容 } else { const 异常订阅LINK = `trojan://CMLiussss@127.0.0.1:8888?security=tls&allowInsecure=1&type=tcp&headerType=none#%E5%BC%82%E5%B8%B8%E8%AE%A2%E9%98%85%20${response.apiUrl.split('://')[1].split('/')[0]}`; @@ -472,7 +472,7 @@ function isValidBase64(str) { async function 迁移地址列表(env, txt = 'ADD.txt') { const 旧数据 = await env.KV.get(`/${txt}`); const 新数据 = await env.KV.get(txt); - + if (旧数据 && !新数据) { // 写入新位置 await env.KV.put(txt, 旧数据); @@ -498,11 +498,11 @@ async function KV(request, env, txt = 'ADD.txt') { return new Response("保存失败: " + error.message, { status: 500 }); } } - + // GET请求部分 let content = ''; let hasKV = !!env.KV; - + if (hasKV) { try { content = await env.KV.get(txt) || ''; @@ -511,7 +511,7 @@ async function KV(request, env, txt = 'ADD.txt') { content = '读取数据时发生错误: ' + error.message; } } - + const html = ` @@ -577,10 +577,10 @@ async function KV(request, env, txt = 'ADD.txt') { ################################################################
- Subscribe / sub 订阅地址, 支持 Base64、clash-meta、sing-box 订阅格式
+ Subscribe / sub 订阅地址, 点击链接自动 复制订阅链接生成订阅二维码
---------------------------------------------------------------
自适应订阅地址:
- https://${url.hostname}/${mytoken}
+ https://${url.hostname}/${mytoken}
Base64订阅地址:
https://${url.hostname}/${mytoken}?b64
@@ -601,8 +601,8 @@ async function KV(request, env, txt = 'ADD.txt') { ################################################################
订阅转换配置
---------------------------------------------------------------
- SUBAPI(订阅转换后端): ${subProtocol}://${subConverter}
- SUBCONFIG(订阅转换配置文件): ${subConfig}
+ SUBAPI(订阅转换后端): ${subProtocol}://${subConverter}
+ SUBCONFIG(订阅转换配置文件): ${subConfig}
---------------------------------------------------------------
################################################################
${FileName} 汇聚订阅编辑: @@ -615,12 +615,12 @@ async function KV(request, env, txt = 'ADD.txt') { - ` : '

未绑定KV空间

'} + ` : '

请绑定 变量名称KV 的KV命名空间

'}
################################################################
${decodeURIComponent(atob('dGVsZWdyYW0lMjAlRTQlQkElQTQlRTYlQjUlODElRTclQkUlQTQlMjAlRTYlOEElODAlRTYlOUMlQUYlRTUlQTQlQTclRTQlQkQlQUMlN0UlRTUlOUMlQTglRTclQkElQkYlRTUlOEYlOTElRTclODklOEMhJTNDYnIlM0UKJTNDYSUyMGhyZWYlM0QlMjdodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlMjclM0VodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlM0MlMkZhJTNFJTNDYnIlM0UKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJTNDYnIlM0UKZ2l0aHViJTIwJUU5JUExJUI5JUU3JTlCJUFFJUU1JTlDJUIwJUU1JTlEJTgwJTIwU3RhciFTdGFyIVN0YXIhISElM0NiciUzRQolM0NhJTIwaHJlZiUzRCUyN2h0dHBzJTNBJTJGJTJGZ2l0aHViLmNvbSUyRmNtbGl1JTJGQ0YtV29ya2Vycy1TVUIlMjclM0VodHRwcyUzQSUyRiUyRmdpdGh1Yi5jb20lMkZjbWxpdSUyRkNGLVdvcmtlcnMtU1VCJTNDJTJGYSUzRSUzQ2JyJTNFCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSUzQ2JyJTNFCiUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMyUyMw=='))} -

UA: ${request.headers.get('User-Agent')} +

UA: ${request.headers.get('User-Agent')}