mirror of
https://github.com/lush2020/edgetunnel.git
synced 2026-03-23 16:38:34 +08:00
绑定名为'KV'的KV空间,即可在配置页实现在线编辑'ADD'与'ADDAPI'优选列表;
This commit is contained in:
@@ -164,6 +164,9 @@ Telegram交流群:[@CMLiussss](https://t.me/CMLiussss),**感谢[Alice Networ
|
||||
|
||||
# 注意事项
|
||||
|
||||
### 开启在线编辑优选列表
|
||||
- 绑定名为`KV`的KV空间,即可在无`SUB`的前提下,在配置页实现在线编辑`ADD`与`ADDAPI`优选列表;
|
||||
|
||||
### **关于`KEY`与`UUID`:**
|
||||
- 填入`KEY`变量后,将停用`UUID`变量,请确保**二者选其一使用**!
|
||||
1. 填写`KEY`后,您的**永久订阅**地址为:`https://[YOUR-URL]/[YOUR-KEY]`;
|
||||
|
||||
414
明文源码.js
414
明文源码.js
@@ -45,6 +45,7 @@ let userIDTime = "";
|
||||
let proxyIPPool = [];
|
||||
let path = '/?ed=2560';
|
||||
let 动态UUID;
|
||||
let link = [];
|
||||
export default {
|
||||
async fetch(request, env, ctx) {
|
||||
try {
|
||||
@@ -123,7 +124,7 @@ export default {
|
||||
FileName = env.SUBNAME || FileName;
|
||||
subEmoji = env.SUBEMOJI || env.EMOJI || subEmoji;
|
||||
if (subEmoji == '0') subEmoji = 'false';
|
||||
|
||||
if (env.LINK) link = await 整理(env.LINK) ;
|
||||
sub = env.SUB || sub;
|
||||
subConverter = env.SUBAPI || subConverter;
|
||||
if (subConverter.includes("http://") ){
|
||||
@@ -160,6 +161,9 @@ export default {
|
||||
} else if (路径 == `/${fakeUserID}`) {
|
||||
const fakeConfig = await 生成配置信息(userID, request.headers.get('Host'), sub, 'CF-Workers-SUB', RproxyIP, url, env);
|
||||
return new Response(`${fakeConfig}`, { status: 200 });
|
||||
} else if (路径 == `/${动态UUID}/add` || 路径 == `/${userID}/add`) {
|
||||
const html = await KV(request, env);
|
||||
return html;
|
||||
} 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);
|
||||
@@ -173,10 +177,10 @@ export default {
|
||||
let total = 24 * 1099511627776 ;
|
||||
|
||||
if (userAgent && userAgent.includes('mozilla')){
|
||||
return new Response(`${维列斯Config}`, {
|
||||
return new Response(`<div style="font-size:13px;">${维列斯Config}</div>`, {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "text/plain;charset=utf-8",
|
||||
"Content-Type": "text/html;charset=utf-8",
|
||||
"Profile-Update-Interval": "6",
|
||||
"Subscription-Userinfo": `upload=${pagesSum}; download=${workersSum}; total=${total}; expire=${expire}`,
|
||||
}
|
||||
@@ -730,7 +734,7 @@ async function remoteSocketToWS(remoteSocket, webSocket, 维列斯ResponseHeader
|
||||
function base64ToArrayBuffer(base64Str) {
|
||||
// 如果输入为空,直接返回空结果
|
||||
if (!base64Str) {
|
||||
return { error: null };
|
||||
return { earlyData: undefined, error: null };
|
||||
}
|
||||
try {
|
||||
// Go 语言使用了 URL 安全的 Base64 变体(RFC 4648)
|
||||
@@ -751,7 +755,7 @@ function base64ToArrayBuffer(base64Str) {
|
||||
return { earlyData: arryBuffer.buffer, error: null };
|
||||
} catch (error) {
|
||||
// 如果在任何步骤中出现错误(如非法 Base64 字符),则返回错误
|
||||
return { error };
|
||||
return { earlyData: undefined, error };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1194,20 +1198,7 @@ function 配置信息(UUID, 域名地址) {
|
||||
}
|
||||
|
||||
const 威图瑞 = `${协议类型}://${用户ID}@${地址}:${端口}\u003f\u0065\u006e\u0063\u0072\u0079`+'p'+`${atob('dGlvbj0=') + 加密方式}\u0026\u0073\u0065\u0063\u0075\u0072\u0069\u0074\u0079\u003d${传输层安全[0]}&sni=${SNI}&fp=${指纹}&type=${传输层协议}&host=${伪装域名}&path=${encodeURIComponent(路径)}#${encodeURIComponent(别名)}`;
|
||||
const 猫猫猫 = `- type: ${协议类型}
|
||||
name: ${FileName}
|
||||
server: ${地址}
|
||||
port: ${端口}
|
||||
uuid: ${用户ID}
|
||||
network: ${传输层协议}
|
||||
tls: ${传输层安全[1]}
|
||||
udp: false
|
||||
sni: ${SNI}
|
||||
client-fingerprint: ${指纹}
|
||||
ws-opts:
|
||||
path: "${路径}"
|
||||
headers:
|
||||
host: ${伪装域名}`;
|
||||
const 猫猫猫 = `- {name: ${FileName}, server: ${地址}, port: ${端口}, type: ${协议类型}, uuid: ${用户ID}, tls: ${传输层安全[1]}, alpn: [h3], udp: false, sni: ${SNI}, tfo: false, skip-cert-verify: true, servername: ${伪装域名}, client-fingerprint: ${指纹}, network: ${传输层协议}, ws-opts: {path: "${路径}", headers: {${伪装域名}}}}`;
|
||||
return [威图瑞,猫猫猫];
|
||||
}
|
||||
|
||||
@@ -1228,46 +1219,64 @@ async function 生成配置信息(userID, hostName, sub, UA, RproxyIP, _url, env
|
||||
}
|
||||
const subs = await 整理(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 = [
|
||||
'103.21.244.0/23',
|
||||
'104.16.0.0/13',
|
||||
'104.24.0.0/14',
|
||||
'172.64.0.0/14',
|
||||
'103.21.244.0/23',
|
||||
'104.16.0.0/14',
|
||||
'104.24.0.0/15',
|
||||
'141.101.64.0/19',
|
||||
'172.64.0.0/14',
|
||||
'188.114.96.0/21',
|
||||
'190.93.240.0/21',
|
||||
];
|
||||
|
||||
// 生成符合给定 CIDR 范围的随机 IP 地址
|
||||
function generateRandomIPFromCIDR(cidr) {
|
||||
const [base, mask] = cidr.split('/');
|
||||
const baseIP = base.split('.').map(Number);
|
||||
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('.');
|
||||
} else {
|
||||
if (env.KV){
|
||||
const KV空间优选列表 = await env.KV.get('/ADD.txt');
|
||||
if (KV空间优选列表) {
|
||||
const KV空间优选列表数组 = await 整理(KV空间优选列表);
|
||||
for (const item of KV空间优选列表数组) {
|
||||
if (item.startsWith('https://')) {
|
||||
addressesapi.push(item);
|
||||
} else if (item.includes('://')) {
|
||||
link.push(item);
|
||||
} else {
|
||||
addresses.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
addresses = addresses.concat('127.0.0.1:1234#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随机节点'));
|
||||
|
||||
if ((addresses.length + addressesapi.length + addressesnotls.length + addressesnotlsapi.length + addressescsv.length) == 0){
|
||||
// 定义 Cloudflare IP 范围的 CIDR 列表
|
||||
let cfips = [
|
||||
'103.21.244.0/23',
|
||||
'104.16.0.0/13',
|
||||
'104.24.0.0/14',
|
||||
'172.64.0.0/14',
|
||||
'103.21.244.0/23',
|
||||
'104.16.0.0/14',
|
||||
'104.24.0.0/15',
|
||||
'141.101.64.0/19',
|
||||
'172.64.0.0/14',
|
||||
'188.114.96.0/21',
|
||||
'190.93.240.0/21',
|
||||
];
|
||||
|
||||
// 生成符合给定 CIDR 范围的随机 IP 地址
|
||||
function generateRandomIPFromCIDR(cidr) {
|
||||
const [base, mask] = cidr.split('/');
|
||||
const baseIP = base.split('.').map(Number);
|
||||
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');
|
||||
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);
|
||||
@@ -1307,73 +1316,86 @@ async function 生成配置信息(userID, hostName, sub, UA, RproxyIP, _url, env
|
||||
let socks5List = '';
|
||||
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')}\n`;
|
||||
else socks5List += `\n ${go2Socks5s.join('\n ')}\n`;
|
||||
if (go2Socks5s.includes(atob('YWxsIGlu'))||go2Socks5s.includes(atob('Kg=='))) socks5List += `${decodeURIComponent('%E6%89%80%E6%9C%89%E6%B5%81%E9%87%8F')}<br>`;
|
||||
else socks5List += `<br> ${go2Socks5s.join('<br> ')}<br>`;
|
||||
}
|
||||
|
||||
let 订阅器 = '\n';
|
||||
let 订阅器 = '<br>';
|
||||
if (sub) {
|
||||
if (enableSocks) 订阅器 += `CFCDN(访问方式): Socks5\n ${newSocks5s.join('\n ')}\n${socks5List}`;
|
||||
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}`;
|
||||
if (enableSocks) 订阅器 += `CFCDN(访问方式): Socks5<br> ${newSocks5s.join('<br> ')}<br>${socks5List}`;
|
||||
else if (proxyIP && proxyIP != '') 订阅器 += `CFCDN(访问方式): ProxyIP<br> ${proxyIPs.join('<br> ')}<br>`;
|
||||
else if (RproxyIP == 'true') 订阅器 += `CFCDN(访问方式): 自动获取ProxyIP<br>`;
|
||||
else 订阅器 += `CFCDN(访问方式): 无法访问, 需要您设置 proxyIP/PROXYIP !!!<br>`
|
||||
订阅器 += `<br>SUB(优选订阅生成器): ${sub}`;
|
||||
} else {
|
||||
if (enableSocks) 订阅器 += `CFCDN(访问方式): Socks5\n ${newSocks5s.join('\n ')}\n${socks5List}`;
|
||||
else if (proxyIP && proxyIP != '') 订阅器 += `CFCDN(访问方式): ProxyIP\n ${proxyIPs.join('\n ')}\n`;
|
||||
else 订阅器 += `CFCDN(访问方式): 无法访问, 需要您设置 proxyIP/PROXYIP !!!\n`;
|
||||
订阅器 += `\n您的订阅内容由 内置 addresses/ADD* 参数变量提供\n`;
|
||||
if (addresses.length > 0) 订阅器 += `ADD(TLS优选域名&IP): \n ${addresses.join('\n ')}\n`;
|
||||
if (addressesnotls.length > 0) 订阅器 += `ADDNOTLS(noTLS优选域名&IP): \n ${addressesnotls.join('\n ')}\n`;
|
||||
if (addressesapi.length > 0) 订阅器 += `ADDAPI(TLS优选域名&IP 的 API): \n ${addressesapi.join('\n ')}\n`;
|
||||
if (addressesnotlsapi.length > 0) 订阅器 += `ADDNOTLSAPI(noTLS优选域名&IP 的 API): \n ${addressesnotlsapi.join('\n ')}\n`;
|
||||
if (addressescsv.length > 0) 订阅器 += `ADDCSV(IPTest测速csv文件 限速 ${DLS} ): \n ${addressescsv.join('\n ')}\n`;
|
||||
if (enableSocks) 订阅器 += `CFCDN(访问方式): Socks5<br> ${newSocks5s.join('<br> ')}<br>${socks5List}`;
|
||||
else if (proxyIP && proxyIP != '') 订阅器 += `CFCDN(访问方式): ProxyIP<br> ${proxyIPs.join('<br> ')}<br>`;
|
||||
else 订阅器 += `CFCDN(访问方式): 无法访问, 需要您设置 proxyIP/PROXYIP !!!<br>`;
|
||||
let 判断是否绑定KV空间 = '';
|
||||
if (env.KV) 判断是否绑定KV空间 = ` <a href='${_url.pathname}/add'>编辑优选列表</a>`;
|
||||
订阅器 += `<br>您的订阅内容由 内置 addresses/ADD* 参数变量提供${判断是否绑定KV空间}<br>`;
|
||||
if (addresses.length > 0) 订阅器 += `ADD(TLS优选域名&IP): <br> ${addresses.join('<br> ')}<br>`;
|
||||
if (addressesnotls.length > 0) 订阅器 += `ADDNOTLS(noTLS优选域名&IP): <br> ${addressesnotls.join('<br> ')}<br>`;
|
||||
if (addressesapi.length > 0) 订阅器 += `ADDAPI(TLS优选域名&IP 的 API): <br> ${addressesapi.join('<br> ')}<br>`;
|
||||
if (addressesnotlsapi.length > 0) 订阅器 += `ADDNOTLSAPI(noTLS优选域名&IP 的 API): <br> ${addressesnotlsapi.join('<br> ')}<br>`;
|
||||
if (addressescsv.length > 0) 订阅器 += `ADDCSV(IPTest测速csv文件 限速 ${DLS} ): <br> ${addressescsv.join('<br> ')}<br>`;
|
||||
}
|
||||
|
||||
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 订阅地址, 支持 Base64、clash-meta、sing-box 订阅格式
|
||||
---------------------------------------------------------------
|
||||
快速自适应订阅地址:
|
||||
https://${proxyhost}${hostName}/${uuid}
|
||||
https://${proxyhost}${hostName}/${uuid}?sub
|
||||
else 订阅器 += `<br>SUBAPI(订阅转换后端): ${subProtocol}://${subConverter}<br>SUBCONFIG(订阅转换配置文件): ${subConfig}`;
|
||||
const 动态UUID信息 = (uuid != userID) ? `TOKEN: ${uuid}<br>UUIDNow: ${userID}<br>UUIDLow: ${userIDLow}<br>${userIDTime}TIME(动态UUID有效时间): ${有效时间} 天<br>UPTIME(动态UUID更新时间): ${更新时间} 时(北京时间)<br><br>` : `${userIDTime}`;
|
||||
const 节点配置页 = `
|
||||
################################################################<br>
|
||||
Subscribe / sub 订阅地址, 支持 Base64、clash-meta、sing-box 订阅格式<br>
|
||||
---------------------------------------------------------------<br>
|
||||
自适应订阅地址:<br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${proxyhost}${hostName}/${uuid}')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${proxyhost}${hostName}/${uuid}</a><br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${proxyhost}${hostName}/${uuid}?sub')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${proxyhost}${hostName}/${uuid}?sub</a><br>
|
||||
<br>
|
||||
Base64订阅地址:<br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${proxyhost}${hostName}/${uuid}?b64')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${proxyhost}${hostName}/${uuid}?b64</a><br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${proxyhost}${hostName}/${uuid}?base64')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${proxyhost}${hostName}/${uuid}?base64</a><br>
|
||||
<br>
|
||||
clash订阅地址:<br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${proxyhost}${hostName}/${uuid}?clash')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${proxyhost}${hostName}/${uuid}?clash</a><br>
|
||||
<br>
|
||||
singbox订阅地址:<br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${proxyhost}${hostName}/${uuid}?sb')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${proxyhost}${hostName}/${uuid}?sb</a><br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('https://${proxyhost}${hostName}/${uuid}?singbox')" style="color:blue;text-decoration:underline;cursor:pointer;">https://${proxyhost}${hostName}/${uuid}?singbox</a><br>
|
||||
|
||||
Base64订阅地址:
|
||||
https://${proxyhost}${hostName}/${uuid}?b64
|
||||
https://${proxyhost}${hostName}/${uuid}?base64
|
||||
|
||||
clash订阅地址:
|
||||
https://${proxyhost}${hostName}/${uuid}?clash
|
||||
|
||||
singbox订阅地址:
|
||||
https://${proxyhost}${hostName}/${uuid}?sb
|
||||
https://${proxyhost}${hostName}/${uuid}?singbox
|
||||
---------------------------------------------------------------
|
||||
################################################################
|
||||
${FileName} 配置信息
|
||||
---------------------------------------------------------------
|
||||
${动态UUID信息}HOST: ${hostName}
|
||||
UUID: ${userID}
|
||||
FKID: ${fakeUserID}
|
||||
UA: ${UA}
|
||||
${订阅器}
|
||||
---------------------------------------------------------------
|
||||
################################################################
|
||||
v2ray
|
||||
---------------------------------------------------------------
|
||||
${v2ray}
|
||||
---------------------------------------------------------------
|
||||
################################################################
|
||||
clash-meta
|
||||
---------------------------------------------------------------
|
||||
${clash}
|
||||
---------------------------------------------------------------
|
||||
################################################################
|
||||
${decodeURIComponent(atob('dGVsZWdyYW0lMjAlRTQlQkElQTQlRTYlQjUlODElRTclQkUlQTQlMjAlRTYlOEElODAlRTYlOUMlQUYlRTUlQTQlQTclRTQlQkQlQUMlN0UlRTUlOUMlQTglRTclQkElQkYlRTUlOEYlOTElRTclODklOEMhCmh0dHBzJTNBJTJGJTJGdC5tZSUyRkNNTGl1c3NzcwotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KZ2l0aHViJTIwJUU5JUExJUI5JUU3JTlCJUFFJUU1JTlDJUIwJUU1JTlEJTgwJTIwU3RhciFTdGFyIVN0YXIhISEKaHR0cHMlM0ElMkYlMkZnaXRodWIuY29tJTJGY21saXUlMkZlZGdldHVubmVsCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQolMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjM='))}
|
||||
`;
|
||||
<script>
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
alert('已复制到剪贴板');
|
||||
}).catch(err => {
|
||||
console.error('复制失败:', err);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
---------------------------------------------------------------<br>
|
||||
################################################################<br>
|
||||
${FileName} 配置信息<br>
|
||||
---------------------------------------------------------------<br>
|
||||
${动态UUID信息}HOST: ${hostName}<br>
|
||||
UUID: ${userID}<br>
|
||||
FKID: ${fakeUserID}<br>
|
||||
UA: ${UA}<br>
|
||||
${订阅器}<br>
|
||||
---------------------------------------------------------------<br>
|
||||
################################################################<br>
|
||||
v2ray<br>
|
||||
---------------------------------------------------------------<br>
|
||||
<a href="javascript:void(0)" onclick="copyToClipboard('${v2ray}')" style="color:blue;text-decoration:underline;cursor:pointer;">${v2ray}</a><br>
|
||||
---------------------------------------------------------------<br>
|
||||
################################################################<br>
|
||||
clash-meta<br>
|
||||
---------------------------------------------------------------<br>
|
||||
${clash}<br>
|
||||
---------------------------------------------------------------<br>
|
||||
################################################################<br>
|
||||
${decodeURIComponent(atob('dGVsZWdyYW0lMjAlRTQlQkElQTQlRTYlQjUlODElRTclQkUlQTQlMjAlRTYlOEElODAlRTYlOUMlQUYlRTUlQTQlQTclRTQlQkQlQUMlN0UlRTUlOUMlQTglRTclQkElQkYlRTUlOEYlOTElRTclODklOEMhJTNDYnIlM0UKJTNDYSUyMGhyZWYlM0QlMjdodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlMjclM0VodHRwcyUzQSUyRiUyRnQubWUlMkZDTUxpdXNzc3MlM0MlMkZhJTNFJTNDYnIlM0UKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJTNDYnIlM0UKZ2l0aHViJTIwJUU5JUExJUI5JUU3JTlCJUFFJUU1JTlDJUIwJUU1JTlEJTgwJTIwU3RhciFTdGFyIVN0YXIhISElM0NiciUzRQolM0NhJTIwaHJlZiUzRCUyN2h0dHBzJTNBJTJGJTJGZ2l0aHViLmNvbSUyRmNtbGl1JTJGZWRnZXR1bm5lbCUyNyUzRWh0dHBzJTNBJTJGJTJGZ2l0aHViLmNvbSUyRmNtbGl1JTJGZWRnZXR1bm5lbCUzQyUyRmElM0UlM0NiciUzRQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0lM0NiciUzRQolMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjMlMjM='))}
|
||||
`;
|
||||
return 节点配置页;
|
||||
} else {
|
||||
if (typeof fetch != 'function') {
|
||||
return 'Error: fetch is not available in this environment.';
|
||||
@@ -1749,6 +1771,7 @@ function 生成本地订阅(host,UUID,noTLS,newAddressesapi,newAddressescsv,newA
|
||||
|
||||
let base64Response = responseBody; // 重新进行 Base64 编码
|
||||
if(noTLS == 'true') base64Response += `\n${notlsresponseBody}`;
|
||||
if (link.length > 0) base64Response += '\n' + link.join('\n');
|
||||
return btoa(base64Response);
|
||||
}
|
||||
|
||||
@@ -1833,3 +1856,164 @@ function 生成动态UUID(密钥) {
|
||||
|
||||
return Promise.all([当前UUIDPromise, 上一个UUIDPromise, 到期时间字符串]);
|
||||
}
|
||||
|
||||
async function KV(request, env) {
|
||||
try {
|
||||
// POST请求处理
|
||||
if (request.method === "POST") {
|
||||
if (!env.KV) return new Response("未绑定KV空间", { status: 400 });
|
||||
try {
|
||||
const content = await request.text();
|
||||
await env.KV.put('/ADD.txt', content);
|
||||
return new Response("保存成功");
|
||||
} catch (error) {
|
||||
console.error('保存KV时发生错误:', error);
|
||||
return new Response("保存失败: " + error.message, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// GET请求部分
|
||||
let content = '';
|
||||
let hasKV = !!env.KV;
|
||||
|
||||
if (hasKV) {
|
||||
try {
|
||||
content = await env.KV.get('/ADD.txt') || '';
|
||||
} catch (error) {
|
||||
console.error('读取KV时发生错误:', error);
|
||||
content = '读取数据时发生错误: ' + error.message;
|
||||
}
|
||||
}
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>KV编辑器</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
font-size: 13px; /* 设置全局字体大小 */
|
||||
}
|
||||
.editor-container {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.editor {
|
||||
width: 100%;
|
||||
height: 520px;
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
}
|
||||
.save-container {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
.save-btn, .back-btn {
|
||||
padding: 8px 20px;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.save-btn {
|
||||
background: #4CAF50;
|
||||
}
|
||||
.save-btn:hover {
|
||||
background: #45a049;
|
||||
}
|
||||
.back-btn {
|
||||
background: #666;
|
||||
}
|
||||
.back-btn:hover {
|
||||
background: #555;
|
||||
}
|
||||
.save-status {
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="editor-container">
|
||||
${hasKV ? `
|
||||
<textarea class="editor"
|
||||
placeholder="${decodeURIComponent(atob('QUREJUU3JUE0JUJBJUU0JUJFJThCJUVGJUJDJTlBCnZpc2EuY24lMjMlRTQlQkMlOTglRTklODAlODklRTUlOUYlOUYlRTUlOTAlOEQKMTI3LjAuMC4xJTNBMTIzNCUyM0NGbmF0CiU1QjI2MDYlM0E0NzAwJTNBJTNBJTVEJTNBMjA1MyUyM0lQdjYKCiVFNiVCMyVBOCVFNiU4NCU4RiVFRiVCQyU5QQolRTYlQUYlOEYlRTglQTElOEMlRTQlQjglODAlRTQlQjglQUElRTUlOUMlQjAlRTUlOUQlODAlRUYlQkMlOEMlRTYlQTAlQkMlRTUlQkMlOEYlRTQlQjglQkElMjAlRTUlOUMlQjAlRTUlOUQlODAlM0ElRTclQUIlQUYlRTUlOEYlQTMlMjMlRTUlQTQlODclRTYlQjMlQTgKSVB2NiVFNSU5QyVCMCVFNSU5RCU4MCVFOSU5QyU4MCVFOCVBNiU4MSVFNyU5NCVBOCVFNCVCOCVBRCVFNiU4QiVBQyVFNSU4RiVCNyVFNiU4QiVBQyVFOCVCNSVCNyVFNiU5RCVBNSVFRiVCQyU4QyVFNSVBNiU4MiVFRiVCQyU5QSU1QjI2MDYlM0E0NzAwJTNBJTNBJTVEJTNBMjA1MwolRTclQUIlQUYlRTUlOEYlQTMlRTQlQjglOEQlRTUlODYlOTklRUYlQkMlOEMlRTklQkIlOTglRTglQUUlQTQlRTQlQjglQkElMjA0NDMlMjAlRTclQUIlQUYlRTUlOEYlQTMlRUYlQkMlOEMlRTUlQTYlODIlRUYlQkMlOUF2aXNhLmNuJTIzJUU0JUJDJTk4JUU5JTgwJTg5JUU1JTlGJTlGJUU1JTkwJThECgoKQUREQVBJJUU3JUE0JUJBJUU0JUJFJThCJUVGJUJDJTlBCmh0dHBzJTNBJTJGJTJGcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSUyRmNtbGl1JTJGV29ya2VyVmxlc3Myc3ViJTJGcmVmcyUyRmhlYWRzJTJGbWFpbiUyRmFkZHJlc3Nlc2FwaS50eHQKCiVFNiVCMyVBOCVFNiU4NCU4RiVFRiVCQyU5QUFEREFQSSVFNyU5QiVCNCVFNiU4RSVBNSVFNiVCNyVCQiVFNSU4QSVBMCVFNyU5QiVCNCVFOSU5MyVCRSVFNSU4RCVCMyVFNSU4RiVBRg=='))}"
|
||||
id="content">${content}</textarea>
|
||||
<div class="save-container">
|
||||
<button class="back-btn" onclick="goBack()">返回配置页</button>
|
||||
<button class="save-btn" onclick="saveContent()">保存</button>
|
||||
<span class="save-status" id="saveStatus"></span>
|
||||
</div>
|
||||
` : '<p>未绑定KV空间</p>'}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
if (document.querySelector('.editor')) {
|
||||
let timer;
|
||||
const textarea = document.getElementById('content');
|
||||
const originalContent = textarea.value;
|
||||
|
||||
function goBack() {
|
||||
const currentUrl = window.location.href;
|
||||
const parentUrl = currentUrl.substring(0, currentUrl.lastIndexOf('/'));
|
||||
window.location.href = parentUrl;
|
||||
}
|
||||
|
||||
function replaceFullwidthColon() {
|
||||
const text = textarea.value;
|
||||
textarea.value = text.replace(/:/g, ':');
|
||||
}
|
||||
|
||||
function saveContent() {
|
||||
replaceFullwidthColon();
|
||||
const newContent = textarea.value;
|
||||
if (newContent !== originalContent) {
|
||||
fetch(window.location.href, {
|
||||
method: 'POST',
|
||||
body: newContent
|
||||
}).then(() => {
|
||||
const now = new Date().toLocaleString();
|
||||
document.title = \`编辑已保存 \${now}\`;
|
||||
document.getElementById('saveStatus').textContent = \`已保存 \${now}\`;
|
||||
}).catch(error => {
|
||||
document.getElementById('saveStatus').textContent = \`保存失败: \${error.message}\`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
textarea.addEventListener('blur', saveContent);
|
||||
textarea.addEventListener('input', () => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(saveContent, 5000);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
return new Response(html, {
|
||||
headers: { "Content-Type": "text/html;charset=utf-8" }
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('处理请求时发生错误:', error);
|
||||
return new Response("服务器错误: " + error.message, {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "text/plain;charset=utf-8" }
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user