From 90faf39814bedb8d880807b644205302d107790c Mon Sep 17 00:00:00 2001 From: cmliu Date: Thu, 26 Dec 2024 00:24:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...16\346\226\207\346\272\220\347\240\201.js" | 440 +++++++++--------- 1 file changed, 225 insertions(+), 215 deletions(-) diff --git "a/\346\230\216\346\226\207\346\272\220\347\240\201.js" "b/\346\230\216\346\226\207\346\272\220\347\240\201.js" index f78787c1..bb7c6040 100644 --- "a/\346\230\216\346\226\207\346\272\220\347\240\201.js" +++ "b/\346\230\216\346\226\207\346\272\220\347\240\201.js" @@ -3,19 +3,19 @@ import { connect } from "cloudflare:sockets"; let password = ''; let proxyIP = ''; -let sub = ''; +let sub = ''; let subConverter = 'SUBAPI.fxxk.dedyn.io';// clash订阅转换后端,目前使用CM的订阅转换功能。自带虚假节点信息防泄露 let subConfig = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_MultiMode.ini"; //订阅配置文件 let subProtocol = 'https'; let subEmoji = 'true'; let socks5Address = ''; -let parsedSocks5Address = {}; +let parsedSocks5Address = {}; let enableSocks = false; -let fakeUserID ; -let fakeHostName ; +let fakeUserID; +let fakeHostName; const expire = 4102329600;//2099-12-31 -let proxyIPs ; +let proxyIPs; let socks5s; let go2Socks5s = [ '*ttvnw.net', @@ -29,13 +29,13 @@ let addressescsv = []; let DLS = 8; let remarkIndex = 1;//CSV备注所在列偏移量 let FileName = 'epeius'; -let BotToken =''; -let ChatID =''; +let BotToken = ''; +let ChatID = ''; let proxyhosts = []; let proxyhostsURL = ''; let RproxyIP = 'false'; -let httpsPorts = ["2053","2083","2087","2096","8443"]; -let sha224Password ; +let httpsPorts = ["2053", "2083", "2087", "2096", "8443"]; +let sha224Password; const regex = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[.*\]):?(\d+)?#?(.*)?$/; let proxyIPPool = []; let path = '/?ed=2560'; @@ -46,9 +46,9 @@ export default { try { const UA = request.headers.get('User-Agent') || 'null'; const userAgent = UA.toLowerCase(); - password = env.PASSWORD || env.pswd || env.UUID || env.uuid || password; + password = env.PASSWORD || env.pswd || env.UUID || env.uuid || env.TOKEN || password; if (!password) { - return new Response('请设置你的PASSWORD变量,或尝试重试部署,检查变量是否生效?', { + return new Response('请设置你的PASSWORD变量,或尝试重试部署,检查变量是否生效?', { status: 404, headers: { "Content-Type": "text/plain;charset=utf-8", @@ -69,9 +69,9 @@ export default { fakeUserIDMD5.slice(16, 20), fakeUserIDMD5.slice(20) ].join('-'); - + fakeHostName = `${fakeUserIDMD5.slice(6, 9)}.${fakeUserIDMD5.slice(13, 19)}`; - + proxyIP = env.PROXYIP || env.proxyip || proxyIP; proxyIPs = await ADD(proxyIP); proxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)]; @@ -89,7 +89,7 @@ export default { RproxyIP = env.RPROXYIP || 'false'; enableSocks = true; } catch (err) { - /** @type {Error} */ + /** @type {Error} */ let e = err; console.log(e.toString()); RproxyIP = env.RPROXYIP || !proxyIP ? 'true' : 'false'; @@ -108,14 +108,14 @@ export default { DLS = Number(env.DLS) || DLS; remarkIndex = Number(env.CSVREMARK) || remarkIndex; BotToken = env.TGTOKEN || BotToken; - ChatID = env.TGID || ChatID; + ChatID = env.TGID || ChatID; FileName = env.SUBNAME || FileName; subEmoji = env.SUBEMOJI || env.EMOJI || subEmoji; - if(subEmoji == '0') subEmoji = 'false'; - if (env.LINK) link = await ADD(env.LINK) ; + if (subEmoji == '0') subEmoji = 'false'; + if (env.LINK) link = await ADD(env.LINK); sub = env.SUB || sub; subConverter = env.SUBAPI || subConverter; - if (subConverter.includes("http://") ){ + if (subConverter.includes("http://")) { subConverter = subConverter.split("//")[1]; subProtocol = 'http'; } else { @@ -135,65 +135,65 @@ export default { RproxyIP = 'false'; } switch (url.pathname) { - case '/': - if (env.URL302) return Response.redirect(env.URL302, 302); - else if (env.URL) return await proxyURL(env.URL, url); - else return new Response(JSON.stringify(request.cf, null, 4), { - status: 200, - headers: { - 'content-type': 'application/json', - }, - }); - case `/${fakeUserID}`: - const fakeConfig = await get特洛伊Config(password, request.headers.get('Host'), sub, 'CF-Workers-SUB', RproxyIP, url, env); - return new Response(`${fakeConfig}`, { status: 200 }); - case `/${password}/edit`: - const html = await KV(request, env); - return html; - case `/${password}`: - await sendMessage(`#获取订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${UA}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); - const 特洛伊Config = await get特洛伊Config(password, request.headers.get('Host'), sub, UA, RproxyIP, url, env); - const now = Date.now(); - //const timestamp = Math.floor(now / 1000); - const today = new Date(now); - today.setHours(0, 0, 0, 0); - const UD = Math.floor(((now - today.getTime())/86400000) * 24 * 1099511627776 / 2); - let pagesSum = UD; - let workersSum = UD; - let total = 24 * 1099511627776 ; - - if (userAgent && (userAgent.includes('mozilla') || userAgent.includes('subconverter'))){ - return new Response(`
${特洛伊Config}
`, { - status: 200, - headers: { - "Content-Type": "text/html;charset=utf-8", - "Profile-Update-Interval": "6", - "Subscription-Userinfo": `upload=${pagesSum}; download=${workersSum}; total=${total}; expire=${expire}`, - "Cache-Control": "no-store", - } - }); - } else { - return new Response(`${特洛伊Config}`, { + case '/': + if (env.URL302) return Response.redirect(env.URL302, 302); + else if (env.URL) return await proxyURL(env.URL, url); + else return new Response(JSON.stringify(request.cf, null, 4), { status: 200, headers: { - "Content-Disposition": `attachment; filename=${FileName}; filename*=utf-8''${encodeURIComponent(FileName)}`, - "Content-Type": "text/plain;charset=utf-8", - "Profile-Update-Interval": "6", - "Subscription-Userinfo": `upload=${pagesSum}; download=${workersSum}; total=${total}; expire=${expire}`, - } + 'content-type': 'application/json', + }, }); - } - default: - if (env.URL302) return Response.redirect(env.URL302, 302); - else if (env.URL) return await proxyURL(env.URL, url); - else return new Response('不用怀疑!你PASSWORD就是错的!!!', { status: 404 }); + case `/${fakeUserID}`: + const fakeConfig = await get特洛伊Config(password, request.headers.get('Host'), sub, 'CF-Workers-SUB', RproxyIP, url, env); + return new Response(`${fakeConfig}`, { status: 200 }); + case `/${password}/edit`: + const html = await KV(request, env); + return html; + case `/${password}`: + await sendMessage(`#获取订阅 ${FileName}`, request.headers.get('CF-Connecting-IP'), `UA: ${UA}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); + const 特洛伊Config = await get特洛伊Config(password, request.headers.get('Host'), sub, UA, RproxyIP, url, env); + const now = Date.now(); + //const timestamp = Math.floor(now / 1000); + const today = new Date(now); + today.setHours(0, 0, 0, 0); + const UD = Math.floor(((now - today.getTime()) / 86400000) * 24 * 1099511627776 / 2); + let pagesSum = UD; + let workersSum = UD; + let total = 24 * 1099511627776; + + if (userAgent && (userAgent.includes('mozilla') || userAgent.includes('subconverter'))) { + return new Response(`
${特洛伊Config}
`, { + status: 200, + headers: { + "Content-Type": "text/html;charset=utf-8", + "Profile-Update-Interval": "6", + "Subscription-Userinfo": `upload=${pagesSum}; download=${workersSum}; total=${total}; expire=${expire}`, + "Cache-Control": "no-store", + } + }); + } else { + return new Response(`${特洛伊Config}`, { + status: 200, + headers: { + "Content-Disposition": `attachment; filename=${FileName}; filename*=utf-8''${encodeURIComponent(FileName)}`, + "Content-Type": "text/plain;charset=utf-8", + "Profile-Update-Interval": "6", + "Subscription-Userinfo": `upload=${pagesSum}; download=${workersSum}; total=${total}; expire=${expire}`, + } + }); + } + default: + if (env.URL302) return Response.redirect(env.URL302, 302); + else if (env.URL) return await proxyURL(env.URL, url); + else return new Response('不用怀疑!你PASSWORD就是错的!!!', { status: 404 }); } } else { socks5Address = url.searchParams.get('socks5') || socks5Address; if (new RegExp('/socks5=', 'i').test(url.pathname)) socks5Address = url.pathname.split('5=')[1]; else if (new RegExp('/socks://', 'i').test(url.pathname) || new RegExp('/socks5://', 'i').test(url.pathname)) { socks5Address = url.pathname.split('://')[1].split('#')[0]; - if (socks5Address.includes('@')){ + if (socks5Address.includes('@')) { let userPassword = socks5Address.split('@')[0]; const base64Regex = /^(?:[A-Z0-9+/]{4})*(?:[A-Z0-9+/]{2}==|[A-Z0-9+/]{3}=)?$/i; if (base64Regex.test(userPassword) && !userPassword.includes(':')) userPassword = atob(userPassword); @@ -206,7 +206,7 @@ export default { parsedSocks5Address = socks5AddressParser(socks5Address); enableSocks = true; } catch (err) { - /** @type {Error} */ + /** @type {Error} */ let e = err; console.log(e.toString()); enableSocks = false; @@ -215,7 +215,7 @@ export default { enableSocks = false; } - if (url.searchParams.has('proxyip')){ + if (url.searchParams.has('proxyip')) { proxyIP = url.searchParams.get('proxyip'); enableSocks = false; } else if (new RegExp('/proxyip=', 'i').test(url.pathname)) { @@ -348,35 +348,35 @@ async function parse特洛伊Header(buffer) { let addressIndex = 2; let address = ""; switch (atype) { - case 1: - addressLength = 4; - address = new Uint8Array( - socks5DataBuffer.slice(addressIndex, addressIndex + addressLength) - ).join("."); - break; - case 3: - addressLength = new Uint8Array( - socks5DataBuffer.slice(addressIndex, addressIndex + 1) - )[0]; - addressIndex += 1; - address = new TextDecoder().decode( - socks5DataBuffer.slice(addressIndex, addressIndex + addressLength) - ); - break; - case 4: - addressLength = 16; - const dataView = new DataView(socks5DataBuffer.slice(addressIndex, addressIndex + addressLength)); - const ipv6 = []; - for (let i = 0; i < 8; i++) { - ipv6.push(dataView.getUint16(i * 2).toString(16)); - } - address = ipv6.join(":"); - break; - default: - return { - hasError: true, - message: `invalid addressType is ${atype}` - }; + case 1: + addressLength = 4; + address = new Uint8Array( + socks5DataBuffer.slice(addressIndex, addressIndex + addressLength) + ).join("."); + break; + case 3: + addressLength = new Uint8Array( + socks5DataBuffer.slice(addressIndex, addressIndex + 1) + )[0]; + addressIndex += 1; + address = new TextDecoder().decode( + socks5DataBuffer.slice(addressIndex, addressIndex + addressLength) + ); + break; + case 4: + addressLength = 16; + const dataView = new DataView(socks5DataBuffer.slice(addressIndex, addressIndex + addressLength)); + const ipv6 = []; + for (let i = 0; i < 8; i++) { + ipv6.push(dataView.getUint16(i * 2).toString(16)); + } + address = ipv6.join(":"); + break; + default: + return { + hasError: true, + message: `invalid addressType is ${atype}` + }; } if (!address) { @@ -400,7 +400,7 @@ async function parse特洛伊Header(buffer) { async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, log, addressType) { async function useSocks5Pattern(address) { - if ( go2Socks5s.includes(atob('YWxsIGlu')) || go2Socks5s.includes(atob('Kg==')) ) return true; + if (go2Socks5s.includes(atob('YWxsIGlu')) || go2Socks5s.includes(atob('Kg=='))) return true; return go2Socks5s.some(pattern => { let regexPattern = pattern.replace(/\*/g, '.*'); let regex = new RegExp(`^${regexPattern}$`, 'i'); @@ -411,10 +411,10 @@ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawCli log(`connected to ${address}:${port}`); //if (/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(address)) address = `${atob('d3d3Lg==')}${address}${atob('LmlwLjA5MDIyNy54eXo=')}`; const tcpSocket = socks ? await socks5Connect(addressType, address, port, log) - : connect({ - hostname: address, - port - }); + : connect({ + hostname: address, + port + }); remoteSocket.value = tcpSocket; //log(`connected to ${address}:${port}`); const writer = tcpSocket.writable.getWriter(); @@ -446,7 +446,7 @@ async function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawCli remoteSocketToWS(tcpSocket, webSocket, null, log); } let useSocks = false; - if (go2Socks5s.length > 0 && enableSocks ) useSocks = await useSocks5Pattern(addressRemote); + if (go2Socks5s.length > 0 && enableSocks) useSocks = await useSocks5Pattern(addressRemote); let tcpSocket = await connectAndWrite(addressRemote, portRemote, useSocks); remoteSocketToWS(tcpSocket, webSocket, retry, log); } @@ -480,7 +480,7 @@ function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) { controller.enqueue(earlyData); } }, - pull(controller) {}, + pull(controller) { }, cancel(reason) { if (readableStreamCancel) { return; @@ -497,7 +497,7 @@ async function remoteSocketToWS(remoteSocket, webSocket, retry, log) { let hasIncomingData = false; await remoteSocket.readable.pipeTo( new WritableStream({ - start() {}, + start() { }, /** * * @param {Uint8Array} chunk @@ -583,7 +583,7 @@ function revertFakeInfo(content, userID, hostName, isBase64) { 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(''); @@ -591,7 +591,7 @@ 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(); } @@ -599,14 +599,14 @@ async function ADD(内容) { // 将制表符、双引号、单引号和换行符都替换为逗号 // 然后将连续的多个逗号替换为单个逗号 var 替换后的内容 = 内容.replace(/[ |"'\r\n]+/g, ',').replace(/,+/g, ','); - + // 删除开头和结尾的逗号(如果有的话) if (替换后的内容.charAt(0) == ',') 替换后的内容 = 替换后的内容.slice(1); if (替换后的内容.charAt(替换后的内容.length - 1) == ',') 替换后的内容 = 替换后的内容.slice(0, 替换后的内容.length - 1); - + // 使用逗号分割字符串,得到地址数组 const 地址数组 = 替换后的内容.split(','); - + return 地址数组; } @@ -646,26 +646,26 @@ async function proxyURL(proxyURL, url) { function 配置信息(密码, 域名地址) { const 啥啥啥_写的这是啥啊 = 'dHJvamFu'; const 协议类型 = atob(啥啥啥_写的这是啥啊); - + const 别名 = FileName; let 地址 = 域名地址; let 端口 = 443; - + const 传输层协议 = 'ws'; const 伪装域名 = 域名地址; const 路径 = path; - - let 传输层安全 = ['tls',true]; + + let 传输层安全 = ['tls', true]; const SNI = 域名地址; const 指纹 = 'randomized'; - - const v2ray = `${协议类型}://${encodeURIComponent(密码)}@${地址}:${端口}?security=${传输层安全[0]}&sni=${SNI}&alpn=h3&fp=${指纹}&allowInsecure=1&type=${传输层协议}&host=${伪装域名}&path=${encodeURIComponent(路径)}#${encodeURIComponent(别名)}` + + const v2ray = `${协议类型}://${encodeURIComponent(密码)}@${地址}:${端口}?security=${传输层安全[0]}&sni=${SNI}&alpn=h3&fp=${指纹}&allowInsecure=1&type=${传输层协议}&host=${伪装域名}&path=${encodeURIComponent(路径)}#${encodeURIComponent(别名)}` const clash = `- {name: ${别名}, server: ${地址}, port: ${端口}, udp: false, client-fingerprint: ${指纹}, type: ${协议类型}, password: ${密码}, sni: ${SNI}, alpn: [h3], skip-cert-verify: true, network: ${传输层协议}, ws-opts: {path: "${路径}", headers: {Host: ${伪装域名}}}}`; - return [v2ray,clash]; + return [v2ray, clash]; } -let subParams = ['sub','base64','b64','clash','singbox','sb','surge']; +let subParams = ['sub', 'base64', 'b64', 'clash', 'singbox', 'sb', 'surge']; const cmad = decodeURIComponent(atob(`dGVsZWdyYW0lMjAlRTQlQkElQTQlRTYlQjUlODElRTclQkUlQTQlMjAlRTYlOEElODAlRTYlOUMlQUYlRTUlQTQlQTclRTQlQkQlQUMlN0UlRTUlOUMlQTglRTclQkElQkYlRTUlOEYlOTElRTclODklOEMhJTNDYnIlM0UKJTNDYSUyMGhyZWYlM0QlMjdodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlMjclM0VodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlM0MlMkZhJTNFJTNDYnIlM0UKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJTNDYnIlM0UKZ2l0aHViJTIwJUU5JUExJUI5JUU3JTlCJUFFJUU1JTlDJUIwJUU1JTlEJTgwJTIwU3RhciFTdGFyIVN0YXIhISElM0NiciUzRQolM0NhJTIwaHJlZiUzRCUyN2h0dHBzJTNBJTJGJTJGZ2l0aHViLmNvbSUyRmNtbGl1JTJGZXBlaXVzJTI3JTNFaHR0cHMlM0ElMkYlMkZnaXRodWIuY29tJTJGY21saXUlMkZlcGVpdXMlM0MlMkZhJTNFJTNDYnIlM0UKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJTNDYnIlM0UKJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIzJTIz`)); async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, env) { if (sub) { @@ -676,7 +676,7 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e const subs = await ADD(sub); if (subs.length > 1) sub = subs[0]; } else { - if (env.KV){ + if (env.KV) { await 迁移地址列表(env); const 优选地址列表 = await env.KV.get('ADD.txt'); if (优选地址列表) { @@ -686,7 +686,7 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e 链接地址: new Set(), 优选地址: new Set() }; - + for (const 元素 of 优选地址数组) { if (元素.startsWith('https://')) { 分类地址.接口地址.add(元素); @@ -696,14 +696,14 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e 分类地址.优选地址.add(元素); } } - + addressesapi = [...分类地址.接口地址]; link = [...分类地址.链接地址]; addresses = [...分类地址.优选地址]; } } - if ((addresses.length + addressesapi.length + addressescsv.length) == 0){ + if ((addresses.length + addressesapi.length + addressescsv.length) == 0) { // 定义 Cloudflare IP 范围的 CIDR 列表 let cfips = [ '103.21.244.0/23', @@ -718,7 +718,7 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e '188.114.96.0/21', '190.93.240.0/21', ]; - + // 生成符合给定 CIDR 范围的随机 IP 地址 function generateRandomIPFromCIDR(cidr) { const [base, mask] = cidr.split('/'); @@ -726,13 +726,13 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e const subnetMask = 32 - parseInt(mask, 10); const maxHosts = Math.pow(2, subnetMask) - 1; const randomHost = Math.floor(Math.random() * maxHosts); - + const randomIP = baseIP.map((octet, index) => { if (index < 2) return octet; if (index === 2) return (octet & (255 << (subnetMask - 8))) + ((randomHost >> 8) & 255); return (octet & (255 << subnetMask)) + (randomHost & 255); }); - + return randomIP.join('.'); } addresses = addresses.concat('127.0.0.1:1234#CFnat'); @@ -741,35 +741,35 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e } const userAgent = UA.toLowerCase(); - const Config = 配置信息(password , hostName); + const Config = 配置信息(password, hostName); const v2ray = Config[0]; const clash = Config[1]; let proxyhost = ""; - if (hostName.includes(".workers.dev")){ - if ( proxyhostsURL && (!proxyhosts || proxyhosts.length == 0)) { + if (hostName.includes(".workers.dev")) { + if (proxyhostsURL && (!proxyhosts || proxyhosts.length == 0)) { try { - const response = await fetch(proxyhostsURL); - + const response = await fetch(proxyhostsURL); + if (!response.ok) { console.error('获取地址时出错:', response.status, response.statusText); return; // 如果有错误,直接返回 } - + const text = await response.text(); const lines = text.split('\n'); // 过滤掉空行或只包含空白字符的行 const nonEmptyLines = lines.filter(line => line.trim() !== ''); - + proxyhosts = proxyhosts.concat(nonEmptyLines); } catch (error) { //console.error('获取地址时出错:', error); } - } + } if (proxyhosts.length != 0) proxyhost = proxyhosts[Math.floor(Math.random() * proxyhosts.length)] + "/"; } - - if ( userAgent.includes('mozilla') && !subParams.some(_searchParams => _url.searchParams.has(_searchParams))) { - let surge = `Surge订阅地址:
https://${proxyhost}${hostName}/${password}?surge`; + + if (userAgent.includes('mozilla') && !subParams.some(_searchParams => _url.searchParams.has(_searchParams))) { + let surge = `Surge订阅地址:
https://${proxyhost}${hostName}/${password}?surge
`; if (hostName.includes(".workers.dev")) surge = "Surge订阅必须绑定自定义域"; const newSocks5s = socks5s.map(socks5Address => { if (socks5Address.includes('@')) return socks5Address.split('@')[1]; @@ -778,9 +778,9 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e }); let socks5List = ''; - if (go2Socks5s.length > 0 && enableSocks ) { + if (go2Socks5s.length > 0 && enableSocks) { socks5List = `${decodeURIComponent('SOCKS5%EF%BC%88%E7%99%BD%E5%90%8D%E5%8D%95%EF%BC%89%3A%20')}`; - if ( go2Socks5s.includes(atob('YWxsIGlu')) || go2Socks5s.includes(atob('Kg==')) ) socks5List += `${decodeURIComponent('%E6%89%80%E6%9C%89%E6%B5%81%E9%87%8F')}
`; + if (go2Socks5s.includes(atob('YWxsIGlu')) || go2Socks5s.includes(atob('Kg=='))) socks5List += `${decodeURIComponent('%E6%89%80%E6%9C%89%E6%B5%81%E9%87%8F')}
`; else socks5List += `
  ${go2Socks5s.join('
  ')}
`; } @@ -805,25 +805,21 @@ async function get特洛伊Config(password, hostName, sub, UA, RproxyIP, _url, e const 节点配置页 = ` ################################################################
- Subscribe / sub 订阅地址, 支持 Base64、clash-meta、sing-box 订阅格式
+ Subscribe / sub 订阅地址, 点击链接自动 复制订阅链接生成订阅二维码
---------------------------------------------------------------
自适应订阅地址:
- https://${proxyhost}${hostName}/${password}
- https://${proxyhost}${hostName}/${password}?sub
-
+ https://${proxyhost}${hostName}/${password}
+
Base64订阅地址:
- https://${proxyhost}${hostName}/${password}?b64
- https://${proxyhost}${hostName}/${password}?base64
-
+ https://${proxyhost}${hostName}/${password}?b64
+
clash订阅地址:
- https://${proxyhost}${hostName}/${password}?clash
-
+ https://${proxyhost}${hostName}/${password}?clash
+
singbox订阅地址:
- https://${proxyhost}${hostName}/${password}?sb
- https://${proxyhost}${hostName}/${password}?singbox
-
- ${surge}
-
+ https://${proxyhost}${hostName}/${password}?sb
+
+ ${surge} 实用订阅技巧∨
+