// 部署完成后在网址后面加上这个,获取自建节点和机场聚合节点,/?token=auto或/auto或 let mytoken = 'auto'; //可以随便取,或者uuid生成,https://1024tools.com/uuid let BotToken =''; //可以为空,或者@BotFather中输入/start,/newbot,并关注机器人 let ChatID =''; //可以为空,或者@userinfobot中获取,/start let TG = 0; //1 为推送所有的访问信息,0 为不推送订阅转换后端的访问信息与异常访问 let SUBUpdateTime = 6; //自定义订阅更新时间,单位小时 //自建节点 const MainData = ` vless://b7a392e2-4ef0-4496-90bc-1c37bb234904@cf.090227.xyz:443?encryption=none&security=tls&sni=edgetunnel-2z2.pages.dev&fp=random&type=ws&host=edgetunnel-2z2.pages.dev&path=%2F%3Fed%3D2048#%E5%8A%A0%E5%85%A5%E6%88%91%E7%9A%84%E9%A2%91%E9%81%93t.me%2FCMLiussss%E8%A7%A3%E9%94%81%E6%9B%B4%E5%A4%9A%E4%BC%98%E9%80%89%E8%8A%82%E7%82%B9 vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIuWKoOWFpeaIkeeahOmikemBk3QubWUvQ01MaXVzc3Nz6Kej6ZSB5pu05aSa5LyY6YCJ6IqC54K5PuiLseWbvSDlgKvmlabph5Hono3ln44iLA0KICAiYWRkIjogImNmLjA5MDIyNy54eXoiLA0KICAicG9ydCI6ICI4NDQzIiwNCiAgImlkIjogIjAzZmNjNjE4LWI5M2QtNjc5Ni02YWVkLThhMzhjOTc1ZDU4MSIsDQogICJhaWQiOiAiMCIsDQogICJzY3kiOiAiYXV0byIsDQogICJuZXQiOiAid3MiLA0KICAidHlwZSI6ICJub25lIiwNCiAgImhvc3QiOiAicHBmdjJ0bDl2ZW9qZC1tYWlsbGF6eS5wYWdlcy5kZXYiLA0KICAicGF0aCI6ICIvamFkZXIuZnVuOjQ0My9saW5rdndzIiwNCiAgInRscyI6ICJ0bHMiLA0KICAic25pIjogInBwZnYydGw5dmVvamQtbWFpbGxhenkucGFnZXMuZGV2IiwNCiAgImFscG4iOiAiIiwNCiAgImZwIjogIiINCn0= ` //机场信息,可多个,也可为0 const urls = [ 'https://sub.xf.free.hr/auto', 'https://hy2sub.pages.dev', // 添加更多订阅,支持base64 ]; let subconverter = "api.v1.mk"; //在线订阅转换后端,目前使用肥羊的订阅转换功能。支持自建psub 可自行搭建https://github.com/bulianglin/psub let subconfig = "https://raw.githubusercontent.com/cmliu/ACL4SSR/main/Clash/config/ACL4SSR_Online_Full.ini"; //订阅配置文件 export default { async fetch (request,env) { const userAgentHeader = request.headers.get('User-Agent'); const userAgent = userAgentHeader ? userAgentHeader.toLowerCase() : "null"; const url = new URL(request.url); const token = url.searchParams.get('token'); mytoken = env.TOKEN || mytoken; BotToken = env.TGTOKEN || BotToken; ChatID = env.TGID || ChatID; TG = env.TG || TG; subconverter = env.SUBAPI || subconverter; subconfig = env.SUBCONFIG || subconfig; if ( !(token == mytoken || url.pathname == ("/"+ mytoken) || url.pathname.includes("/"+ mytoken + "?")) ) { if ( TG == 1 && url.pathname !== "/" && url.pathname !== "/favicon.ico" ) await sendMessage("#异常访问", request.headers.get('CF-Connecting-IP'), `UA: ${userAgent}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); return new Response('Hello World!', { status: 403 }); } else if ( TG == 1 || !userAgent.includes('subconverter') || !userAgent.includes('null')){ await sendMessage("#获取订阅", request.headers.get('CF-Connecting-IP'), `UA: ${userAgent}\n域名: ${url.hostname}\n入口: ${url.pathname + url.search}`); } if (userAgent.includes('clash')) { const subconverterUrl = `https://${subconverter}/sub?target=clash&url=${encodeURIComponent(request.url)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&tfo=false&scv=false&fdn=false&sort=false&new_name=true`; try { const subconverterResponse = await fetch(subconverterUrl); if (!subconverterResponse.ok) { throw new Error(`Error fetching subconverterUrl: ${subconverterResponse.status} ${subconverterResponse.statusText}`); } const subconverterContent = await subconverterResponse.text(); return new Response(subconverterContent ,{ headers: { "content-type": "text/plain; charset=utf-8", "Profile-Update-Interval": `${SUBUpdateTime}`, } }); } catch (error) { return new Response(`Error: ${error.message}`, { status: 500, headers: { 'content-type': 'text/plain; charset=utf-8' }, }); } } else if (userAgent.includes('sing-box') || userAgent.includes('singbox')) { const subconverterUrl = `https://${subconverter}/sub?target=singbox&url=${encodeURIComponent(request.url)}&insert=false&config=${encodeURIComponent(subconfig)}&emoji=true&list=false&tfo=false&scv=false&fdn=false&sort=false&new_name=true`; try { const subconverterResponse = await fetch(subconverterUrl); if (!subconverterResponse.ok) { throw new Error(`Error fetching subconverterUrl: ${subconverterResponse.status} ${subconverterResponse.statusText}`); } const subconverterContent = await subconverterResponse.text(); return new Response(subconverterContent ,{ headers: { "content-type": "text/plain; charset=utf-8", "Profile-Update-Interval": `${SUBUpdateTime}`, } }); } catch (error) { return new Response(`Error: ${error.message}`, { status: 500, headers: { 'content-type': 'text/plain; charset=utf-8' }, }); } } else { let req_data = ""; req_data += MainData; try { const responses = await Promise.all(urls.map(url => fetch(url,{ method: 'get', headers: { 'Accept': 'text/html,application/xhtml+xml,application/xml;', 'User-Agent': 'CF-Workers-SUB/cmliu' } }))); for (const response of responses) { if (response.ok) { const content = await response.text(); //console.log(content); req_data += base64Decode(content) + '\n'; //console.log(req_data); } } } catch (error) { } //修复中文错误 const utf8Encoder = new TextEncoder(); const encodedData = utf8Encoder.encode(req_data); const text = String.fromCharCode.apply(null, encodedData); //去重 const uniqueLines = new Set(text.split('\n')); const result = [...uniqueLines].join('\n'); //console.log(result); const base64Data = btoa(result); //console.log(base64Data); return new Response(base64Data ,{ headers: { "content-type": "text/plain; charset=utf-8", "Profile-Update-Interval": `${SUBUpdateTime}`, } }); } } }; async function sendMessage(type, ip, add_data = "") { if ( BotToken !== '' && ChatID !== ''){ let msg = ""; const response = await fetch(`http://ip-api.com/json/${ip}?lang=zh-CN`); if (response.status == 200) { const ipInfo = await response.json(); msg = `${type}\nIP: ${ip}\n国家: ${ipInfo.country}\n城市: ${ipInfo.city}\n组织: ${ipInfo.org}\nASN: ${ipInfo.as}\n${add_data}`; } else { msg = `${type}\nIP: ${ip}\n${add_data}`; } let url = "https://api.telegram.org/bot"+ BotToken +"/sendMessage?chat_id=" + ChatID + "&parse_mode=HTML&text=" + encodeURIComponent(msg); return fetch(url, { method: 'get', headers: { 'Accept': 'text/html,application/xhtml+xml,application/xml;', 'Accept-Encoding': 'gzip, deflate, br', 'User-Agent': 'Mozilla/5.0 Chrome/90.0.4430.72' } }); } } // 将 base64 编码的字符串转换为 utf-8 编码的字符 function base64Decode(str) { const bytes = new Uint8Array(atob(str).split('').map(c => c.charCodeAt(0))); const decoder = new TextDecoder('utf-8'); return decoder.decode(bytes); }