开启JavaScript才能访问本站哦~
怎么使用cloudflare将本地地址-例如《localhost:3000》映射到公网上去
怎么使用cloudflare将本地地址-例如《localhost:3000》映射到公网上去
使用 D;D;‌Cloudflare Tunnel‌D;D; 将本地地址暴露到公网(以 localhost: 为例)🌟 核心原理Cloudflare Tunnel 通过建立加密的 D;D;‌出站连接‌D;D;(无需开放公网端口),将本地服务安全映射到 Cloudflare 的全球网络,并生成公网可访问的域名。 🛠️ 操作步骤. D;D;‌**安装 Cloudflare 客户端 cloudflared**‌D;D;# Linux/macOScurl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd -o cloudflaredchmod +x cloudflared# Windows(PowerShell)Invoke-WebRequest https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd.exe -OutFile cloudflared.exe . D;D;‌登录 Cloudflare 账户‌D;D;./cloudflared tunnel login 自动跳转浏览器,选择需要绑定的域名完成授权。 . D;D;‌创建隧道‌D;D;./cloudflared tunnel create tunnel_name # 替换为自定义隧道名称(如 my-local-app) 成功后会生成隧道 UUID 和配置文件路径(默认在 ~/.cloudflared/*.json)。 . D;D;‌配置路由规则‌D;D;创建配置文件 config.yml: tunnel: tunnel_uuid_or_namecredentials-file: /path/to/credentials.jsoningress: - hostname: your-subdomain.your-domain.com # 自定义公网域名 - service: http://localhost:service: http_status: # 未匹配请求返回 . D;D;‌启动隧道‌D;D;./cloudflared tunnel run tunnel_uuid_or_name 服务会持续运行,公网域名 your-subdomain.your-domain.com 已指向你的本地服务。 ⚙️ 可选高级配置D;D;‌绑定自定义域名‌D;D; 在 Cloudflare DNS 中添加 CNAME 记录:Type: CNAMEName: your-subdomainTarget: tunnel_uuid.cfargotunnel.com D;D;‌设置访问权限‌D;D; 在 Cloudflare Zero Trust 控制台(Access -> Applications)中配置: 限制访问IP;地区 添加身份验证(如邮箱验证、SSO) 📌 注意事项 D;D;‌无需公网IP;端口开放‌D;D;:所有流量通过 Cloudflare 加密代理。 D;D;‌免费额度‌D;D;:免费版支持单个用户并发连接,适合个人测试。 D;D;‌性能优化‌D;D;:若需高并发,可在配置中启用 warp-routing 或升级付费计划。 🌐 验证访问访问 https://your-subdomain.your-domain.com,若看到本地服务内容,则映射成功! ✅ 以上方法避免了复杂的网络配置,且天然集成 Cloudflare 的安全防护(DDoS;WAF;CDN)。适合开发测试、临时演示或轻量级生产场景。
Deepseek-R1越狱版-无审查-无内容限制-无思想钢印-无道德制高点
Deepseek-R1越狱版-无审查-无内容限制-无思想钢印-无道德制高点
本地部署 deepseek 无限制版本! 也就是DeepSeek R的越狱版!deepseek-r-abliterated :无内容审查,无限制,无思想钢印,无道德….? 越狱版的DeepSeek R现已托管在Hugging face上,支持B、B、B 【链接直达】 可能有人会觉得越狱版没有官方版聪明,这是一个比较大的误解,官方版可是B的,普通人是跑不起来的,大多数人能本地运行的都是b、b、b、b这几大类型的模型,是被蒸馏压缩过的,无法直接和B相比,但是自己本地使用已足够。 当然如果你有高级的硬件配置,你可以直接上B的, 在Ollama 【链接直达】 本地部署越狱版步骤 、下载并安装Ollama 【点击下载】 、在CMD终端下通过命令下载DeepSeek R越狱版 b ollama run huihui_ai/deepseek-r-abliterated:b b ollama run huihui_ai/deepseek-r-abliterated:b b ollama run huihui_ai/deepseek-r-abliterated:b b ollama run huihui_ai/deepseek-r-abliterated:b b ollama run huihui_ai/deepseek-r-abliterated:b 、安装 Web UI 就可以本地调用 deepseek r 越狱版 AI 大模型 【点击下载】 如需卸载删除已安装的模型,可以通过下面命令执行: ollama rm <模型名称>
本地部署 DeepSeek-R1 大模型!免费开源,媲美OpenAI-o1能力
本地部署 DeepSeek-R1 大模型!免费开源,媲美OpenAI-o1能力
最近,一家名叫DeepSeek的初创公司经过技术迭代与升级,发布了全新一代大模型,“DeepSeek-V”。由于这款大模型太过好用,DeepSeek R 更是直接免费开源,在AI发烧友圈子传播后,传到了海外社交平台、技术论坛,引发了海外网友的连连称赞。 各项性能指标更是和OpenAI-o 模型不相上下,甚至做到了小部分的超越,关键是开源的,我们可以本地部署使用 **、本地部署,**我们可以通过Ollama来进行安装Ollama 官方版:【点击前往】Web UI 控制端【点击安装】 安装命令 .B Qwen DeepSeek R ollama run deepseek-r:.b B Qwen DeepSeek R ollama run deepseek-r:b B Llama DeepSeek R ollama run deepseek-r:b B Qwen DeepSeek R ollama run deepseek-r:b B Qwen DeepSeek R ollama run deepseek-r:b B Llama DeepSeek R ollama run deepseek-r:b . 更多模型下载DeepSeek-R 模型 #总参数 #已激活参数 上下文长度 下载 DeepSeek-R-Zero B B 千 🤗 HuggingFace DeepSeek-R B B 千 🤗 HuggingFace DeepSeek-R-Zero 和 DeepSeek-R 基于 DeepSeek-V-Base 进行训练。有关模型架构的更多详细信息,请参阅DeepSeek-V存储库。 DeepSeek-R-Distill 模型 模型 基础模型 下载 DeepSeek-R-Distill-Qwen-.B Qwen.-Math-.B 🤗 HuggingFace DeepSeek-R-Distill-Qwen-B Qwen.-Math-B 🤗 HuggingFace DeepSeek-R-Distill-Llama-B Llama-.-B 🤗 HuggingFace DeepSeek-R-Distill-Qwen-B Qwen.-B 🤗 HuggingFace DeepSeek-R-Distill-Qwen-B Qwen.-B 🤗 HuggingFace DeepSeek-R-Distill-Llama-B Llama-.-B-Instruct 🤗 HuggingFace DeepSeek-R-Distill 模型基于开源模型进行了微调,使用了 DeepSeek-R 生成的样本。我们对其配置和分词器进行了轻微更改。请使用我们的设置来运行这些模型。 .评估结果DeepSeek-R-评估对于我们所有的模型,最大生成长度设置为 , 个 token。对于需要采样的基准,我们使用的温度为.,top-p 值为.,并为每个查询生成 个响应来估计 pass@。 类别 基准(公制) 克劳德-.-十四行诗- GPT-o DeepSeek V OpenAI o-mini OpenAI o- DeepSeek R 建筑学 – – 教育部 – – 教育部 # 激活参数 – – B – – B # 总参数 – – B – – B 英语 MMLU(通过@) . . . . . . MMLU-Redux(EM) . . . . – . MMLU-Pro(EM) . . . . – . 掉落 ( 发 F) . . . . . . IF-Eval(提示严格) . . . . – . GPQA-钻石级 (Pass@) . . . . . . SimpleQA(正确) . . . . . . 框架(配件) . . . . – . AlpacaEval. (LC-胜率) . . . . – . ArenaHard(GPT--) . . . . – . 代码 LiveCodeBench (Pass@-COT) . . – . . . Codeforces(百分位数) . . . . . . Codeforces(评级) SWE 已验证(已解决) . . . . . . Aider-Polyglot (Acc.) . . . . . . 数学 AIME (通行证@) . . . . . . 数学- (通过@) . . . . . . CNMO (通行证@) . . . . – . 中文 CLUEWSC(EM) . . . . – . C-评估(EM) . . . . – . C-SimpleQA(正确) . . . . – . 蒸馏模型评估 模型 AIME 通行证@ AIME 缺点@ MATH- 通过@ GPQA 钻石通行证@ LiveCodeBench 通行证@ CodeForces 评级 GPT-o- . . . . . 克劳德-.-十四行诗- . . . . . o-迷你 . . . . . QwQ-B-预览 . . . . . DeepSeek-R-Distill-Qwen-.B . . . . . DeepSeek-R-Distill-Qwen-B . . . . . DeepSeek-R-Distill-Qwen-B . . . . . DeepSeek-R-Distill-Qwen-B . . . . . DeepSeek-R-Distill-Llama-B . . . . . DeepSeek-R-Distill-Llama-B . . . . . ————-以上
通过 Cloudflare 的 worker 、Pages 搭建永久免费的VPN,真正无限流量!
通过 Cloudflare 的 worker 、Pages 搭建永久免费的VPN,真正无限流量!
今天我们主要来说下如果通过 Cloudflare 的 worker 、Pages 搭建永久免费的VPN,真正做到无限流量! 、首选你需要注册一个免费的 Cloudflare 账号 【点击前往】 、接着你需要准备好开源软件:VrayN,因为一会要用到 【点击下载】 、在Cloudflare 上创建worker,并填写下面的代码,这个代码来自CM在【 GitHub 】社区的开源项目,代码已经内置IP优选和代理功能,自带动态的UUID,可以大大减少手动配置过程,非常适合新手和特殊用户。 **注意:**创建的worker项目名称最好使用系统默认的,别自定义,以免被系统识别到特殊字符而被屏蔽。 获取Cloudflare 的 worker 开源代码 加密版:【点击获取】推荐使用加密版,有混淆作用! 明文版:【点击获取】 或者直接复制下方的代码即可! 视频教程:https://www.youtube.com/watch?v=DYGuOaqGI import &#; connect &#; from ;cloudflare:sockets;;let userID = ;;;let proxyIP = ;;;let sub = ;;;let subConverter = ;SUBAPI.fxxk.dedyn.io;;let subConfig = "https://raw.githubusercontent.com/ACLSSR/ACLSSR/master/Clash/config/ACLSSR_Online_Mini_MultiMode.ini";let subProtocol = ;https;;let subEmoji = ;true;;let socksAddress = ;;;let parsedSocksAddress = &#;&#;; let enableSocks = false;let fakeUserID ;let fakeHostName ;let noTLS = ;false;; const expire = ;//--let proxyIPs;let sockss;let goSockss = [ ;*ttvnw.net;, ;*tapecontent.net;, ;*cloudatacdn.com;, ;*.loadshare.org;,];let addresses = [];let addressesapi = [];let addressesnotls = [];let addressesnotlsapi = [];let addressescsv = [];let DLS = ;let remarkIndex = ;//CSV备注所在列偏移量let FileName = atob(;ZWRnZXRbmlbA==;);let BotToken;let ChatID; let proxyhosts = [];let proxyhostsURL = ;;;let RproxyIP = ;false;;let httpsPorts = ["","","","",""];let 有效时间 = ;let 更新时间 = ;let userIDLow;let userIDTime = "";let proxyIPPool = [];let path = ;/?ed=;;let 动态UUID;export default &#; async fetch(request, env, ctx) &#; try &#; const UA = request.headers.get(;User-Agent;) || ;null;; const userAgent = UA.toLowerCase(); userID = env.UUID || env.uuid || env.PASSWORD || env.pswd || userID; if (env.KEY || env.TOKEN || (userID && !isValidUUID(userID))) &#; 动态UUID = env.KEY || env.TOKEN || userID; 有效时间 = Number(env.TIME) || 有效时间; 更新时间 = Number(env.UPTIME) || 更新时间; const userIDs = await 生成动态UUID(动态UUID); userID = userIDs[]; userIDLow = userIDs[]; &#; if (!userID) &#; return new Response(;请设置你的UUID变量,或尝试重试部署,检查变量是否生效?;, &#; status: , headers: &#; "Content-Type": "text/plain;charset=utf-", &#; &#;); &#; const currentDate = new Date(); currentDate.setHours(, , , ); const timestamp = Math.ceil(currentDate.getTime() / ); const fakeUserIDMD = await 双重哈希(`$&#;userID&#;$&#;timestamp&#;`); fakeUserID = [ fakeUserIDMD.slice(, ), fakeUserIDMD.slice(, ), fakeUserIDMD.slice(, ), fakeUserIDMD.slice(, ), fakeUserIDMD.slice() ].join(;-;); fakeHostName = `$&#;fakeUserIDMD.slice(, )&#;.$&#;fakeUserIDMD.slice(, )&#;`; proxyIP = env.PROXYIP || env.proxyip || proxyIP; proxyIPs = await 整理(proxyIP); proxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)]; socksAddress = env.SOCKS || socksAddress; sockss = await 整理(socksAddress); socksAddress = sockss[Math.floor(Math.random() * sockss.length)]; socksAddress = socksAddress.split(;//;)[] || socksAddress; if (env.GOSOCKS) goSockss = await 整理(env.GOSOCKS); if (env.CFPORTS) httpsPorts = await 整理(env.CFPORTS); if (socksAddress) &#; try &#; parsedSocksAddress = socksAddressParser(socksAddress); RproxyIP = env.RPROXYIP || ;false;; enableSocks = true; &#; catch (err) &#; let e = err; console.log(e.toString()); RproxyIP = env.RPROXYIP || !proxyIP ? ;true; : ;false;; enableSocks = false; &#; &#; else &#; RproxyIP = env.RPROXYIP || !proxyIP ? ;true; : ;false;; &#; const upgradeHeader = request.headers.get(;Upgrade;); const url = new URL(request.url); if (!upgradeHeader || upgradeHeader !== ;websocket;) &#; if (env.ADD) addresses = await 整理(env.ADD); if (env.ADDAPI) addressesapi = await 整理(env.ADDAPI); if (env.ADDNOTLS) addressesnotls = await 整理(env.ADDNOTLS); if (env.ADDNOTLSAPI) addressesnotlsapi = await 整理(env.ADDNOTLSAPI); if (env.ADDCSV) addressescsv = await 整理(env.ADDCSV); DLS = Number(env.DLS) || DLS; remarkIndex = Number(env.CSVREMARK) || remarkIndex; BotToken = env.TGTOKEN || BotToken; ChatID = env.TGID || ChatID; FileName = env.SUBNAME || FileName; subEmoji = env.SUBEMOJI || env.EMOJI || subEmoji; if (subEmoji == ;;) subEmoji = ;false;; sub = env.SUB || sub; subConverter = env.SUBAPI || subConverter; if (subConverter.includes("http://") )&#; subConverter = subConverter.split("//")[]; subProtocol = ;http;; &#; else &#; subConverter = subConverter.split("//")[] || subConverter; &#; subConfig = env.SUBCONFIG || subConfig; if (url.searchParams.has(;sub;) && url.searchParams.get(;sub;) !== ;;) sub = url.searchParams.get(;sub;); if (url.searchParams.has(;notls;)) noTLS = ;true;; if (url.searchParams.has(;proxyip;)) &#; path = `/?ed=&proxyip=$&#;url.searchParams.get(;proxyip;)&#;`; RproxyIP = ;false;; &#; else if (url.searchParams.has(;socks;)) &#; path = `/?ed=&socks=$&#;url.searchParams.get(;socks;)&#;`; RproxyIP = ;false;; &#; else if (url.searchParams.has(;socks;)) &#; path = `/?ed=&socks=$&#;url.searchParams.get(;socks;)&#;`; RproxyIP = ;false;; &#; const 路径 = url.pathname.toLowerCase(); if (路径 == ;/;) &#; if (env.URL) return Response.redirect(env.URL, ); else if (env.URL) return await 代理URL(env.URL, url); else return new Response(JSON.stringify(request.cf, null, ), &#; status: , headers: &#; ;content-type;: ;application/json;, &#;, &#;); &#; else if (路径 == `/$&#;fakeUserID&#;`) &#; const fakeConfig = await 生成配置信息(userID, request.headers.get(;Host;), sub, ;CF-Workers-SUB;, RproxyIP, url, env); return new Response(`$&#;fakeConfig&#;`, &#; status: &#;); &#; else if (路径 == `/$&#;动态UUID&#;` || 路径 == `/$&#;userID&#;`) &#; await sendMessage(`#获取订阅 $&#;FileName&#;`, request.headers.get(;CF-Connecting-IP;), `UA: $&#;UA&#;</tg-spoiler>\n域名: $&#;url.hostname&#;\n<tg-spoiler>入口: $&#;url.pathname + url.search&#;</tg-spoiler>`); const 维列斯Config = await 生成配置信息(userID, request.headers.get(;Host;), sub, UA, RproxyIP, url, env); const now = Date.now(); //const timestamp = Math.floor(now / ); const today = new Date(now); today.setHours(, , , ); const UD = Math.floor(((now - today.getTime())/) * * / ); let pagesSum = UD; let workersSum = UD; let total = * ; if (userAgent && userAgent.includes(;mozilla;))&#; return new Response(`$&#;维列斯Config&#;`, &#; status: , headers: &#; "Content-Type": "text/plain;charset=utf-", "Profile-Update-Interval": "", "Subscription-Userinfo": `upload=$&#;pagesSum&#;; download=$&#;workersSum&#;; total=$&#;total&#;; expire=$&#;expire&#;`, &#; &#;); &#; else &#; return new Response(`$&#;维列斯Config&#;`, &#; status: , headers: &#; "Content-Disposition": `attachment; filename=$&#;FileName&#;; filename*=utf-;;$&#;encodeURIComponent(FileName)&#;`, "Content-Type": "text/plain;charset=utf-", "Profile-Update-Interval": "", "Subscription-Userinfo": `upload=$&#;pagesSum&#;; download=$&#;workersSum&#;; total=$&#;total&#;; expire=$&#;expire&#;`, &#; &#;); &#; &#; else &#; if (env.URL) return Response.redirect(env.URL, ); else if (env.URL) return await 代理URL(env.URL, url); else return new Response(``, &#; status: &#;); &#; &#; else &#; socksAddress = url.searchParams.get(;socks;) || socksAddress; if (new RegExp(;/socks=;, ;i;).test(url.pathname)) socksAddress = url.pathname.split(;=;)[]; else if (new RegExp(;/socks://;, ;i;).test(url.pathname) || new RegExp(;/socks://;, ;i;).test(url.pathname)) &#; socksAddress = url.pathname.split(;://;)[].split(;#;)[]; if (socksAddress.includes(;@;))&#; let userPassword = socksAddress.split(;@;)[]; const baseRegex = /^(?:[A-Z-+/]&#;&#;)*(?:[A-Z-+/]&#;&#;==|[A-Z-+/]&#;&#;=)?$/i; if (baseRegex.test(userPassword) && !userPassword.includes(;:;)) userPassword = atob(userPassword); socksAddress = `$&#;userPassword&#;@$&#;socksAddress.split(;@;)[]&#;`; &#; &#; if (socksAddress) &#; try &#; parsedSocksAddress = socksAddressParser(socksAddress); enableSocks = true; &#; catch (err) &#; let e = err; console.log(e.toString()); enableSocks = false; &#; &#; else &#; 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=;)[]; enableSocks = false; &#; else if (new RegExp(;/proxyip.;, ;i;).test(url.pathname)) &#; proxyIP = `proxyip.$&#;url.pathname.toLowerCase().split("/proxyip.")[]&#;`; enableSocks = false; &#; return await 维列斯OverWSHandler(request); &#; &#; catch (err) &#; let e = err; return new Response(e.toString()); &#; &#;,&#;;async function 维列斯OverWSHandler(request) &#; // @ts-ignore const webSocketPair = new WebSocketPair(); const [client, webSocket] = Object.values(webSocketPair); // 接受 WebSocket 连接 webSocket.accept(); let address = ;;; let portWithRandomLog = ;;; // 日志函数,用于记录连接信息 const log = (/** @type &#;string&#; */ info, /** @type &#;string | undefined&#; */ event) => &#; console.log(`[$&#;address&#;:$&#;portWithRandomLog&#;] $&#;info&#;`, event || ;;); &#;; // 获取早期数据头部,可能包含了一些初始化数据 const earlyDataHeader = request.headers.get(;sec-websocket-protocol;) || ;;; // 创建一个可读的 WebSocket 流,用于接收客户端数据 const readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log); // 用于存储远程 Socket 的包装器 let remoteSocketWapper = &#; value: null, &#;; // 标记是否为 DNS 查询 let isDns = false; // WebSocket 数据流向远程服务器的管道 readableWebSocketStream.pipeTo(new WritableStream(&#; async write(chunk, controller) &#; if (isDns) &#; // 如果是 DNS 查询,调用 DNS 处理函数 return await handleDNSQuery(chunk, webSocket, null, log); &#; if (remoteSocketWapper.value) &#; // 如果已有远程 Socket,直接写入数据 const writer = remoteSocketWapper.value.writable.getWriter() await writer.write(chunk); writer.releaseLock(); return; &#; // 处理 维列斯 协议头部 const &#; hasError, message, addressType, portRemote = , addressRemote = ;;, rawDataIndex, 维列斯Version = new UintArray([, ]), isUDP, &#; = process维列斯Header(chunk, userID); // 设置地址和端口信息,用于日志 address = addressRemote; portWithRandomLog = `$&#;portRemote&#;--$&#;Math.random()&#; $&#;isUDP ? ;udp ; : ;tcp ;&#; `; if (hasError) &#; // 如果有错误,抛出异常 throw new Error(message); return; &#; // 如果是 UDP 且端口不是 DNS 端口(),则关闭连接 if (isUDP) &#; if (portRemote === ) &#; isDns = true; &#; else &#; throw new Error(;UDP 代理仅对 DNS( 端口)启用;); return; &#; &#; // 构建 维列斯 响应头部 const 维列斯ResponseHeader = new UintArray([维列斯Version[], ]); // 获取实际的客户端数据 const rawClientData = chunk.slice(rawDataIndex); if (isDns) &#; // 如果是 DNS 查询,调用 DNS 处理函数 return handleDNSQuery(rawClientData, webSocket, 维列斯ResponseHeader, log); &#; // 处理 TCP 出站连接 log(`处理 TCP 出站连接 $&#;addressRemote&#;:$&#;portRemote&#;`); handleTCPOutBound(remoteSocketWapper, addressType, addressRemote, portRemote, rawClientData, webSocket, 维列斯ResponseHeader, log); &#;, close() &#; log(`readableWebSocketStream 已关闭`); &#;, abort(reason) &#; log(`readableWebSocketStream 已中止`, JSON.stringify(reason)); &#;, &#;)).catch((err) => &#; log(;readableWebSocketStream 管道错误;, err); &#;); // 返回一个 WebSocket 升级的响应 return new Response(null, &#; status: , // @ts-ignore webSocket: client, &#;);&#;async function handleTCPOutBound(remoteSocket, addressType, addressRemote, portRemote, rawClientData, webSocket, 维列斯ResponseHeader, log,) &#; async function useSocksPattern(address) &#; if ( goSockss.includes(atob(;YWxsIGlu;)) || goSockss.includes(atob(;Kg==;)) ) return true; return goSockss.some(pattern => &#; let regexPattern = pattern.replace(/\*/g, ;.*;); let regex = new RegExp(`^$&#;regexPattern&#;$`, ;i;); return regex.test(address); &#;); &#; async function connectAndWrite(address, port, socks = false) &#; log(`connected to $&#;address&#;:$&#;port&#;`); //if (/^(?:(?:[-]|[-][-]|[]?[-][-]?).)&#;&#;(?:[-]|[-][-]|[]?[-][-]?)$/.test(address)) address = `$&#;atob(;ddLg==;)&#;$&#;address&#;$&#;atob(;LmlwLjAMDIyNyeXo=;)&#;`; // 如果指定使用 SOCKS 代理,则通过 SOCKS 协议连接;否则直接连接 const tcpSocket = socks ? await socksConnect(addressType, address, port, log) : connect(&#; hostname: address, port: port, &#;); remoteSocket.value = tcpSocket; //log(`connected to $&#;address&#;:$&#;port&#;`); const writer = tcpSocket.writable.getWriter(); // 首次写入,通常是 TLS 客户端 Hello 消息 await writer.write(rawClientData); writer.releaseLock(); return tcpSocket; &#; /** * 重试函数:当 Cloudflare 的 TCP Socket 没有传入数据时,我们尝试重定向 IP * 这可能是因为某些网络问题导致的连接失败 */ async function retry() &#; if (enableSocks) &#; // 如果启用了 SOCKS,通过 SOCKS 代理重试连接 tcpSocket = await connectAndWrite(addressRemote, portRemote, true); &#; else &#; // 否则,尝试使用预设的代理 IP(如果有)或原始地址重试连接 if (!proxyIP || proxyIP == ;;) &#; proxyIP = atob(`UFJPWFlJUCcDEuZnhaykZWRbipbw==`); &#; else if (proxyIP.includes(;]:;)) &#; portRemote = proxyIP.split(;]:;)[] || portRemote; proxyIP = proxyIP.split(;]:;)[] || proxyIP; &#; else if (proxyIP.split(;:;).length === ) &#; portRemote = proxyIP.split(;:;)[] || portRemote; proxyIP = proxyIP.split(;:;)[] || proxyIP; &#; if (proxyIP.includes(;.tp;)) portRemote = proxyIP.split(;.tp;)[].split(;.;)[] || portRemote; tcpSocket = await connectAndWrite(proxyIP || addressRemote, portRemote); &#; // 无论重试是否成功,都要关闭 WebSocket(可能是为了重新建立连接) tcpSocket.closed.catch(error => &#; console.log(;retry tcpSocket closed error;, error); &#;).finally(() => &#; safeCloseWebSocket(webSocket); &#;) // 建立从远程 Socket 到 WebSocket 的数据流 remoteSocketToWS(tcpSocket, webSocket, 维列斯ResponseHeader, null, log); &#; let useSocks = false; if (goSockss.length > && enableSocks ) useSocks = await useSocksPattern(addressRemote); // 首次尝试连接远程服务器 let tcpSocket = await connectAndWrite(addressRemote, portRemote, useSocks); // 当远程 Socket 就绪时,将其传递给 WebSocket // 建立从远程服务器到 WebSocket 的数据流,用于将远程服务器的响应发送回客户端 // 如果连接失败或无数据,retry 函数将被调用进行重试 remoteSocketToWS(tcpSocket, webSocket, 维列斯ResponseHeader, retry, log);&#;function makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) &#; // 标记可读流是否已被取消 let readableStreamCancel = false; // 创建一个新的可读流 const stream = new ReadableStream(&#; // 当流开始时的初始化函数 start(controller) &#; // 监听 WebSocket 的消息事件 webSocketServer.addEventListener(;message;, (event) => &#; // 如果流已被取消,不再处理新消息 if (readableStreamCancel) &#; return; &#; const message = event.data; // 将消息加入流的队列中 controller.enqueue(message); &#;); // 监听 WebSocket 的关闭事件 // 注意:这个事件意味着客户端关闭了客户端 -> 服务器的流 // 但是,服务器 -> 客户端的流仍然打开,直到在服务器端调用 close() // WebSocket 协议要求在每个方向上都要发送单独的关闭消息,以完全关闭 Socket webSocketServer.addEventListener(;close;, () => &#; // 客户端发送了关闭信号,需要关闭服务器端 safeCloseWebSocket(webSocketServer); // 如果流未被取消,则关闭控制器 if (readableStreamCancel) &#; return; &#; controller.close(); &#;); // 监听 WebSocket 的错误事件 webSocketServer.addEventListener(;error;, (err) => &#; log(;WebSocket 服务器发生错误;); // 将错误传递给控制器 controller.error(err); &#;); // 处理 WebSocket -RTT(零往返时间)的早期数据 // -RTT 允许在完全建立连接之前发送数据,提高了效率 const &#; earlyData, error &#; = baseToArrayBuffer(earlyDataHeader); if (error) &#; // 如果解码早期数据时出错,将错误传递给控制器 controller.error(error); &#; else if (earlyData) &#; // 如果有早期数据,将其加入流的队列中 controller.enqueue(earlyData); &#; &#;, // 当使用者从流中拉取数据时调用 pull(controller) &#; // 这里可以实现反压机制 // 如果 WebSocket 可以在流满时停止读取,我们就可以实现反压 // 参考:https://streams.spec.whatwg.org/#example-rs-push-backpressure &#;, // 当流被取消时调用 cancel(reason) &#; // 流被取消的几种情况: // . 当管道的 WritableStream 有错误时,这个取消函数会被调用,所以在这里处理 WebSocket 服务器的关闭 // . 如果 ReadableStream 被取消,所有 controller.close/enqueue 都需要跳过 // . 但是经过测试,即使 ReadableStream 被取消,controller.error 仍然有效 if (readableStreamCancel) &#; return; &#; log(`可读流被取消,原因是 $&#;reason&#;`); readableStreamCancel = true; // 安全地关闭 WebSocket safeCloseWebSocket(webSocketServer); &#; &#;); return stream;&#;// https://xtls.github.io/development/protocols/维列斯.html// https://github.com/zizifn/excalidraw-backup/blob/main/vray-protocol.excalidraw/** * 解析 维列斯 协议的头部数据 * @param &#; ArrayBuffer&#; 维列斯Buffer 维列斯 协议的原始头部数据 * @param &#;string&#; userID 用于验证的用户 ID * @returns &#;Object&#; 解析结果,包括是否有错误、错误信息、远程地址信息等 */function process维列斯Header(维列斯Buffer, userID) &#; // 检查数据长度是否足够(至少需要 字节) if (维列斯Buffer.byteLength < ) &#; return &#; hasError: true, message: ;invalid data;, &#;; &#; // 解析 维列斯 协议版本(第一个字节) const version = new UintArray(维列斯Buffer.slice(, )); let isValidUser = false; let isUDP = false; // 验证用户 ID(接下来的 个字节) function isUserIDValid(userID, userIDLow, buffer) &#; const userIDArray = new UintArray(buffer.slice(, )); const userIDString = stringify(userIDArray); return userIDString === userID || userIDString === userIDLow; &#; // 使用函数验证 isValidUser = isUserIDValid(userID, userIDLow, 维列斯Buffer); // 如果用户 ID 无效,返回错误 if (!isValidUser) &#; return &#; hasError: true, message: `invalid user $&#;(new UintArray(维列斯Buffer.slice(, )))&#;`, &#;; &#; // 获取附加选项的长度(第 个字节) const optLength = new UintArray(维列斯Buffer.slice(, ))[]; // 暂时跳过附加选项 // 解析命令(紧跟在选项之后的 个字节) // x: TCP, x: UDP, x: MUX(多路复用) const command = new UintArray( 维列斯Buffer.slice( + optLength, + optLength + ) )[]; // x TCP // x UDP // x MUX if (command === ) &#; // TCP 命令,不需特殊处理 &#; else if (command === ) &#; // UDP 命令 isUDP = true; &#; else &#; // 不支持的命令 return &#; hasError: true, message: `command $&#;command&#; is not support, command -tcp,-udp,-mux`, &#;; &#; // 解析远程端口(大端序, 字节) const portIndex = + optLength + ; const portBuffer = 维列斯Buffer.slice(portIndex, portIndex + ); // port is big-Endian in raw data etc == xd const portRemote = new DataView(portBuffer).getUint(); // 解析地址类型和地址 let addressIndex = portIndex + ; const addressBuffer = new UintArray( 维列斯Buffer.slice(addressIndex, addressIndex + ) ); // 地址类型:-IPv(字节), -域名(可变长), -IPv(字节) const addressType = addressBuffer[]; let addressLength = ; let addressValueIndex = addressIndex + ; let addressValue = ;;; switch (addressType) &#; case : // IPv 地址 addressLength = ; // 将 个字节转为点分十进制格式 addressValue = new UintArray( 维列斯Buffer.slice(addressValueIndex, addressValueIndex + addressLength) ).join(;.;); break; case : // 域名 // 第一个字节是域名长度 addressLength = new UintArray( 维列斯Buffer.slice(addressValueIndex, addressValueIndex + ) )[]; addressValueIndex += ; // 解码域名 addressValue = new TextDecoder().decode( 维列斯Buffer.slice(addressValueIndex, addressValueIndex + addressLength) ); break; case : // IPv 地址 addressLength = ; const dataView = new DataView( 维列斯Buffer.slice(addressValueIndex, addressValueIndex + addressLength) ); // 每 字节构成 IPv 地址的一部分 const ipv = []; for (let i = ; i < ; i++) &#; ipv.push(dataView.getUint(i * ).toString()); &#; addressValue = ipv.join(;:;); // seems no need add [] for ipv break; default: // 无效的地址类型 return &#; hasError: true, message: `invild addressType is $&#;addressType&#;`, &#;; &#; // 确保地址不为空 if (!addressValue) &#; return &#; hasError: true, message: `addressValue is empty, addressType is $&#;addressType&#;`, &#;; &#; // 返回解析结果 return &#; hasError: false, addressRemote: addressValue, // 解析后的远程地址 addressType, // 地址类型 portRemote, // 远程端口 rawDataIndex: addressValueIndex + addressLength, // 原始数据的实际起始位置 维列斯Version: version, // 维列斯 协议版本 isUDP, // 是否是 UDP 请求 &#;;&#;async function remoteSocketToWS(remoteSocket, webSocket, 维列斯ResponseHeader, retry, log) &#; // 将数据从远程服务器转发到 WebSocket let remoteChunkCount = ; let chunks = []; /** @type &#;ArrayBuffer | null&#; */ let 维列斯Header = 维列斯ResponseHeader; let hasIncomingData = false; // 检查远程 Socket 是否有传入数据 // 使用管道将远程 Socket 的可读流连接到一个可写流 await remoteSocket.readable .pipeTo( new WritableStream(&#; start() &#; // 初始化时不需要任何操作 &#;, /** * 处理每个数据块 * @param &#;UintArray&#; chunk 数据块 * @param &#;*&#; controller 控制器 */ async write(chunk, controller) &#; hasIncomingData = true; // 标记已收到数据 // remoteChunkCount++; // 用于流量控制,现在似乎不需要了 // 检查 WebSocket 是否处于开放状态 if (webSocket.readyState !== WS_READY_STATE_OPEN) &#; controller.error( ;webSocket.readyState is not open, maybe close; ); &#; if (维列斯Header) &#; // 如果有 维列斯 响应头部,将其与第一个数据块一起发送 webSocket.send(await new Blob([维列斯Header, chunk]).arrayBuffer()); 维列斯Header = null; // 清空头部,之后不再发送 &#; else &#; // 直接发送数据块 // 以前这里有流量控制代码,限制大量数据的发送速率 // 但现在 Cloudflare 似乎已经修复了这个问题 // if (remoteChunkCount > ) &#; // // cf one package is byte(kb), * = M // await delay(); // &#; webSocket.send(chunk); &#; &#;, close() &#; // 当远程连接的可读流关闭时 log(`remoteConnection!.readable is close with hasIncomingData is $&#;hasIncomingData&#;`); // 不需要主动关闭 WebSocket,因为这可能导致 HTTP ERR_CONTENT_LENGTH_MISMATCH 问题 // 客户端无论如何都会发送关闭事件 // safeCloseWebSocket(webSocket); &#;, abort(reason) &#; // 当远程连接的可读流中断时 console.error(`remoteConnection!.readable abort`, reason); &#;, &#;) ) .catch((error) => &#; // 捕获并记录任何异常 console.error( `remoteSocketToWS has exception `, error.stack || error ); // 发生错误时安全地关闭 WebSocket safeCloseWebSocket(webSocket); &#;); // 处理 Cloudflare 连接 Socket 的特殊错误情况 // . Socket.closed 将有错误 // . Socket.readable 将关闭,但没有任何数据 if (hasIncomingData === false && retry) &#; log(`retry`); retry(); // 调用重试函数,尝试重新建立连接 &#;&#;/** * 将 Base 编码的字符串转换为 ArrayBuffer * * @param &#;string&#; baseStr Base 编码的输入字符串 * @returns &#;&#; earlyData: ArrayBuffer | undefined, error: Error | null &#;&#; 返回解码后的 ArrayBuffer 或错误 */function baseToArrayBuffer(baseStr) &#; // 如果输入为空,直接返回空结果 if (!baseStr) &#; return &#; error: null &#;; &#; try &#; // Go 语言使用了 URL 安全的 Base 变体(RFC ) // 这种变体使用 ;-; 和 ;_; 来代替标准 Base 中的 ;+; 和 ;/; // JavaScript 的 atob 函数不直接支持这种变体,所以我们需要先转换 baseStr = baseStr.replace(/-/g, ;+;).replace(/_/g, ;/;); // 使用 atob 函数解码 Base 字符串 // atob 将 Base 编码的 ASCII 字符串转换为原始的二进制字符串 const decode = atob(baseStr); // 将二进制字符串转换为 UintArray // 这是通过遍历字符串中的每个字符并获取其 Unicode 编码值(-)来完成的 const arryBuffer = UintArray.from(decode, (c) => c.charCodeAt()); // 返回 UintArray 的底层 ArrayBuffer // 这是实际的二进制数据,可以用于网络传输或其他二进制操作 return &#; earlyData: arryBuffer.buffer, error: null &#;; &#; catch (error) &#; // 如果在任何步骤中出现错误(如非法 Base 字符),则返回错误 return &#; error &#;; &#;&#;/** * 这不是真正的 UUID 验证,而是一个简化的版本 * @param &#;string&#; uuid 要验证的 UUID 字符串 * @returns &#;boolean&#; 如果字符串匹配 UUID 格式则返回 true,否则返回 false */function isValidUUID(uuid) &#; // 定义一个正则表达式来匹配 UUID 格式 const uuidRegex = /^[-a-f]&#;&#;-[-a-f]&#;&#;-[][-a-f]&#;&#;-[ab][-a-f]&#;&#;-[-a-f]&#;&#;$/i; // 使用正则表达式测试 UUID 字符串 return uuidRegex.test(uuid);&#;// WebSocket 的两个重要状态常量const WS_READY_STATE_OPEN = ; // WebSocket 处于开放状态,可以发送和接收消息const WS_READY_STATE_CLOSING = ; // WebSocket 正在关闭过程中function safeCloseWebSocket(socket) &#; try &#; // 只有在 WebSocket 处于开放或正在关闭状态时才调用 close() // 这避免了在已关闭或连接中的 WebSocket 上调用 close() if (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) &#; socket.close(); &#; &#; catch (error) &#; // 记录任何可能发生的错误,虽然按照规范不应该有错误 console.error(;safeCloseWebSocket error;, error); &#;&#;// 预计算 - 每个字节的十六进制表示const byteToHex = [];for (let i = ; i < ; ++i) &#; // (i + ).toString() 确保总是得到两位数的十六进制 // .slice() 删除前导的 "",只保留两位十六进制数 byteToHex.push((i + ).toString().slice());&#;/** * 快速地将字节数组转换为 UUID 字符串,不进行有效性检查 * 这是一个底层函数,直接操作字节,不做任何验证 * @param &#;UintArray&#; arr 包含 UUID 字节的数组 * @param &#;number&#; offset 数组中 UUID 开始的位置,默认为 * @returns &#;string&#; UUID 字符串 */function unsafeStringify(arr, offset = ) &#; // 直接从查找表中获取每个字节的十六进制表示,并拼接成 UUID 格式 // ---- 的分组是通过精心放置的连字符 "-" 实现的 // toLowerCase() 确保整个 UUID 是小写的 return (byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + "-" + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + "-" + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + "-" + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + "-" + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]] + byteToHex[arr[offset + ]]).toLowerCase();&#;/** * 将字节数组转换为 UUID 字符串,并验证其有效性 * 这是一个安全的函数,它确保返回的 UUID 格式正确 * @param &#;UintArray&#; arr 包含 UUID 字节的数组 * @param &#;number&#; offset 数组中 UUID 开始的位置,默认为 * @returns &#;string&#; 有效的 UUID 字符串 * @throws &#;TypeError&#; 如果生成的 UUID 字符串无效 */function stringify(arr, offset = ) &#; // 使用不安全的函数快速生成 UUID 字符串 const uuid = unsafeStringify(arr, offset); // 验证生成的 UUID 是否有效 if (!isValidUUID(uuid)) &#; // 原:throw TypeError("Stringified UUID is invalid"); throw TypeError(`生成的 UUID 不符合规范 $&#;uuid&#;`); //uuid = userID; &#; return uuid;&#;/** * 处理 DNS 查询的函数 * @param &#;ArrayBuffer&#; udpChunk - 客户端发送的 DNS 查询数据 * @param &#;ArrayBuffer&#; 维列斯ResponseHeader - 维列斯 协议的响应头部数据 * @param &#;(string)=> void&#; log - 日志记录函数 */async function handleDNSQuery(udpChunk, webSocket, 维列斯ResponseHeader, log) &#; // 无论客户端发送到哪个 DNS 服务器,我们总是使用硬编码的服务器 // 因为有些 DNS 服务器不支持 DNS over TCP try &#; // 选用 Google 的 DNS 服务器(注:后续可能会改为 Cloudflare 的 ...) const dnsServer = ;...;; // 在 Cloudflare 修复连接自身 IP 的 bug 后,将改为 ... const dnsPort = ; // DNS 服务的标准端口 let 维列斯Header = 维列斯ResponseHeader; // 保存 维列斯 响应头部,用于后续发送 // 与指定的 DNS 服务器建立 TCP 连接 const tcpSocket = connect(&#; hostname: dnsServer, port: dnsPort, &#;); log(`连接到 $&#;dnsServer&#;:$&#;dnsPort&#;`); // 记录连接信息 const writer = tcpSocket.writable.getWriter(); await writer.write(udpChunk); // 将客户端的 DNS 查询数据发送给 DNS 服务器 writer.releaseLock(); // 释放写入器,允许其他部分使用 // 将从 DNS 服务器接收到的响应数据通过 WebSocket 发送回客户端 await tcpSocket.readable.pipeTo(new WritableStream(&#; async write(chunk) &#; if (webSocket.readyState === WS_READY_STATE_OPEN) &#; if (维列斯Header) &#; // 如果有 维列斯 头部,则将其与 DNS 响应数据合并后发送 webSocket.send(await new Blob([维列斯Header, chunk]).arrayBuffer()); 维列斯Header = null; // 头部只发送一次,之后置为 null &#; else &#; // 否则直接发送 DNS 响应数据 webSocket.send(chunk); &#; &#; &#;, close() &#; log(`DNS 服务器($&#;dnsServer&#;) TCP 连接已关闭`); // 记录连接关闭信息 &#;, abort(reason) &#; console.error(`DNS 服务器($&#;dnsServer&#;) TCP 连接异常中断`, reason); // 记录异常中断原因 &#;, &#;)); &#; catch (error) &#; // 捕获并记录任何可能发生的错误 console.error( `handleDNSQuery 函数发生异常,错误信息: $&#;error.message&#;` ); &#;&#;/** * 建立 SOCKS 代理连接 * @param &#;number&#; addressType 目标地址类型(: IPv, : 域名, : IPv) * @param &#;string&#; addressRemote 目标地址(可以是 IP 或域名) * @param &#;number&#; portRemote 目标端口 * @param &#;function&#; log 日志记录函数 */async function socksConnect(addressType, addressRemote, portRemote, log) &#; const &#; username, password, hostname, port &#; = parsedSocksAddress; // 连接到 SOCKS 代理服务器 const socket = connect(&#; hostname, // SOCKS 服务器的主机名 port, // SOCKS 服务器的端口 &#;); // 请求头格式(Worker -> SOCKS 服务器): // +----+----------+----------+ // |VER | NMETHODS | METHODS | // +----+----------+----------+ // | | | to | // +----+----------+----------+ // https://en.wikipedia.org/wiki/SOCKS#SOCKS // METHODS 字段的含义: // x 不需要认证 // x 用户名/密码认证 https://datatracker.ietf.org/doc/html/rfc const socksGreeting = new UintArray([, , , ]); // : SOCKS 版本号, : 支持的认证方法数, 和: 两种认证方法(无认证和用户名/密码) const writer = socket.writable.getWriter(); await writer.write(socksGreeting); log(;已发送 SOCKS 问候消息;); const reader = socket.readable.getReader(); const encoder = new TextEncoder(); let res = (await reader.read()).value; // 响应格式(SOCKS 服务器 -> Worker): // +----+--------+ // |VER | METHOD | // +----+--------+ // | | | // +----+--------+ if (res[] !== x) &#; log(`SOCKS 服务器版本错误: 收到 $&#;res[]&#;,期望是 `); return; &#; if (res[] === xff) &#; log("服务器不接受任何认证方法"); return; &#; // 如果返回 x,表示需要用户名/密码认证 if (res[] === x) &#; log("SOCKS 服务器需要认证"); if (!username || !password) &#; log("请提供用户名和密码"); return; &#; // 认证请求格式: // +----+------+----------+------+----------+ // |VER | ULEN | UNAME | PLEN | PASSWD | // +----+------+----------+------+----------+ // | | | to | | to | // +----+------+----------+------+----------+ const authRequest = new UintArray([ , // 认证子协议版本 username.length, // 用户名长度 ...encoder.encode(username), // 用户名 password.length, // 密码长度 ...encoder.encode(password) // 密码 ]); await writer.write(authRequest); res = (await reader.read()).value; // 期望返回 x 表示认证成功 if (res[] !== x || res[] !== x) &#; log("SOCKS 服务器认证失败"); return; &#; &#; // 请求数据格式(Worker -> SOCKS 服务器): // +----+-----+-------+------+----------+----------+ // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | // +----+-----+-------+------+----------+----------+ // | | | X;; | | Variable | | // +----+-----+-------+------+----------+----------+ // ATYP: 地址类型 // x: IPv 地址 // x: 域名 // x: IPv 地址 // DST.ADDR: 目标地址 // DST.PORT: 目标端口(网络字节序) // addressType // --> IPv 地址长度 = // --> 域名 // --> IPv 地址长度 = let DSTADDR; // DSTADDR = ATYP + DST.ADDR switch (addressType) &#; case : // IPv DSTADDR = new UintArray( [, ...addressRemote.split(;.;).map(Number)] ); break; case : // 域名 DSTADDR = new UintArray( [, addressRemote.length, ...encoder.encode(addressRemote)] ); break; case : // IPv DSTADDR = new UintArray( [, ...addressRemote.split(;:;).flatMap(x => [parseInt(x.slice(, ), ), parseInt(x.slice(), )])] ); break; default: log(`无效的地址类型: $&#;addressType&#;`); return; &#; const socksRequest = new UintArray([, , , ...DSTADDR, portRemote >> , portRemote & xff]); // : SOCKS版本, : 表示CONNECT请求, : 保留字段 // ...DSTADDR: 目标地址, portRemote >> 和 & xff: 将端口转为网络字节序 await writer.write(socksRequest); log(;已发送 SOCKS 请求;); res = (await reader.read()).value; // 响应格式(SOCKS 服务器 -> Worker): // +----+-----+-------+------+----------+----------+ // |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | // +----+-----+-------+------+----------+----------+ // | | | X;; | | Variable | | // +----+-----+-------+------+----------+----------+ if (res[] === x) &#; log("SOCKS 连接已建立"); &#; else &#; log("SOCKS 连接建立失败"); return; &#; writer.releaseLock(); reader.releaseLock(); return socket;&#;/** * SOCKS 代理地址解析器 * 此函数用于解析 SOCKS 代理地址字符串,提取出用户名、密码、主机名和端口号 * * @param &#;string&#; address SOCKS 代理地址,格式可以是: * - "username:password@hostname:port" (带认证) * - "hostname:port" (不需认证) * - "username:password@[ipv]:port" (IPv 地址需要用方括号括起来) */function socksAddressParser(address) &#; // 使用 "@" 分割地址,分为认证部分和服务器地址部分 // reverse() 是为了处理没有认证信息的情况,确保 latter 总是包含服务器地址 let [latter, former] = address.split("@").reverse(); let username, password, hostname, port; // 如果存在 former 部分,说明提供了认证信息 if (former) &#; const formers = former.split(":"); if (formers.length !== ) &#; throw new Error(;无效的 SOCKS 地址格式:认证部分必须是 "username:password" 的形式;); &#; [username, password] = formers; &#; // 解析服务器地址部分 const latters = latter.split(":"); // 从末尾提取端口号(因为 IPv 地址中也包含冒号) port = Number(latters.pop()); if (isNaN(port)) &#; throw new Error(;无效的 SOCKS 地址格式:端口号必须是数字;); &#; // 剩余部分就是主机名(可能是域名、IPv 或 IPv 地址) hostname = latters.join(":"); // 处理 IPv 地址的特殊情况 // IPv 地址包含多个冒号,所以必须用方括号括起来,如 [:db::] const regex = /^\[.*\]$/; if (hostname.includes(":") && !regex.test(hostname)) &#; throw new Error(;无效的 SOCKS 地址格式:IPv 地址必须用方括号括起来,如 [:db::];); &#; //if (/^(?:(?:[-]|[-][-]|[]?[-][-]?).)&#;&#;(?:[-]|[-][-]|[]?[-][-]?)$/.test(hostname)) hostname = `$&#;atob(;ddLg==;)&#;$&#;hostname&#;$&#;atob(;LmlwLjAMDIyNyeXo=;)&#;`; // 返回解析后的结果 return &#; username, // 用户名,如果没有则为 undefined password, // 密码,如果没有则为 undefined hostname, // 主机名,可以是域名、IPv 或 IPv 地址 port, // 端口号,已转换为数字类型 &#;&#;/** * 恢复被伪装的信息 * 这个函数用于将内容中的假用户ID和假主机名替换回真实的值 * * @param &#;string&#; content 需要处理的内容 * @param &#;string&#; userID 真实的用户ID * @param &#;string&#; hostName 真实的主机名 * @param &#;boolean&#; isBase 内容是否是Base编码的 * @returns &#;string&#; 恢复真实信息后的内容 */function 恢复伪装信息(content, userID, hostName, isBase) &#; if (isBase) content = atob(content); // 如果内容是Base编码的,先解码 // 使用正则表达式全局替换(;g;标志) // 将所有出现的假用户ID和假主机名替换为真实的值 content = content.replace(new RegExp(fakeUserID, ;g;), userID) .replace(new RegExp(fakeHostName, ;g;), hostName); if (isBase) content = btoa(content); // 如果原内容是Base编码的,处理完后再次编码 return content;&#;/** * 双重MD哈希函数 * 这个函数对输入文本进行两次MD哈希,增强安全性 * 第二次哈希使用第一次哈希结果的一部分作为输入 * * @param &#;string&#; 文本 要哈希的文本 * @returns &#;Promise<string>&#; 双重哈希后的小写十六进制字符串 */async function 双重哈希(文本) &#; const 编码器 = new TextEncoder(); const 第一次哈希 = await crypto.subtle.digest(;MD;, 编码器.encode(文本)); const 第一次哈希数组 = Array.from(new UintArray(第一次哈希)); const 第一次十六进制 = 第一次哈希数组.map(字节 => 字节.toString().padStart(, ;;)).join(;;); const 第二次哈希 = await crypto.subtle.digest(;MD;, 编码器.encode(第一次十六进制.slice(, ))); const 第二次哈希数组 = Array.from(new UintArray(第二次哈希)); const 第二次十六进制 = 第二次哈希数组.map(字节 => 字节.toString().padStart(, ;;)).join(;;); return 第二次十六进制.toLowerCase();&#;async function 代理URL(代理网址, 目标网址) &#; const 网址列表 = await 整理(代理网址); const 完整网址 = 网址列表[Math.floor(Math.random() * 网址列表.length)]; // 解析目标 URL let 解析后的网址 = new URL(完整网址); console.log(解析后的网址); // 提取并可能修改 URL 组件 let 协议 = 解析后的网址.protocol.slice(, -) || ;https;; let 主机名 = 解析后的网址.hostname; let 路径名 = 解析后的网址.pathname; let 查询参数 = 解析后的网址.search; // 处理路径名 if (路径名.charAt(路径名.length - ) == ;/;) &#; 路径名 = 路径名.slice(, -); &#; 路径名 += 目标网址.pathname; // 构建新的 URL let 新网址 = `$&#;协议&#;://$&#;主机名&#;$&#;路径名&#;$&#;查询参数&#;`; // 反向代理请求 let 响应 = await fetch(新网址); // 创建新的响应 let 新响应 = new Response(响应.body, &#; status: 响应.status, statusText: 响应.statusText, headers: 响应.headers &#;); // 添加自定义头部,包含 URL 信息 //新响应.headers.set(;X-Proxied-By;, ;Cloudflare Worker;); //新响应.headers.set(;X-Original-URL;, 完整网址); 新响应.headers.set(;X-New-URL;, 新网址); return 新响应;&#;const 啥啥啥_写的这是啥啊 = atob(;ZGbGMzTT=;);function 配置信息(UUID, 域名地址) &#; const 协议类型 = atob(啥啥啥_写的这是啥啊); const 别名 = FileName; let 地址 = 域名地址; let 端口 = ; const 用户ID = UUID; const 加密方式 = ;none;; const 传输层协议 = ;ws;; const 伪装域名 = 域名地址; const 路径 = path; let 传输层安全 = [;tls;,true]; const SNI = 域名地址; const 指纹 = ;randomized;; if (域名地址.includes(;.workers.dev;))&#; 地址 = atob(;dmlzYSjbg==;); 端口 = ; 传输层安全 = [;;,false]; &#; const 威图瑞 = `$&#;协议类型&#;://$&#;用户ID&#;@$&#;地址&#;:$&#;端口&#;\uf\u\ue\u\u\u`+;p;+`$&#;atob(;dGlvbj=;) + 加密方式&#;\u\u\u\u\u\u\u\u\u\ud$&#;传输层安全[]&#;&sni=$&#;SNI&#;&fp=$&#;指纹&#;&type=$&#;传输层协议&#;&host=$&#;伪装域名&#;&path=$&#;encodeURIComponent(路径)&#;#$&#;encodeURIComponent(别名)&#;`; const 猫猫猫 = `- type: $&#;协议类型&#; name: $&#;FileName&#; server: $&#;地址&#; port: $&#;端口&#; uuid: $&#;用户ID&#; network: $&#;传输层协议&#; tls: $&#;传输层安全[]&#; udp: false sni: $&#;SNI&#; client-fingerprint: $&#;指纹&#; ws-opts: path: "$&#;路径&#;" headers: host: $&#;伪装域名&#;`; return [威图瑞,猫猫猫];&#;let subParams = [;sub;,;base;,;b;,;clash;,;singbox;,;sb;];/** * @param &#;string&#; userID * @param &#;string | null&#; hostName * @param &#;string&#; sub * @param &#;string&#; UA * @returns &#;Promise<string>&#; */async function 生成配置信息(userID, hostName, sub, UA, RproxyIP, _url, env) &#; if (sub) &#; const match = sub.match(/^(?:https?:\/\/)?([^\/]+)/); if (match) &#; sub = match[]; &#; const subs = await 整理(sub); if (subs.length > ) sub = subs[]; &#; else if ((addresses.length + addressesapi.length + addressesnotls.length + addressesnotlsapi.length + addressescsv.length) == )&#; // 定义 Cloudflare IP 范围的 CIDR 列表 let cfips = [ ;.../;, ;.../;, ;.../;, ;.../;, ;.../;, ;.../;, ;.../;, ;.../;, ;.../;, ;.../;, ;.../;, ]; // 生成符合给定 CIDR 范围的随机 IP 地址 function generateRandomIPFromCIDR(cidr) &#; const [base, mask] = cidr.split(;/;); const baseIP = base.split(;.;).map(Number); const subnetMask = - parseInt(mask, ); const maxHosts = Math.pow(, subnetMask) - ; const randomHost = Math.floor(Math.random() * maxHosts); const randomIP = baseIP.map((octet, index) => &#; if (index < ) return octet; if (index === ) return (octet & ( << (subnetMask - ))) + ((randomHost >> ) & ); return (octet & ( << subnetMask)) + (randomHost & ); &#;); return randomIP.join(;.;); &#; addresses = addresses.concat(;...:#CFnat;); if (hostName.includes(".workers.dev")) &#; addressesnotls = addressesnotls.concat(cfips.map(cidr => generateRandomIPFromCIDR(cidr) + ;#CF随机节点;)); &#; else &#; addresses = addresses.concat(cfips.map(cidr => generateRandomIPFromCIDR(cidr) + ;#CF随机节点;)); &#; &#; const uuid = (_url.pathname == `/$&#;动态UUID&#;`) ? 动态UUID : userID; const userAgent = UA.toLowerCase(); const Config = 配置信息(userID , hostName); const vray = Config[]; const clash = Config[]; let proxyhost = ""; if(hostName.includes(".workers.dev"))&#; if ( proxyhostsURL && (!proxyhosts || proxyhosts.length == )) &#; try &#; 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 != ) proxyhost = proxyhosts[Math.floor(Math.random() * proxyhosts.length)] + "/"; &#; if (userAgent.includes(;mozilla;) && !subParams.some(_searchParams => _url.searchParams.has(_searchParams))) &#; const newSockss = sockss.map(socksAddress => &#; if (socksAddress.includes(;@;)) return socksAddress.split(;@;)[]; else if (socksAddress.includes(;//;)) return socksAddress.split(;//;)[]; else return socksAddress; &#;); let socksList = ;;; if (goSockss.length > && enableSocks ) &#; socksList = `$&#;decodeURIComponent(;SOCKS%EF%BC%%E%%BD%E%%D%E%D%%EF%BC%%A%;)&#;`; if (goSockss.includes(atob(;YWxsIGlu;))||goSockss.includes(atob(;Kg==;))) socksList += `$&#;decodeURIComponent(;%E%%%E%C%%E%B%%E%%F;)&#;\n`; else socksList += `\n $&#;goSockss.join(;\n ;)&#;\n`; &#; let 订阅器 = ;\n;; if (sub) &#; if (enableSocks) 订阅器 += `CFCDN(访问方式): Socks\n $&#;newSockss.join(;\n ;)&#;\n$&#;socksList&#;`; else if (proxyIP && proxyIP != ;;) 订阅器 += `CFCDN(访问方式): ProxyIP\n $&#;proxyIPs.join(;\n ;)&#;\n`; else if (RproxyIP == ;true;) 订阅器 += `CFCDN(访问方式): 自动获取ProxyIP\n`; else 订阅器 += `CFCDN(访问方式): 无法访问, 需要您设置 proxyIP/PROXYIP !!!\n` 订阅器 += `\nSUB(优选订阅生成器): $&#;sub&#;`; &#; else &#; if (enableSocks) 订阅器 += `CFCDN(访问方式): Socks\n $&#;newSockss.join(;\n ;)&#;\n$&#;socksList&#;`; else if (proxyIP && proxyIP != ;;) 订阅器 += `CFCDN(访问方式): ProxyIP\n $&#;proxyIPs.join(;\n ;)&#;\n`; else 订阅器 += `CFCDN(访问方式): 无法访问, 需要您设置 proxyIP/PROXYIP !!!\n`; 订阅器 += `\n您的订阅内容由 内置 addresses/ADD* 参数变量提供\n`; if (addresses.length > ) 订阅器 += `ADD(TLS优选域名&IP): \n $&#;addresses.join(;\n ;)&#;\n`; if (addressesnotls.length > ) 订阅器 += `ADDNOTLS(noTLS优选域名&IP): \n $&#;addressesnotls.join(;\n ;)&#;\n`; if (addressesapi.length > ) 订阅器 += `ADDAPI(TLS优选域名&IP 的 API): \n $&#;addressesapi.join(;\n ;)&#;\n`; if (addressesnotlsapi.length > ) 订阅器 += `ADDNOTLSAPI(noTLS优选域名&IP 的 API): \n $&#;addressesnotlsapi.join(;\n ;)&#;\n`; if (addressescsv.length > ) 订阅器 += `ADDCSV(IPTest测速csv文件 限速 $&#;DLS&#; ): \n $&#;addressescsv.join(;\n ;)&#;\n`; &#; if (动态UUID && _url.pathname !== `/$&#;动态UUID&#;`) 订阅器 = ;;; 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 `################################################################Subscribe / sub 订阅地址, 支持 Base、clash-meta、sing-box 订阅格式---------------------------------------------------------------快速自适应订阅地址:https://$&#;proxyhost&#;$&#;hostName&#;/$&#;uuid&#;https://$&#;proxyhost&#;$&#;hostName&#;/$&#;uuid&#;?subBase订阅地址:https://$&#;proxyhost&#;$&#;hostName&#;/$&#;uuid&#;?bhttps://$&#;proxyhost&#;$&#;hostName&#;/$&#;uuid&#;?baseclash订阅地址:https://$&#;proxyhost&#;$&#;hostName&#;/$&#;uuid&#;?clashsingbox订阅地址:https://$&#;proxyhost&#;$&#;hostName&#;/$&#;uuid&#;?sbhttps://$&#;proxyhost&#;$&#;hostName&#;/$&#;uuid&#;?singbox---------------------------------------------------------------################################################################$&#;FileName&#; 配置信息---------------------------------------------------------------$&#;动态UUID信息&#;HOST: $&#;hostName&#;UUID: $&#;userID&#;FKID: $&#;fakeUserID&#;UA: $&#;UA&#;$&#;订阅器&#;---------------------------------------------------------------################################################################vray---------------------------------------------------------------$&#;vray&#;---------------------------------------------------------------################################################################clash-meta---------------------------------------------------------------$&#;clash&#;---------------------------------------------------------------################################################################$&#;decodeURIComponent(atob(;dGVsZWdyYWlMjAlRTQlQkElQTQlRTYlQjUlODElRTclQkUlQTQlMjAlRTYlOEElODAlRTYlOUMlQUYlRTUlQTQlQTclRTQlQkQlQUMlNUlRTUlOUMlQTglRTclQkElQkYlRTUlOEYlOTElRTclODklOEMhCmhdHBzJTNBJTJGJTJGdCtZSUyRkNNTGlcNzcwotLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLSKZlaHViJTIwJUUJUExJUIJUUJTlCJUFFJUUJTlDJUIwJUUJTlEJTgwJTIwURhciFTdGFyIVNYXIhISEKaHRcHMlMElMkYlMkZnaXRodWIuYtJTJGYsaXUlMkZlZGdldHVubmVsCitLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLStLQolMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjM=;))&#;`; &#; else &#; if (typeof fetch != ;function;) &#; return ;Error: fetch is not available in this environment.;; &#; let newAddressesapi = []; let newAddressescsv = []; let newAddressesnotlsapi = []; let newAddressesnotlscsv = []; // 如果是使用默认域名,则改成一个workers的域名,订阅器会加上代理 if (hostName.includes(".workers.dev"))&#; noTLS = ;true;; fakeHostName = `$&#;fakeHostName&#;.workers.dev`; newAddressesnotlsapi = await 整理优选列表(addressesnotlsapi); newAddressesnotlscsv = await 整理测速结果(;FALSE;); &#; else if (hostName.includes(".pages.dev"))&#; fakeHostName = `$&#;fakeHostName&#;.pages.dev`; &#; else if (hostName.includes("worker") || hostName.includes("notls") || noTLS == ;true;)&#; noTLS = ;true;; fakeHostName = `notls$&#;fakeHostName&#;.net`; newAddressesnotlsapi = await 整理优选列表(addressesnotlsapi); newAddressesnotlscsv = await 整理测速结果(;FALSE;); &#; else &#; fakeHostName = `$&#;fakeHostName&#;.xyz` &#; console.log(`虚假HOST: $&#;fakeHostName&#;`); let url = `$&#;subProtocol&#;://$&#;sub&#;/sub?host=$&#;fakeHostName&#;&uuid=$&#;fakeUserID + atob(;JmVkZVdWuZWwYsaXUmcHJveHlpcD=;) + RproxyIP&#;&path=$&#;encodeURIComponent(path)&#;`; let isBase = true; if (!sub || sub == "")&#; if(hostName.includes(;workers.dev;)) &#; if (proxyhostsURL && (!proxyhosts || proxyhosts.length == )) &#; try &#; 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); &#; &#; // 使用Set对象去重 proxyhosts = [...new Set(proxyhosts)]; &#; newAddressesapi = await 整理优选列表(addressesapi); newAddressescsv = await 整理测速结果(;TRUE;); url = `https://$&#;hostName&#;/$&#;fakeUserID + _url.search&#;`; if (hostName.includes("worker") || hostName.includes("notls") || noTLS == ;true;) &#; if (_url.search) url += ;&notls;; 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=$&#;subEmoji&#;&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; isBase = 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=$&#;subEmoji&#;&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`; isBase = false; &#; &#; try &#; let content; if ((!sub || sub == "") && isBase == true) &#; content = await 生成本地订阅(fakeHostName,fakeUserID,noTLS,newAddressesapi,newAddressescsv,newAddressesnotlsapi,newAddressesnotlscsv); &#; else &#; const response = await fetch(url ,&#; headers: &#; ;User-Agent;: UA + atob(;IENGLVdvcmtlcnMtZWRnZXRbmlbCjbWxpdQ==;) &#;&#;); content = await response.text(); &#; if (_url.pathname == `/$&#;fakeUserID&#;`) return content; return 恢复伪装信息(content, userID, hostName, isBase); &#; catch (error) &#; console.error(;Error fetching content:;, error); return `Error fetching content: $&#;error.message&#;`; &#; &#;&#;async function 整理优选列表(api) &#; if (!api || api.length === ) return []; let newapi = ""; // 创建一个AbortController对象,用于控制fetch请求的取消 const controller = new AbortController(); const timeout = setTimeout(() => &#; controller.abort(); // 取消所有请求 &#;, ); // 秒后触发 try &#; // 使用Promise.allSettled等待所有API请求完成,无论成功或失败 // 对api数组进行遍历,对每个API地址发起fetch请求 const responses = await Promise.allSettled(api.map(apiUrl => fetch(apiUrl, &#; method: ;get;, headers: &#; ;Accept;: ;text/html,application/xhtml+xml,application/xml;;, ;User-Agent;: atob(;QYtVyaVycylZGdldHVubmVsLNtbGl;) &#;, signal: controller.signal // 将AbortController的信号量添加到fetch请求中,以便于需要时可以取消请求 &#;).then(response => response.ok ? response.text() : Promise.reject()))); // 遍历所有响应 for (const [index, response] of responses.entries()) &#; // 检查响应状态是否为;fulfilled;,即请求成功完成 if (response.status === ;fulfilled;) &#; // 获取响应的内容 const content = await response.value; const lines = content.split(/\r?\n/); let 节点备注 = ;;; let 测速端口 = ;;; if (lines[].split(;,;).length > )&#; const idMatch = api[index].match(/id=([^&]*)/); if (idMatch) 节点备注 = idMatch[]; const portMatch = api[index].match(/port=([^&]*)/); if (portMatch) 测速端口 = portMatch[]; for (let i = ; i < lines.length; i++) &#; const columns = lines[i].split(;,;)[]; if(columns)&#; newapi += `$&#;columns&#;:$&#;测速端口&#;$&#;节点备注 ? `#$&#;节点备注&#;` : ;;&#;\n`; if (api[index].includes(;proxyip=true;)) proxyIPPool.push(`$&#;columns&#;:$&#;测速端口&#;`); &#; &#; &#; else &#; // 验证当前apiUrl是否带有;proxyip=true; if (api[index].includes(;proxyip=true;)) &#; // 如果URL带有;proxyip=true;,则将内容添加到proxyIPPool proxyIPPool = proxyIPPool.concat((await 整理(content)).map(item => &#; const baseItem = item.split(;#;)[] || item; if (baseItem.includes(;:;)) &#; const port = baseItem.split(;:;)[]; if (!httpsPorts.includes(port)) &#; return baseItem; &#; &#; else &#; return `$&#;baseItem&#;:`; &#; return null; // 不符合条件时返回 null &#;).filter(Boolean)); // 过滤掉 null 值 &#; // 将内容添加到newapi中 newapi += content + ;\n;; &#; &#; &#; &#; catch (error) &#; console.error(error); &#; finally &#; // 无论成功或失败,最后都清除设置的超时定时器 clearTimeout(timeout); &#; const newAddressesapi = await 整理(newapi); // 返回处理后的结果 return newAddressesapi;&#;async function 整理测速结果(tls) &#; if (!addressescsv || addressescsv.length === ) &#; return []; &#; let newAddressescsv = []; for (const csvUrl of addressescsv) &#; try &#; const response = await fetch(csvUrl); if (!response.ok) &#; console.error(;获取CSV地址时出错:;, response.status, response.statusText); continue; &#; const text = await response.text();// 使用正确的字符编码解析文本内容 let lines; if (text.includes(;\r\n;))&#; lines = text.split(;\r\n;); &#; else &#; lines = text.split(;\n;); &#; // 检查CSV头部是否包含必需字段 const header = lines[].split(;,;); const tlsIndex = header.indexOf(;TLS;); const ipAddressIndex = ;// IP地址在 CSV 头部的位置 const portIndex = ;// 端口在 CSV 头部的位置 const dataCenterIndex = tlsIndex + remarkIndex; // 数据中心是 TLS 的后一个字段 if (tlsIndex === -) &#; console.error(;CSV文件缺少必需的字段;); continue; &#; // 从第二行开始遍历CSV行 for (let i = ; i < lines.length; i++) &#; const columns = lines[i].split(;,;); const speedIndex = columns.length - ; // 最后一个字段 // 检查TLS是否为"TRUE"且速度大于DLS if (columns[tlsIndex].toUpperCase() === tls && parseFloat(columns[speedIndex]) > DLS) &#; const ipAddress = columns[ipAddressIndex]; const port = columns[portIndex]; const dataCenter = columns[dataCenterIndex]; const formattedAddress = `$&#;ipAddress&#;:$&#;port&#;#$&#;dataCenter&#;`; newAddressescsv.push(formattedAddress); if (csvUrl.includes(;proxyip=true;) && columns[tlsIndex].toUpperCase() == ;true; && !httpsPorts.includes(port)) &#; // 如果URL带有;proxyip=true;,则将内容添加到proxyIPPool proxyIPPool.push(`$&#;ipAddress&#;:$&#;port&#;`); &#; &#; &#; &#; catch (error) &#; console.error(;获取CSV地址时出错:;, error); continue; &#; &#; return newAddressescsv;&#;function 生成本地订阅(host,UUID,noTLS,newAddressesapi,newAddressescsv,newAddressesnotlsapi,newAddressesnotlscsv) &#; const regex = /^(\d&#;,&#;\.\d&#;,&#;\.\d&#;,&#;\.\d&#;,&#;|\[.*\]):?(\d+)?#?(.*)?$/; addresses = addresses.concat(newAddressesapi); addresses = addresses.concat(newAddressescsv); let notlsresponseBody ; if (noTLS == ;true;)&#; addressesnotls = addressesnotls.concat(newAddressesnotlsapi); addressesnotls = addressesnotls.concat(newAddressesnotlscsv); const uniqueAddressesnotls = [...new Set(addressesnotls)]; notlsresponseBody = uniqueAddressesnotls.map(address => &#; let port = "-"; let addressid = address; const match = addressid.match(regex); if (!match) &#; if (address.includes(;:;) && address.includes(;#;)) &#; const parts = address.split(;:;); address = parts[]; const subParts = parts[].split(;#;); port = subParts[]; addressid = subParts[]; &#; else if (address.includes(;:;)) &#; const parts = address.split(;:;); address = parts[]; port = parts[]; &#; else if (address.includes(;#;)) &#; const parts = address.split(;#;); address = parts[]; addressid = parts[]; &#; if (addressid.includes(;:;)) &#; addressid = addressid.split(;:;)[]; &#; &#; else &#; address = match[]; port = match[] || port; addressid = match[] || address; &#; const httpPorts = ["","","","","",""]; if (!isValidIPv(address) && port == "-") &#; for (let httpPort of httpPorts) &#; if (address.includes(httpPort)) &#; port = httpPort; break; &#; &#; &#; if (port == "-") port = ""; let 伪装域名 = host ; let 最终路径 = path ; let 节点备注 = ;;; const 协议类型 = atob(啥啥啥_写的这是啥啊); const 维列斯Link = `$&#;协议类型&#;://$&#;UUID&#;@$&#;address&#;:$&#;port + atob(;PVuYJcHRpbbmuZSZzZWNcmleTmdHlwZTcyZobNPQ==;) + 伪装域名&#;&path=$&#;encodeURIComponent(最终路径)&#;#$&#;encodeURIComponent(addressid + 节点备注)&#;`; return 维列斯Link; &#;).join(;\n;); &#; // 使用Set对象去重 const uniqueAddresses = [...new Set(addresses)]; const responseBody = uniqueAddresses.map(address => &#; let port = "-"; let addressid = address; const match = addressid.match(regex); if (!match) &#; if (address.includes(;:;) && address.includes(;#;)) &#; const parts = address.split(;:;); address = parts[]; const subParts = parts[].split(;#;); port = subParts[]; addressid = subParts[]; &#; else if (address.includes(;:;)) &#; const parts = address.split(;:;); address = parts[]; port = parts[]; &#; else if (address.includes(;#;)) &#; const parts = address.split(;#;); address = parts[]; addressid = parts[]; &#; if (addressid.includes(;:;)) &#; addressid = addressid.split(;:;)[]; &#; &#; else &#; address = match[]; port = match[] || port; addressid = match[] || address; &#; if (!isValidIPv(address) && port == "-") &#; for (let httpsPort of httpsPorts) &#; if (address.includes(httpsPort)) &#; port = httpsPort; break; &#; &#; &#; if (port == "-") port = ""; let 伪装域名 = host ; let 最终路径 = path ; let 节点备注 = ;;; const matchingProxyIP = proxyIPPool.find(proxyIP => proxyIP.includes(address)); if (matchingProxyIP) 最终路径 += `&proxyip=$&#;matchingProxyIP&#;`; if(proxyhosts.length > && (伪装域名.includes(;.workers.dev;))) &#; 最终路径 = `/$&#;伪装域名&#;$&#;最终路径&#;`; 伪装域名 = proxyhosts[Math.floor(Math.random() * proxyhosts.length)]; 节点备注 = ` 已启用临时域名中转服务,请尽快绑定自定义域!`; &#; const 协议类型 = atob(啥啥啥_写的这是啥啊); const 维列斯Link = `$&#;协议类型&#;://$&#;UUID&#;@$&#;address&#;:$&#;port + atob(;PVuYJcHRpbbmuZSZzZWNcmleTbHMmcpPQ==;) + 伪装域名&#;&fp=random&type=ws&host=$&#;伪装域名&#;&path=$&#;encodeURIComponent(最终路径)&#;#$&#;encodeURIComponent(addressid + 节点备注)&#;`; return 维列斯Link; &#;).join(;\n;); let baseResponse = responseBody; // 重新进行 Base 编码 if(noTLS == ;true;) baseResponse += `\n$&#;notlsresponseBody&#;`; return btoa(baseResponse);&#;async function 整理(内容) &#; // 将制表符、双引号、单引号和换行符都替换为逗号 // 然后将连续的多个逗号替换为单个逗号 var 替换后的内容 = 内容.replace(/[ |";\r\n]+/g, ;,;).replace(/,+/g, ;,;); // 删除开头和结尾的逗号(如果有的话) if (替换后的内容.charAt() == ;,;) 替换后的内容 = 替换后的内容.slice(); if (替换后的内容.charAt(替换后的内容.length - ) == ;,;) 替换后的内容 = 替换后的内容.slice(, 替换后的内容.length - ); // 使用逗号分割字符串,得到地址数组 const 地址数组 = 替换后的内容.split(;,;); return 地址数组;&#;async function sendMessage(type, ip, add_data = "") &#; if (!BotToken || !ChatID) return; try &#; let msg = ""; const response = await fetch(`http://ip-api.com/json/$&#;ip&#;?lang=zh-CN`); if (response.ok) &#; const ipInfo = await response.json(); msg = `$&#;type&#;\nIP: $&#;ip&#;\n国家: $&#;ipInfo.country&#;\n<tg-spoiler>城市: $&#;ipInfo.city&#;\n组织: $&#;ipInfo.org&#;\nASN: $&#;ipInfo.as&#;\n$&#;add_data&#;`; &#; else &#; msg = `$&#;type&#;\nIP: $&#;ip&#;\n<tg-spoiler>$&#;add_data&#;`; &#; const url = `https://api.telegram.org/bot$&#;BotToken&#;/sendMessage?chat_id=$&#;ChatID&#;&parse_mode=HTML&text=$&#;encodeURIComponent(msg)&#;`; return fetch(url, &#; method: ;GET;, headers: &#; ;Accept;: ;text/html,application/xhtml+xml,application/xml;;, ;Accept-Encoding;: ;gzip, deflate, br;, ;User-Agent;: ;Mozilla/. Chrome/...; &#; &#;); &#; catch (error) &#; console.error(;Error sending message:;, error); &#;&#;function isValidIPv(address) &#; const ipvRegex = /^([-]|[-][-]|[]?[-][-]?)\.([-]|[-][-]|[]?[-][-]?)\.([-]|[-][-]|[]?[-][-]?)\.([-]|[-][-]|[]?[-][-]?)$/; return ipvRegex.test(address);&#;function 生成动态UUID(密钥) &#; const 时区偏移 = ; // 北京时间相对于UTC的时区偏移+小时 const 起始日期 = new Date(, , , 更新时间, , ); // 固定起始日期为年月日的凌晨点 const 一周的毫秒数 = * * * * 有效时间; function 获取当前周数() &#; const 现在 = new Date(); const 调整后的现在 = new Date(现在.getTime() + 时区偏移 * * * ); const 时间差 = Number(调整后的现在) - Number(起始日期); return Math.ceil(时间差 / 一周的毫秒数); &#; function 生成UUID(基础字符串) &#; const 哈希缓冲区 = new TextEncoder().encode(基础字符串); return crypto.subtle.digest(;SHA-;, 哈希缓冲区).then((哈希) => &#; const 哈希数组 = Array.from(new UintArray(哈希)); const 十六进制哈希 = 哈希数组.map(b => b.toString().padStart(, ;;)).join(;;); return `$&#;十六进制哈希.substr(, )&#;-$&#;十六进制哈希.substr(, )&#;-$&#;十六进制哈希.substr(, )&#;-$&#;(parseInt(十六进制哈希.substr(, ), ) & xf | x).toString()&#;$&#;十六进制哈希.substr(, )&#;-$&#;十六进制哈希.substr(, )&#;`; &#;); &#; const 当前周数 = 获取当前周数(); // 获取当前周数 const 结束时间 = new Date(起始日期.getTime() + 当前周数 * 一周的毫秒数); // 生成两个 UUID const 当前UUIDPromise = 生成UUID(密钥 + 当前周数); const 上一个UUIDPromise = 生成UUID(密钥 + (当前周数 - )); // 格式化到期时间 const 到期时间UTC = new Date(结束时间.getTime() - 时区偏移 * * * ); // UTC时间 const 到期时间字符串 = `到期时间(UTC): $&#;到期时间UTC.toISOString().slice(, ).replace(;T;, ; ;)&#; (UTC+): $&#;结束时间.toISOString().slice(, ).replace(;T;, ; ;)&#;\n`; return Promise.all([当前UUIDPromise, 上一个UUIDPromise, 到期时间字符串]);&#; 、注册一个免费的域名,可以使用零度前几期介绍的注册方法,来获取你自己的免费域名 【点击前往】 当然如果你已经有域名那么更好! 、如果想获得更多的优质节点,那么推荐使用IP优选网站或优选工具进行获取!【点击前往】
怎样卸载Omi NTFS磁盘专家?
怎样卸载Omi NTFS磁盘专家?
怎样卸载Omi NTFS磁盘专家?App内卸载右击顶部状态栏中Omi NTFS磁盘专家的图标,直接点击卸载应用,输入系统密码即可。 手动卸载NTFS驱动.打开访达Finder -> 同时按下 [command + shift + g], 然后输入 ;Library;Filesystems;,删除omni_ntfs.fs文件。 .打开访达Finder -> 同时按下 [command + shift + g], 然后输入 ;Library;Extensions;,删除omni_ntfs.kext文件。 .打开访达Finder -> 同时按下 [command + shift + g], 然后输入 ;Library;PrivilegedHelperTools;,删除NTFS-Pro-by-Omi-Helper文件。 .打开访达Finder -> 同时按下 [command + shift + g], 然后输入 ;Library;LaunchDaemons;,删除HelperTool-Launchd.plist文件。 .打开访达Finder -> 同时按下 [command + shift + g], 然后输入 ;Applications,删除xNTFS Pro文件。 .重启系统,完成卸载。 如果你是一个程序员码农,可以直接在terminal里面输入下面的命令,完成后重启系统 sudo rm -rf ;Library;Filesystems;omni_ntfs.fs sudo rm -rf ;Library;Extensions;omni_ntfs.kext sudo rm -f ;Library;PrivilegedHelperTools;NTFS-Pro-by-Omi-Helper sudo rm -f ;Library;LaunchDaemons;HelperTool-Launchd.plist sudo rm -rf ;Applications;xNTFS\ Pro.app
BPB-Panel,结合cloudflare实现优选订阅永久免费订阅,速度极快,秒开8K,永不失联的免费节点
BPB-Panel,结合cloudflare实现优选订阅永久免费订阅,速度极快,秒开8K,永不失联的免费节点
搭建流程#Cloudflare官网地址:【点击前往】 项目地址【点击前往】 KV空间绑定名称:bpb 网址后缀:;panel 原始默认密码:admin 优选IP地址【点击前往】 可以添加PROXYIP 和 UUID PROXYIP获取地址【点击前往】(选择你想要的国家和IP。失效重新换就可以) UUID获取地址【点击前往】 测速地址【点击前往】 详细设置介绍#碎片设置# 远程DNS:远程DNS服务器地址,例如 https://.../dns-query。 本地DNS:本地DNS服务器地址,例如 ...。 长度:数据包的最小和最大长度,范围为 - 。 间隔:发送数据包的最小和最大间隔时间,范围为 - 秒。 链代理:用于输入代理链地址。 碎片路由# 屏蔽广告:勾选以屏蔽广告。 屏蔽色情内容:勾选以屏蔽色情内容。 绕过伊朗:勾选以绕过伊朗的限制。 绕过局域网:勾选以绕过局域网限制。 代理IP# IP或域名:输入代理服务器的IP地址或域名。 清洁IP 清洁IP:输入清洁的IP地址。 在线扫描:点击“立即扫描”按钮以在线扫描清洁IP。 端口# 配置类型:选择配置类型(例如TLS)。 端口:选择要使用的端口,可能的选项包括 , , , , , 。 WARP端点# WARP端点:输入WARP端点地址,例如 engage.cloudflareclient.com:。 扫描脚本:点击“复制脚本”按钮以复制扫描脚本。 应用设置# 点击“应用设置”按钮以保存配置。 常规配置# 应用程序:选择要使用的应用程序,例如 vrayNG, vrayN, Shadowrocket, Streisand, Hiddify, Nekoray (Xray), Nekobox, Sing-box。 订阅:点击“QR码”或“复制订阅”按钮以获取相应的订阅信息。 碎片订阅 应用程序:选择要使用的应用程序,例如 vrayNG, vrayN, MahsaNG, Streisand。 碎片订阅:点击“QR码”或“复制订阅”按钮以获取相应的订阅信息。 WARP订阅# 应用程序:选择要使用的应用程序,例如 vrayNG, vrayN, MahsaNG, Streisand, Hiddify, Singbox。 订阅:点击“复制订阅”按钮以获取相应的订阅信息。 碎片 - Nekoray# 配置地址:列出配置地址,例如 BPB - Domain, : 。 碎片配置:点击“复制配置”按钮以获取相应的配置。 作用解释# 远程DNS和本地DNS:指定使用的DNS服务器,远程DNS通常用于提高隐私性和安全性,本地DNS则用于本地解析。 长度和间隔:设置数据包的大小和发送间隔,以优化流量和性能。 链代理:允许用户通过多个代理服务器进行链式代理,以增强隐私和绕过地域限制。 碎片路由:提供广告屏蔽、色情内容屏蔽以及绕过特定国家或局域网限制的选项,以提升网络体验。 代理IP:配置代理服务器的IP地址或域名,用于流量转发和隐藏真实IP。 清洁IP:用于配置和扫描清洁的IP地址,以避免IP被列入黑名单或受到限制。 端口:选择使用的端口,以确保与远程服务器的连接和通信。 WARP端点:配置WARP(WireGuard协议的一种实现)端点,以提供安全的网络连接。 应用设置:保存并应用所有配置选项,以使设置生效。 常规配置、碎片订阅和WARP订阅:提供不同应用程序的配置和订阅选项,用户可以根据需要选择合适的配置方式。 这个面板用于管理和配置网络代理服务,通过碎片化数据、DNS配置和代理服务器,提供安全、私密和高效的网络连接。
怎么使用cloudflare将本地地址-例如《localhost:3000》映射到公网上去
Deepseek-R1越狱版-无审查-无内容限制-无思想钢印-无道德制高点
本地部署 DeepSeek-R1 大模型!免费开源,媲美OpenAI-o1能力
通过 Cloudflare 的 worker 、Pages 搭建永久免费的VPN,真正无限流量!
怎样卸载Omi NTFS磁盘专家?
BPB-Panel,结合cloudflare实现优选订阅永久免费订阅,速度极快,秒开8K,永不失联的免费节点
ChatGPT 开启越狱模式!不可思议,GPT-4o都能撩妹了
mac升级新系统Big Sur掉电快 关于Mac合盖睡眠后掉电快的解决方法
Win10和WSL Ubuntu 22.04 LTS SSH远程连接
casaos和1panel对比