mirror of
https://github.com/lush2020/edgetunnel.git
synced 2026-03-22 01:22:21 +08:00
feat: 增强订阅生成逻辑,支持Surge
This commit is contained in:
60
_worker.js
60
_worker.js
@@ -201,10 +201,12 @@ export default {
|
||||
? 'clash'
|
||||
: url.searchParams.has('sb') || url.searchParams.has('singbox') || ua.includes('singbox') || ua.includes('sing-box')
|
||||
? 'singbox'
|
||||
: 'mixed';
|
||||
: url.searchParams.has('surge') || ua.includes('surge')
|
||||
? 'surge&ver=4'
|
||||
: 'mixed';
|
||||
|
||||
if (!ua.includes('mozilla')) responseHeaders["Content-Disposition"] = `attachment; filename*=utf-8''${encodeURIComponent(config_JSON.优选订阅生成.SUBNAME)}`;
|
||||
|
||||
const 协议类型 = (url.searchParams.has('surge') || ua.includes('surge')) ? 'tro' + 'jan' : config_JSON.协议类型;
|
||||
let 订阅内容 = '';
|
||||
if (订阅类型 === 'mixed') {
|
||||
if (!url.searchParams.has('sub') && config_JSON.优选订阅生成.local) { // 本地生成订阅
|
||||
@@ -237,13 +239,13 @@ export default {
|
||||
节点备注 = 原始地址;
|
||||
}
|
||||
|
||||
return `${config_JSON.协议类型}://${config_JSON.UUID}@${节点地址}:${节点端口}?security=tls&type=${config_JSON.传输协议}&host=${config_JSON.HOST}&sni=${config_JSON.HOST}&path=${encodeURIComponent(config_JSON.PATH)}&fragment=${encodeURIComponent('1,40-60,30-50,tlshello')}&encryption=none${config_JSON.跳过证书验证 ? '&allowInsecure=1' : ''}#${encodeURIComponent(节点备注)}`;
|
||||
return `${协议类型}://${config_JSON.UUID}@${节点地址}:${节点端口}?security=tls&type=${config_JSON.传输协议}&host=${config_JSON.HOST}&sni=${config_JSON.HOST}&path=${encodeURIComponent(config_JSON.PATH)}&fragment=${encodeURIComponent('1,40-60,30-50,tlshello')}&encryption=none${config_JSON.跳过证书验证 ? '&allowInsecure=1' : ''}#${encodeURIComponent(节点备注)}`;
|
||||
}).join('\n');
|
||||
订阅内容 = btoa(订阅内容);
|
||||
} else { // 优选订阅生成器
|
||||
let 优选订阅生成器HOST = url.searchParams.get('sub') || config_JSON.优选订阅生成.SUB;
|
||||
优选订阅生成器HOST = 优选订阅生成器HOST && !/^https?:\/\//i.test(优选订阅生成器HOST) ? `https://${优选订阅生成器HOST}` : 优选订阅生成器HOST;
|
||||
const 优选订阅生成器URL = `${优选订阅生成器HOST}/sub?host=example.com&${config_JSON.协议类型 === ('v' + 'le' + 'ss') ? 'uuid' : 'pw'}=00000000-0000-4000-0000-000000000000&path=${encodeURIComponent(config_JSON.PATH)}&type=${config_JSON.传输协议}`;
|
||||
const 优选订阅生成器URL = `${优选订阅生成器HOST}/sub?host=example.com&${协议类型 === ('v' + 'le' + 'ss') ? 'uuid' : 'pw'}=00000000-0000-4000-0000-000000000000&path=${encodeURIComponent(config_JSON.PATH)}&type=${config_JSON.传输协议}`;
|
||||
try {
|
||||
const response = await fetch(优选订阅生成器URL, { headers: { 'User-Agent': 'v2rayN/edge' + 'tunnel (https://github.com/cmliu/edge' + 'tunnel)' } });
|
||||
if (response.ok) 订阅内容 = await response.text();
|
||||
@@ -256,8 +258,10 @@ export default {
|
||||
const 订阅转换URL = `${config_JSON.订阅转换配置.SUBAPI}/sub?target=${订阅类型}&url=${encodeURIComponent(url.protocol + '//' + url.host + '/sub?target=mixed&token=' + 订阅TOKEN) + (url.searchParams.has('sub') && url.searchParams.get('sub') != '' ? `&sub=${url.searchParams.get('sub')}` : '')}&config=${encodeURIComponent(config_JSON.订阅转换配置.SUBCONFIG)}&emoji=${config_JSON.订阅转换配置.SUBEMOJI}&scv=${config_JSON.跳过证书验证}`;
|
||||
try {
|
||||
const response = await fetch(订阅转换URL, { headers: { 'User-Agent': 'Subconverter for ' + 订阅类型 + ' edge' + 'tunnel(https://github.com/cmliu/edge' + 'tunnel)' } });
|
||||
if (response.ok) 订阅内容 = await response.text();
|
||||
else return new Response('订阅转换后端异常:' + response.statusText, { status: response.status });
|
||||
if (response.ok) {
|
||||
订阅内容 = await response.text();
|
||||
if (url.searchParams.has('surge') || ua.includes('surge')) 订阅内容 = surge(订阅内容, url.protocol + '//' + url.host + '/sub?token=' + 订阅TOKEN + '&surge', config_JSON);
|
||||
} else return new Response('订阅转换后端异常:' + response.statusText, { status: response.status });
|
||||
} catch (error) {
|
||||
return new Response('订阅转换后端异常:' + error.message, { status: 403 });
|
||||
}
|
||||
@@ -319,7 +323,7 @@ function handleConnection(ws, request, FIXED_UUID) {
|
||||
const { host, length } = parseAddress(bytes, offset2, addrType === 1 ? 1 : addrType === 2 ? 2 : 4);
|
||||
const payload = bytes.slice(length);
|
||||
if (host.includes(atob('c3BlZWQuY2xvdWRmbGFyZS5jb20='))) throw new Error('Access');
|
||||
|
||||
|
||||
// 判断是否为UDP命令(0x02)
|
||||
const isUDP = command === 2;
|
||||
if (isUDP) {
|
||||
@@ -334,7 +338,7 @@ function handleConnection(ws, request, FIXED_UUID) {
|
||||
throw new Error('UDP proxy only enable for DNS which is port 53');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const sock = await createConnection(host, port);
|
||||
await sock.opened;
|
||||
const w = sock.writable.getWriter();
|
||||
@@ -349,12 +353,12 @@ function handleConnection(ws, request, FIXED_UUID) {
|
||||
|
||||
const socks5Data = bytes.slice(58);
|
||||
if (socks5Data.byteLength < 6) throw new Error("invalid SOCKS5 request data");
|
||||
|
||||
|
||||
const command = socks5Data[0];
|
||||
// 0x01 TCP (CONNECT)
|
||||
// 0x02 UDP
|
||||
const isUDP = command === 2;
|
||||
|
||||
|
||||
if (command !== 1 && command !== 2) {
|
||||
throw new Error(`unsupported command ${command}, only TCP (CONNECT) and UDP are allowed`);
|
||||
}
|
||||
@@ -365,7 +369,7 @@ function handleConnection(ws, request, FIXED_UUID) {
|
||||
|
||||
const port = (socks5Data[length] << 8) | socks5Data[length + 1];
|
||||
const payload = socks5Data.slice(length + 4);
|
||||
|
||||
|
||||
// 处理UDP DNS请求
|
||||
if (isUDP) {
|
||||
if (port === 53) {
|
||||
@@ -380,7 +384,7 @@ function handleConnection(ws, request, FIXED_UUID) {
|
||||
throw new Error('UDP proxy only enable for DNS which is port 53');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理TCP连接
|
||||
const sock = await createConnection(host, port);
|
||||
await sock.opened;
|
||||
@@ -553,7 +557,7 @@ function handleConnection(ws, request, FIXED_UUID) {
|
||||
const bytes = new Uint8Array(firstData);
|
||||
if (bytes.byteLength >= 58 && bytes[56] === 0x0d && bytes[57] === 0x0a) ({ socket, writer, reader, info } = await 处理木马握手(firstData));
|
||||
else ({ socket, writer, reader, info } = await 处理魏烈思握手(firstData));
|
||||
|
||||
|
||||
// 如果是DNS UDP请求,不需要启动定时器和读取循环
|
||||
if (!isDns) {
|
||||
startTimers();
|
||||
@@ -614,7 +618,7 @@ const WS_READY_STATE_OPEN = 1;
|
||||
async function handleUDPOutBound(webSocket, 协议响应头) {
|
||||
let 响应头已发送 = false;
|
||||
const transformStream = new TransformStream({
|
||||
start(controller) {},
|
||||
start(controller) { },
|
||||
transform(chunk, controller) {
|
||||
// UDP消息前2字节是UDP数据的长度
|
||||
for (let index = 0; index < chunk.byteLength;) {
|
||||
@@ -627,7 +631,7 @@ async function handleUDPOutBound(webSocket, 协议响应头) {
|
||||
controller.enqueue(udpData);
|
||||
}
|
||||
},
|
||||
flush(controller) {}
|
||||
flush(controller) { }
|
||||
});
|
||||
|
||||
// 处理DNS UDP查询
|
||||
@@ -643,7 +647,7 @@ async function handleUDPOutBound(webSocket, 协议响应头) {
|
||||
const dnsQueryResult = await resp.arrayBuffer();
|
||||
const udpSize = dnsQueryResult.byteLength;
|
||||
const udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]);
|
||||
|
||||
|
||||
if (webSocket.readyState === WS_READY_STATE_OPEN) {
|
||||
console.log(`DoH success and dns message length is ${udpSize}`);
|
||||
if (响应头已发送) {
|
||||
@@ -752,6 +756,30 @@ async function socks5Connect(targetHost, targetPort) {
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////功能性函数///////////////////////////////////////////////
|
||||
function surge(content, url, config_JSON) {
|
||||
let 每行内容;
|
||||
if (content.includes('\r\n')) {
|
||||
每行内容 = content.split('\r\n');
|
||||
} else {
|
||||
每行内容 = content.split('\n');
|
||||
}
|
||||
|
||||
let 输出内容 = "";
|
||||
for (let x of 每行内容) {
|
||||
if (x.includes('= tro' + 'jan,')) {
|
||||
console.log(x);
|
||||
const host = x.split("sni=")[1].split(",")[0];
|
||||
const 备改内容 = `sni=${host}, skip-cert-verify=${config_JSON.跳过证书验证}`;
|
||||
const 正确内容 = `sni=${host}, skip-cert-verify=${config_JSON.跳过证书验证}, ws=true, ws-path=${config_JSON.PATH}, ws-headers=Host:"${host}"`;
|
||||
输出内容 += x.replace(new RegExp(备改内容, 'g'), 正确内容).replace("[", "").replace("]", "") + '\n';
|
||||
} else {
|
||||
输出内容 += x + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
输出内容 = `#!MANAGED-CONFIG ${url} interval=${config_JSON.优选订阅生成.SUBUpdateTime * 60 * 60} strict=false` + 输出内容.substring(输出内容.indexOf('\n'));
|
||||
return 输出内容;
|
||||
}
|
||||
async function 请求日志记录(env, request, 访问IP, 请求类型 = "Get_SUB", config_JSON) {
|
||||
const KV容量限制 = 4;//MB
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user