diff --git a/README.md b/README.md index daba05779..afb3acf7a 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ - 通过提交虚假的节点配置给订阅服务,避免节点配置信息泄露。 - 另外,您也可以选择自行部署 [WorkerVless2sub 订阅生成服务](https://github.com/cmliu/WorkerVless2sub),这样既可以利用订阅生成器的便利。 +# 如何使用? ## Workers 部署方法 [视频教程](https://www.youtube.com/watch?v=LeT4jQUh8ok&t=83s)
@@ -41,7 +42,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ 1. 部署 CF Worker: - 在 CF Worker 控制台中创建一个新的 Worker。 - 将 [worker.js](https://github.com/cmliu/edgetunnel/blob/main/_worker.js) 的内容粘贴到 Worker 编辑器中。 - - 将第 7 行 `userID` 修改成你自己的 **UUID** 。 + - 将第 4 行 `userID` 修改成你自己的 **UUID** 。 2. 访问订阅内容: - 访问 `https://[YOUR-WORKERS-URL]/[UUID]` 即可获取订阅内容。 @@ -132,6 +133,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ
# 变量说明 + | 变量名 | 示例 | 必填 | 备注 | YT | |--------|---------|-|-----|-----| | UUID | `90cd4a77-141a-43c9-991b-08263cfe9c10` |✅| Powershell -NoExit -Command "[guid]::NewGuid()"| [Video](https://www.youtube.com/watch?v=s91zjpw3-P8&t=72s) | @@ -149,37 +151,69 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ | DLS | `8` |❌| `ADDCSV`测速结果满足速度下限 || | TGTOKEN | `6894123456:XXXXXXXXXX0qExVsBPUhHDAbXXX` |❌| 发送TG通知的机器人token | | TGID | `6946912345` |❌| 接收TG通知的账户数字ID | -| SUB | `VLESS.fxxk.dedyn.io` | ❌ | 内建域名、IP节点信息的订阅生成器地址 | [Video](https://www.youtube.com/watch?v=s91zjpw3-P8&t=1193s) | +| SUB | `VLESS.fxxk.dedyn.io` | ❌ | 优选订阅生成器域名 | [Video](https://www.youtube.com/watch?v=s91zjpw3-P8&t=1193s) | | SUBAPI | `SUBAPI.fxxk.dedyn.io` |❌| clash、singbox等 订阅转换后端 | [Video](https://www.youtube.com/watch?v=s91zjpw3-P8&t=1446s) | | SUBCONFIG | [https://raw.github.../ACL4SSR_Online_Full_MultiMode.ini](https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/config/ACL4SSR_Online_Full_MultiMode.ini) |❌| clash、singbox等 订阅转换配置文件 | [Video](https://www.youtube.com/watch?v=s91zjpw3-P8&t=1605s) | +| SUBEMOJI | `false` |❌| 订阅转换是否启用Emoji(默认`true`) | | | SUBNAME | `edgetunnel` |❌| 订阅名称 | | | RPROXYIP | `false` |❌| 设为 true 即可强制获取订阅器分配的ProxyIP(需订阅器支持)| [Video](https://www.youtube.com/watch?v=s91zjpw3-P8&t=1816s) | | URL302 | `https://t.me/CMLiussss` |❌| 主页302跳转(支持多url, url之间使用`,`或`换行`作间隔, 小白别用) | | | URL | `https://blog.cmliussss.com` |❌| 主页反代伪装(支持多url, url之间使用`,`或`换行`作间隔, 乱设容易触发反诈) | | | CFPORTS | `2053`,`2096`,`8443` |❌| CF账户标准端口列表 | | -**注意: 填入`KEY`后将不再启用`UUID`!请二选一使用!!!** -1. 填入`KEY`后,永久订阅地址为`https://[YOUR-URL]/[YOUR-KEY]`; -2. 填入`KEY`后,临时订阅地址为`https://[YOUR-URL]/[YOUR-UUID]`; -3. **动态UUID**的订阅使用时间为**1**个`TIME`有效时间周期; -4. **动态UUID**的节点使用时间为**2**个`TIME`有效时间周期(也就是动态UUID失效了,节点也可继续使用一个周期,只是无法继续更新订阅); +# 注意事项 + +### **关于`KEY`与`UUID`:** +- 填入`KEY`变量后,将停用`UUID`变量,请确保**二者选其一使用**! +1. 填写`KEY`后,您的**永久订阅**地址为:`https://[YOUR-URL]/[YOUR-KEY]`; +2. 使用动态`UUID`订阅时: + - 临时订阅地址为:`https://[YOUR-URL]/[YOUR-UUID]`; + - 订阅有效时间为:**1个`TIME`周期**; + - 节点可使用时间:**2个`TIME`周期**,即动态`UUID`失效后,节点仍可使用1个额外周期,但无法继续更新订阅。 + +### **关于`SOCKS5`与`PROXYIP`:** +- 填入`SOCKS5`后,将停用`PROXYIP`。请确保**二者选其一使用**! -**注意: 填入`SOCKS5`后将不再启用`PROXYIP`!请二选一使用!!!** +### **关于`SUB`与`ADD*`变量:** +- 填入`SUB`后,将停用由`ADD*`类变量生成的订阅内容。请确保**二者选其一使用**! -**注意: 填入`SUB`后将不再启用`ADD*`类变量生成的订阅内容!请二选一使用!!!** +### **当`SUB`和`ADD*`均为空时:** +- 系统将自动生成基于Cloudflare的随机IP线路,每次更新订阅时会生成不同的随机IP,确保您的订阅始终有效且不会失联! -## 实用小技巧 -**该项目部署的订阅可通过添加`sub`键值快速更换优选订阅生成器!** -> 例如 `https://edgetunnel.pages.dev/90cd4a77-141a-43c9-991b-08263cfe9c10` 是你的通用自适应订阅地址 +# 实用技巧 +本项目提供灵活的订阅配置方案,支持通过URL参数快速自定义订阅内容。 +- 示例订阅地址: `https://edgetunnel.pages.dev/90cd4a77-141a-43c9-991b-08263cfe9c10` -- 快速更换订阅器为`VLESS.fxxk.dedyn.io`的订阅地址 - +1. 更换**订阅生成器**的订阅地址 + + 快速切换订阅生成器至 `VLESS.fxxk.dedyn.io`: ```url https://edgetunnel.pages.dev/90cd4a77-141a-43c9-991b-08263cfe9c10?sub=VLESS.fxxk.dedyn.io ``` - -**该项目部署的节点可通过节点PATH(路径)的方式,使用指定的`PROXYIP`或`SOCKS5`!!!** + +2. 更换**PROXYIP**的订阅地址 + + 快速更换PROXYIP为 `proxyip.fxxk.dedyn.io`: + ```url + https://edgetunnel.pages.dev/90cd4a77-141a-43c9-991b-08263cfe9c10?proxyip=proxyip.fxxk.dedyn.io + ``` + +3. 更换**SOCKS5**的订阅地址 + + 快速设置SOCKS5代理为 `user:password@127.0.0.1:1080`: + ```url + https://edgetunnel.pages.dev/90cd4a77-141a-43c9-991b-08263cfe9c10?socks5=user:password@127.0.0.1:1080 + ``` + +- 通过提交多个参数快速修改的订阅地址 + + 例如同时修改**订阅生成器**和**PROXYIP**: + ```url + https://edgetunnel.pages.dev/90cd4a77-141a-43c9-991b-08263cfe9c10?sub=VLESS.fxxk.dedyn.io&proxyip=proxyip.fxxk.dedyn.io + ``` + +4. 该项目部署的节点可通过节点PATH(路径)的方式,使用指定的`PROXYIP`或`SOCKS5`!!!** - 指定 `PROXYIP` 案例 ```url @@ -196,7 +230,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ /socks5://user:password@127.0.0.1:1080 ``` -**当你的`ADDAPI`可作为`PROXYIP`时,可在`ADDAPI`变量末位添加`?proxyip=true`,即可在生成节点时使用优选IP自身作为`PROXYIP`** +5. **当你的`ADDAPI`可作为`PROXYIP`时,可在`ADDAPI`变量末位添加`?proxyip=true`,即可在生成节点时使用优选IP自身作为`PROXYIP`** - 指定 `ADDAPI` 作为 `PROXYIP` 案例 ```url https://raw.githubusercontent.com/cmliu/WorkerVless2sub/main/addressesapi.txt?proxyip=true @@ -208,7 +242,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ ## 已适配客户端 ### Windows - [v2rayN](https://github.com/2dust/v2rayN) - - clash.meta([FlClash](https://github.com/chen08209/FlClash),[clash-verge-rev](https://github.com/clash-verge-rev/clash-verge-rev),[Clash Nyanpasu](https://github.com/keiko233/clash-nyanpasu)) + - clash.meta([FlClash](https://github.com/chen08209/FlClash),[mihomo-party](https://github.com/mihomo-party-org/mihomo-party),[clash-verge-rev](https://github.com/clash-verge-rev/clash-verge-rev),[Clash Nyanpasu](https://github.com/keiko233/clash-nyanpasu)) ### IOS - Surge,小火箭 - sing-box([SFI](https://sing-box.sagernet.org/zh/clients/apple/)) @@ -216,7 +250,7 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ - clash.meta([ClashMetaForAndroid](https://github.com/MetaCubeX/ClashMetaForAndroid),[FlClash](https://github.com/chen08209/FlClash)) - sing-box([SFA](https://github.com/SagerNet/sing-box)) ### MacOS - - clash.meta([FlClash](https://github.com/chen08209/FlClash)) + - clash.meta([FlClash](https://github.com/chen08209/FlClash),[mihomo-party](https://github.com/mihomo-party-org/mihomo-party)) # 感谢 [zizifn](https://github.com/zizifn/edgetunnel)、[3Kmfi6HP](https://github.com/6Kmfi6HP/EDtunnel)、[Stanley-baby](https://github.com/Stanley-baby)、[ACL4SSR](https://github.com/ACL4SSR/ACL4SSR/tree/master/Clash/config)、[SHIJS1999](https://github.com/SHIJS1999/cloudflare-worker-vless-ip)、Alice Networks LTD、 diff --git a/_worker.js b/_worker.js index 50a6bc7d4..896a108c1 100644 --- a/_worker.js +++ b/_worker.js @@ -4,9 +4,10 @@ import { connect } from 'cloudflare:sockets'; let userID = ''; let proxyIP = ''; let sub = ''; -let subconverter = 'SUBAPI.fxxk.dedyn.io'; -let subconfig = "https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Mini_MultiMode.ini"; +let subConverter = 'SUBAPI.fxxk.dedyn.io'; +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 enableSocks = false; @@ -36,11 +37,12 @@ let proxyhosts = []; let proxyhostsURL = ''; let RproxyIP = 'false'; let httpsPorts = ["2053","2083","2087","2096","8443"]; -let 有效时间 = 7;//有效时间 单位:天 -let 更新时间 = 3;//更新时间 +let 有效时间 = 7; +let 更新时间 = 3; let userIDLow; let userIDTime = ""; let proxyIPPool = []; +let path = '/?ed=2560'; export default { async fetch(request, env, ctx) { try { @@ -56,6 +58,9 @@ export default { userID = env.UUID; } + subEmoji = env.SUBEMOJI || env.EMOJI || subEmoji; + if(subEmoji == '0') subEmoji = 'false'; + if (!userID) { return new Response('请设置你的UUID变量,或尝试重试部署,检查变量是否生效?', { status: 404, @@ -88,14 +93,14 @@ export default { socks5Address = socks5Address.split('//')[1] || socks5Address; if (env.CFPORTS) httpsPorts = await 整理(env.CFPORTS); sub = env.SUB || sub; - subconverter = env.SUBAPI || subconverter; - if( subconverter.includes("http://") ){ - subconverter = subconverter.split("//")[1]; + subConverter = env.SUBAPI || subConverter; + if( subConverter.includes("http://") ){ + subConverter = subConverter.split("//")[1]; subProtocol = 'http'; } else { - subconverter = subconverter.split("//")[1] || subconverter; + subConverter = subConverter.split("//")[1] || subConverter; } - subconfig = env.SUBCONFIG || subconfig; + subConfig = env.SUBCONFIG || subConfig; if (socks5Address) { try { parsedSocks5Address = socks5AddressParser(socks5Address); @@ -125,6 +130,16 @@ export default { FileName = env.SUBNAME || FileName; if (url.searchParams.has('notls')) noTLS = 'true'; if (!upgradeHeader || upgradeHeader !== 'websocket') { + if (url.searchParams.has('proxyip')) { + path = `/?ed=2560&proxyip=${url.searchParams.get('proxyip')}`; + RproxyIP = 'false'; + } else if (url.searchParams.has('socks5')) { + path = `/?ed=2560&socks5=${url.searchParams.get('socks5')}`; + RproxyIP = 'false'; + } else if (url.searchParams.has('socks')) { + path = `/?ed=2560&socks5=${url.searchParams.get('socks')}`; + RproxyIP = 'false'; + } const 路径 = url.pathname.toLowerCase(); if (路径 == '/') { if (env.URL302) return Response.redirect(env.URL302, 302); @@ -176,10 +191,6 @@ export default { else return new Response(``, { status: 404 }); } } else { - proxyIP = url.searchParams.get('proxyip') || proxyIP; - if (new RegExp('/proxyip=', 'i').test(url.pathname)) proxyIP = url.pathname.toLowerCase().split('/proxyip=')[1]; - else if (new RegExp('/proxyip.', 'i').test(url.pathname)) proxyIP = `proxyip.${url.pathname.toLowerCase().split("/proxyip.")[1]}`; - 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)) { @@ -191,6 +202,7 @@ export default { socks5Address = `${userPassword}@${socks5Address.split('@')[1]}`; } } + if (socks5Address) { try { parsedSocks5Address = socks5AddressParser(socks5Address); @@ -204,6 +216,17 @@ export default { enableSocks = false; } + if (url.searchParams.has('proxyip')){ + proxyIP = url.searchParams.get('proxyip'); + enableSocks = false; + } else if (new RegExp('/proxyip=', 'i').test(url.pathname)) { + proxyIP = url.pathname.toLowerCase().split('/proxyip=')[1]; + enableSocks = false; + } else if (new RegExp('/proxyip.', 'i').test(url.pathname)) { + proxyIP = `proxyip.${url.pathname.toLowerCase().split("/proxyip.")[1]}`; + enableSocks = false; + } + return await vlessOverWSHandler(request); } } catch (err) { @@ -1151,7 +1174,7 @@ function 配置信息(UUID, 域名地址) { const 传输层协议 = 'ws'; const 伪装域名 = 域名地址; - const 路径 = '/?ed=2560'; + const 路径 = path; let 传输层安全 = ['tls',true]; const SNI = 域名地址; @@ -1196,6 +1219,9 @@ async function 生成配置信息(userID, hostName, sub, UA, RproxyIP, _url, env if (match) { sub = match[1]; } + const subs = 整理(sub); + if (subs.length > 1) sub = subs[0]; + } else if ((addresses.length + addressesapi.length + addressesnotls.length + addressesnotlsapi.length + addressescsv.length) == 0){ // 定义 Cloudflare IP 范围的 CIDR 列表 let cfips = [ @@ -1298,7 +1324,7 @@ async function 生成配置信息(userID, hostName, sub, UA, RproxyIP, _url, env } if (env.KEY && _url.pathname !== `/${env.KEY}`) 订阅器 = ''; - else 订阅器 += `\nSUBAPI(订阅转换后端): ${subProtocol}://${subconverter}\nSUBCONFIG(订阅转换配置文件): ${subconfig}`; + else 订阅器 += `\nSUBAPI(订阅转换后端): ${subProtocol}://${subConverter}\nSUBCONFIG(订阅转换配置文件): ${subConfig}`; const 动态UUID = (uuid != userID) ? `TOKEN: ${uuid}\nUUIDNow: ${userID}\nUUIDLow: ${userIDLow}\n${userIDTime}TIME(动态UUID有效时间): ${有效时间} 天\nUPTIME(动态UUID更新时间): ${更新时间} 时(北京时间)\n\n` : `${userIDTime}`; return ` ################################################################ @@ -1339,7 +1365,7 @@ clash-meta ${clash} --------------------------------------------------------------- ################################################################ -${atob('dGVsZWdyYW0g5Lqk5rWB576kIOaKgOacr+Wkp+S9rH7lnKjnur/lj5HniYwhCmh0dHBzOi8vdC5tZS9DTUxpdXNzc3MKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmdpdGh1YiDpobnnm67lnLDlnYAgU3RhciFTdGFyIVN0YXIhISEKaHR0cHM6Ly9naXRodWIuY29tL2NtbGl1L2VkZ2V0dW5uZWwKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyM=')} +${decodeURIComponent(atob('dGVsZWdyYW0lMjAlRTQlQkElQTQlRTYlQjUlODElRTclQkUlQTQlMjAlRTYlOEElODAlRTYlOUMlQUYlRTUlQTQlQTclRTQlQkQlQUMlN0UlRTUlOUMlQTglRTclQkElQkYlRTUlOEYlOTElRTclODklOEMhCmh0dHBzJTNBJTJGJTJGdC5tZSUyRkNNTGl1c3NzcwotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KZ2l0aHViJTIwJUU5JUExJUI5JUU3JTlCJUFFJUU1JTlDJUIwJUU1JTlEJTgwJTIwU3RhciFTdGFyIVN0YXIhISEKaHR0cHMlM0ElMkYlMkZnaXRodWIuY29tJTJGY21saXUlMkZlZGdldHVubmVsCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQolMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjM='))} `; } else { if (typeof fetch != 'function') { @@ -1368,7 +1394,7 @@ ${atob('dGVsZWdyYW0g5Lqk5rWB576kIOaKgOacr+Wkp+S9rH7lnKjnur/lj5HniYwhCmh0dHBzOi8v fakeHostName = `${fakeHostName}.xyz` } console.log(`虚假HOST: ${fakeHostName}`); - let url = `${subProtocol}://${sub}/sub?host=${fakeHostName}&uuid=${fakeUserID + atob('JmVkZ2V0dW5uZWw9Y21saXUmcHJveHlpcD0=') + RproxyIP}`; + let url = `${subProtocol}://${sub}/sub?host=${fakeHostName}&uuid=${fakeUserID + atob('JmVkZ2V0dW5uZWw9Y21saXUmcHJveHlpcD0=') + RproxyIP}&path=${encodeURIComponent(path)}`; let isBase64 = true; if (!sub || sub == ""){ @@ -1398,17 +1424,20 @@ ${atob('dGVsZWdyYW0g5Lqk5rWB576kIOaKgOacr+Wkp+S9rH7lnKjnur/lj5HniYwhCmh0dHBzOi8v newAddressesapi = await 整理优选列表(addressesapi); newAddressescsv = await 整理测速结果('TRUE'); - url = `https://${hostName}/${fakeUserID}`; - if (hostName.includes("worker") || hostName.includes("notls") || noTLS == 'true') url += '?notls'; + url = `https://${hostName}/${fakeUserID + _url.search}`; + if (hostName.includes("worker") || hostName.includes("notls") || noTLS == 'true') { + if (_url.search) url += '¬ls'; + else url += '?notls'; + } console.log(`虚假订阅: ${url}`); } if (!userAgent.includes(('CF-Workers-SUB').toLowerCase())){ if ((userAgent.includes('clash') && !userAgent.includes('nekobox')) || ( _url.searchParams.has('clash') && !userAgent.includes('subconverter'))) { - url = `${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`; + url = `${subProtocol}://${subConverter}/sub?target=clash&url=${encodeURIComponent(url)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=${subEmoji}&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; isBase64 = false; } else if (userAgent.includes('sing-box') || userAgent.includes('singbox') || (( _url.searchParams.has('singbox') || _url.searchParams.has('sb')) && !userAgent.includes('subconverter'))) { - url = `${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`; + url = `${subProtocol}://${subConverter}/sub?target=singbox&url=${encodeURIComponent(url)}&insert=false&config=${encodeURIComponent(subConfig)}&emoji=${subEmoji}&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; isBase64 = false; } } @@ -1617,7 +1646,7 @@ function 生成本地订阅(host,UUID,noTLS,newAddressesapi,newAddressescsv,newA if (port == "-1") port = "80"; let 伪装域名 = host ; - let 最终路径 = '/?ed=2560' ; + let 最终路径 = path ; let 节点备注 = ''; const 协议类型 = atob(啥啥啥_写的这是啥啊); @@ -1674,7 +1703,7 @@ function 生成本地订阅(host,UUID,noTLS,newAddressesapi,newAddressescsv,newA if (port == "-1") port = "443"; let 伪装域名 = host ; - let 最终路径 = '/?ed=2560' ; + let 最终路径 = path ; let 节点备注 = ''; const matchingProxyIP = proxyIPPool.find(proxyIP => proxyIP.includes(address)); if (matchingProxyIP) 最终路径 += `&proxyip=${matchingProxyIP}`;