Skip to content

Commit 8f76bc1

Browse files
committed
Refactor proxy handling and improve user ID matching logic in index.js
- Simplified proxy configuration by introducing handleProxyConfig and selectRandomAddress functions. - Enhanced user ID handling to support multiple IDs and improved path matching. - Updated response handling for subscription and configuration generation. - Fixed references to proxy IP and port in configuration generation. - Updated HTML output for better user experience with dynamic proxy selection.
1 parent 328b84c commit 8f76bc1

File tree

1 file changed

+188
-79
lines changed

1 file changed

+188
-79
lines changed

index.js

Lines changed: 188 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,15 @@ export default {
6969
userID = UUID || userID;
7070
socks5Address = SOCKS5 || socks5Address;
7171
socks5Relay = SOCKS5_RELAY || socks5Relay;
72-
if (PROXYIP) {
73-
// Split PROXYIP into an array of proxy addresses
74-
const proxyAddresses = PROXYIP.split(',').map(addr => addr.trim());
75-
// Randomly select one proxy address
76-
const selectedProxy = proxyAddresses[Math.floor(Math.random() * proxyAddresses.length)];
77-
[proxyIP, proxyPort = '443'] = selectedProxy.split(':');
78-
} else {
79-
proxyPort = proxyIP.includes(':') ? proxyIP.split(':')[1] : '443';
80-
proxyIP = proxyIP.split(':')[0];
81-
}
82-
console.log('ProxyIP:', proxyIP);
83-
console.log('ProxyPort:', proxyPort);
72+
73+
// Handle proxy configuration
74+
const proxyConfig = handleProxyConfig(PROXYIP);
75+
proxyIP = proxyConfig.ip;
76+
proxyPort = proxyConfig.port;
77+
8478
if (socks5Address) {
8579
try {
86-
// Split SOCKS5 into an array of addresses
87-
const socks5Addresses = socks5Address.split(',').map(addr => addr.trim());
88-
// Randomly select one SOCKS5 address
89-
const selectedSocks5 = socks5Addresses[Math.floor(Math.random() * socks5Addresses.length)];
80+
const selectedSocks5 = selectRandomAddress(socks5Address);
9081
parsedSocks5Address = socks5AddressParser(selectedSocks5);
9182
enableSocks = true;
9283
} catch (err) {
@@ -95,32 +86,49 @@ export default {
9586
}
9687
}
9788

98-
const userID_Path = userID.includes(',') ? userID.split(',')[0] : userID;
89+
const userIDs = userID.split(',').map(id => id.trim());
9990
const url = new URL(request.url);
10091
const host = request.headers.get('Host');
92+
const requestedPath = url.pathname.substring(1); // Remove leading slash
93+
const matchingUserID = userIDs.find(id => {
94+
// Check if the path starts with the UUID or sub/UUID or bestip/UUID
95+
const patterns = [
96+
id,
97+
`sub/${id}`,
98+
`bestip/${id}`
99+
];
100+
return patterns.some(pattern => requestedPath.startsWith(pattern));
101+
});
101102

102103
if (request.headers.get('Upgrade') !== 'websocket') {
103-
switch (url.pathname) {
104-
case '/cf':
105-
return new Response(JSON.stringify(request.cf, null, 4), {
106-
status: 200,
107-
headers: { "Content-Type": "application/json;charset=utf-8" },
108-
});
109-
case `/${userID_Path}`:
110-
return new Response(getConfig(userID, host), {
111-
status: 200,
112-
headers: { "Content-Type": "text/html; charset=utf-8" },
113-
});
114-
case `/sub/${userID_Path}`:
115-
return new Response(btoa(GenSub(userID, host)), {
104+
if (url.pathname === '/cf') {
105+
return new Response(JSON.stringify(request.cf, null, 4), {
106+
status: 200,
107+
headers: { "Content-Type": "application/json;charset=utf-8" },
108+
});
109+
}
110+
111+
if (matchingUserID) {
112+
if (url.pathname === `/${matchingUserID}` || url.pathname === `/sub/${matchingUserID}`) {
113+
const isSubscription = url.pathname.startsWith('/sub/');
114+
const proxyAddresses = PROXYIP ? PROXYIP.split(',').map(addr => addr.trim()) : proxyIP;
115+
const content = isSubscription ?
116+
GenSub(matchingUserID, host, proxyAddresses) :
117+
getConfig(matchingUserID, host, proxyAddresses);
118+
119+
return new Response(content, {
116120
status: 200,
117-
headers: { "Content-Type": "text/plain;charset=utf-8" },
121+
headers: {
122+
"Content-Type": isSubscription ?
123+
"text/plain;charset=utf-8" :
124+
"text/html; charset=utf-8"
125+
},
118126
});
119-
case `/bestip/${userID_Path}`:
120-
return fetch(`https://sub.xf.free.hr/auto?host=${host}&uuid=${userID}&path=/`, { headers: request.headers });
121-
default:
122-
return handleDefaultPath(url, request);
127+
} else if (url.pathname === `/bestip/${matchingUserID}`) {
128+
return fetch(`https://sub.xf.free.hr/auto?host=${host}&uuid=${matchingUserID}&path=/`, { headers: request.headers });
129+
}
123130
}
131+
return handleDefaultPath(url, request);
124132
} else {
125133
return await ProtocolOverWSHandler(request);
126134
}
@@ -482,16 +490,16 @@ async function ProtocolOverWSHandler(request) {
482490
/**
483491
* Handles outbound TCP connections for the proxy.
484492
* Establishes connection to remote server and manages data flow.
485-
* @param {Socket} remoteSocket - Socket for remote connection
493+
* @param {Socket} remoteSocket - Remote socket connection
486494
* @param {string} addressType - Type of address (IPv4/IPv6)
487495
* @param {string} addressRemote - Remote server address
488496
* @param {number} portRemote - Remote server port
489497
* @param {Uint8Array} rawClientData - Raw data from client
490498
* @param {WebSocket} webSocket - WebSocket connection
491-
* @param {Uint8Array} ProtocolResponseHeader - Protocol response header
499+
* @param {Uint8Array} protocolResponseHeader - Protocol response header
492500
* @param {Function} log - Logging function
493501
*/
494-
async function HandleTCPOutBound(remoteSocket, addressType, addressRemote, portRemote, rawClientData, webSocket, ProtocolResponseHeader, log,) {
502+
async function HandleTCPOutBound(remoteSocket, addressType, addressRemote, portRemote, rawClientData, webSocket, protocolResponseHeader, log,) {
495503
async function connectAndWrite(address, port, socks = false) {
496504
/** @type {import("@cloudflare/workers-types").Socket} */
497505
let tcpSocket;
@@ -525,14 +533,14 @@ async function HandleTCPOutBound(remoteSocket, addressType, addressRemote, portR
525533
}).finally(() => {
526534
safeCloseWebSocket(webSocket);
527535
})
528-
RemoteSocketToWS(tcpSocket, webSocket, ProtocolResponseHeader, null, log);
536+
RemoteSocketToWS(tcpSocket, webSocket, protocolResponseHeader, null, log);
529537
}
530538

531539
let tcpSocket = await connectAndWrite(addressRemote, portRemote);
532540

533541
// when remoteSocket is ready, pass to websocket
534542
// remote--> ws
535-
RemoteSocketToWS(tcpSocket, webSocket, ProtocolResponseHeader, retry, log);
543+
RemoteSocketToWS(tcpSocket, webSocket, protocolResponseHeader, retry, log);
536544
}
537545

538546
/**
@@ -1039,9 +1047,10 @@ const ed = 'RUR0dW5uZWw=';
10391047
* Generates configuration for VLESS client.
10401048
* @param {string} userIDs - Single or comma-separated user IDs
10411049
* @param {string} hostName - Host name for configuration
1050+
* @param {string|string[]} proxyIP - Proxy IP address or array of addresses
10421051
* @returns {string} Configuration HTML
10431052
*/
1044-
function getConfig(userIDs, hostName) {
1053+
function getConfig(userIDs, hostName, proxyIP) {
10451054
const commonUrlPart = `?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2048#${hostName}`;
10461055

10471056
// Split the userIDs into an array
@@ -1050,7 +1059,7 @@ function getConfig(userIDs, hostName) {
10501059
// Prepare output string for each userID
10511060
const sublink = `https://${hostName}/sub/${userIDArray[0]}?format=clash`
10521061
const subbestip = `https://${hostName}/bestip/${userIDArray[0]}`;
1053-
const clash_link = `https://url.v1.mk/sub?target=clash&url=${encodeURIComponent(sublink)}&insert=false&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`;
1062+
const clash_link = `https://url.v1.mk/sub?target=clash&url=${encodeURIComponent(`https://${hostName}/sub/${userIDArray[0]}?format=clash`)}&insert=false&emoji=true&list=false&tfo=false&scv=true&fdn=false&sort=false&new_name=true`;
10541063
// HTML Head with CSS and FontAwesome library
10551064
const htmlHead = `
10561065
<head>
@@ -1061,12 +1070,12 @@ function getConfig(userIDs, hostName) {
10611070
<meta property='og:title' content='EDtunnel - Protocol Configuration and Subscribe Output' />
10621071
<meta property='og:description' content='Use Cloudflare Pages and Worker serverless to implement protocol' />
10631072
<meta property='og:url' content='https://${hostName}/' />
1064-
<meta property='og:image' content='https://ipfs.io/ipfs/bafybeigd6i5aavwpr6wvnwuyayklq3omonggta4x2q7kpmgafj357nkcky' />
1073+
<meta property='og:image' content='https://cdn.jsdelivr.net/gh/6Kmfi6HP/EDtunnel@refs/heads/main/image/logo.png' />
10651074
<meta name='twitter:card' content='summary_large_image' />
10661075
<meta name='twitter:title' content='EDtunnel - Protocol Configuration and Subscribe Output' />
10671076
<meta name='twitter:description' content='Use Cloudflare Pages and Worker serverless to implement protocol' />
10681077
<meta name='twitter:url' content='https://${hostName}/' />
1069-
<meta name='twitter:image' content='https://ipfs.io/ipfs/bafybeigd6i5aavwpr6wvnwuyayklq3omonggta4x2q7kpmgafj357nkcky' />
1078+
<meta name='twitter:image' content='https://cdn.jsdelivr.net/gh/6Kmfi6HP/EDtunnel@refs/heads/main/image/logo.png' />
10701079
<meta property='og:image:width' content='1500' />
10711080
<meta property='og:image:height' content='1500' />
10721081
@@ -1191,7 +1200,7 @@ function getConfig(userIDs, hostName) {
11911200
const header = `
11921201
<div class="container">
11931202
<h1>EDtunnel: Protocol Configuration</h1>
1194-
<img src="https://ipfs.io/ipfs/bafybeigd6i5aavwpr6wvnwuyayklq3omonggta4x2q7kpmgafj357nkcky" alt="EDtunnel Logo" class="logo">
1203+
<img src="https://cdn.jsdelivr.net/gh/6Kmfi6HP/EDtunnel@refs/heads/main/image/logo.png" alt="EDtunnel Logo" class="logo">
11951204
<p>Welcome! This function generates configuration for the vless protocol. If you found this useful, please check our GitHub project:</p>
11961205
<p><a href="https://github.com/6Kmfi6HP/EDtunnel" target="_blank" style="color: #00ff00;">EDtunnel - https://github.com/6Kmfi6HP/EDtunnel</a></p>
11971206
<div style="clear: both;"></div>
@@ -1216,7 +1225,7 @@ function getConfig(userIDs, hostName) {
12161225

12171226
const configOutput = userIDArray.map((userID) => {
12181227
const protocolMain = atob(pt) + '://' + userID + atob(at) + hostName + ":443" + commonUrlPart;
1219-
const protocolSec = atob(pt) + '://' + userID + atob(at) + proxyIP + ":" + proxyPort + commonUrlPart;
1228+
const protocolSec = atob(pt) + '://' + userID + atob(at) + proxyIP[0].split(':')[0] + ":" + proxyPort + commonUrlPart;
12201229
return `
12211230
<div class="container config-item">
12221231
<h2>UUID: ${userID}</h2>
@@ -1227,9 +1236,15 @@ function getConfig(userIDs, hostName) {
12271236
</div>
12281237
12291238
<h3>Best IP Configuration</h3>
1239+
<div class="input-group mb-3">
1240+
<select class="form-select" id="proxySelect" onchange="updateProxyConfig()">
1241+
${Array.from(proxyIP).map(proxy => `<option value="${proxy}">${proxy}</option>`).join('')}
1242+
</select>
1243+
</div>
1244+
<br>
12301245
<div class="code-container">
1231-
<pre><code>${protocolSec}</code></pre>
1232-
<button class="btn copy-btn" onclick='copyToClipboard("${protocolSec}")'><i class="fas fa-copy"></i> Copy</button>
1246+
<pre><code id="proxyConfig">${protocolSec}</code></pre>
1247+
<button class="btn copy-btn" onclick='copyToClipboard(document.getElementById("proxyConfig").textContent)'><i class="fas fa-copy"></i> Copy</button>
12331248
</div>
12341249
</div>
12351250
`;
@@ -1241,18 +1256,31 @@ function getConfig(userIDs, hostName) {
12411256
<body>
12421257
${header}
12431258
${configOutput}
1259+
<script>
1260+
const userIDArray = ${JSON.stringify(userIDArray)};
1261+
const pt = "${pt}";
1262+
const at = "${at}";
1263+
const commonUrlPart = "?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2048#${hostName}";
1264+
1265+
function copyToClipboard(text) {
1266+
navigator.clipboard.writeText(text)
1267+
.then(() => {
1268+
alert("Copied to clipboard");
1269+
})
1270+
.catch((err) => {
1271+
console.error("Failed to copy to clipboard:", err);
1272+
});
1273+
}
1274+
1275+
function updateProxyConfig() {
1276+
const select = document.getElementById('proxySelect');
1277+
const proxyValue = select.value;
1278+
const [host, port] = proxyValue.split(':');
1279+
const protocolSec = atob(pt) + '://' + userIDArray[0] + atob(at) + host + ":" + port + commonUrlPart;
1280+
document.getElementById("proxyConfig").textContent = protocolSec;
1281+
}
1282+
</script>
12441283
</body>
1245-
<script>
1246-
function copyToClipboard(text) {
1247-
navigator.clipboard.writeText(text)
1248-
.then(() => {
1249-
alert("Copied to clipboard");
1250-
})
1251-
.catch((err) => {
1252-
console.error("Failed to copy to clipboard:", err);
1253-
});
1254-
}
1255-
</script>
12561284
</html>`;
12571285
}
12581286

@@ -1263,38 +1291,119 @@ const HttpsPort = new Set([443, 8443, 2053, 2096, 2087, 2083]);
12631291
* Generates subscription content.
12641292
* @param {string} userID_path - User ID path
12651293
* @param {string} hostname - Host name
1294+
* @param {string|string[]} proxyIP - Proxy IP address or array of addresses
12661295
* @returns {string} Subscription content
12671296
*/
1268-
function GenSub(userID_path, hostname) {
1269-
const userIDArray = userID_path.includes(',') ? userID_path.split(',') : [userID_path];
1297+
function GenSub(userID_path, hostname, proxyIP) {
1298+
// Add all CloudFlare public CNAME domains
1299+
const mainDomains = new Set([
1300+
hostname,
1301+
// public domains
1302+
'icook.hk',
1303+
'japan.com',
1304+
'malaysia.com',
1305+
'russia.com',
1306+
'singapore.com',
1307+
'www.visa.com',
1308+
'www.csgo.com',
1309+
'www.shopify.com',
1310+
'www.whatismyip.com',
1311+
'www.ipget.net',
1312+
// 高频率更新
1313+
'speed.marisalnc.com', // 1000ip/3min
1314+
'freeyx.cloudflare88.eu.org', // 1000ip/3min
1315+
'cloudflare.182682.xyz', // 15ip/15min
1316+
'115155.xyz', // 18ip/1小时
1317+
'cdn.2020111.xyz', // 15ip/10min
1318+
'cfip.cfcdn.vip', // 6ip/1天
1319+
proxyIPs,
1320+
// 手动更新和未知频率
1321+
'cf.0sm.com', // 手动更新
1322+
'cloudflare-ip.mofashi.ltd', // 未知频率
1323+
'cf.090227.xyz', // 未知频率
1324+
'cname.xirancdn.us', // 未知频率
1325+
'f3058171cad.002404.xyz', // 未知频率
1326+
'cf.zhetengsha.eu.org', // 未知频率
1327+
'cloudflare.9jy.cc', // 未知频率
1328+
'8.889288.xyz', // 未知频率
1329+
'cf.zerone-cdn.pp.ua', // 未知频率
1330+
'cfip.1323123.xyz', // 未知频率
1331+
'cdn.tzpro.xyz', // 未知频率
1332+
'cf.877771.xyz', // 未知频率
1333+
'cnamefuckxxs.yuchen.icu', // 未知频率
1334+
'cfip.xxxxxxxx.tk', // OTC大佬提供维护
1335+
]);
1336+
1337+
const userIDArray = userID_path.includes(',') ? userID_path.split(",") : [userID_path];
1338+
const proxyIPArray = Array.isArray(proxyIP) ? proxyIP : (proxyIP ? (proxyIP.includes(',') ? proxyIP.split(',') : [proxyIP]) : proxyIPs);
12701339
const randomPath = () => '/' + Math.random().toString(36).substring(2, 15) + '?ed=2048';
12711340
const commonUrlPartHttp = `?encryption=none&security=none&fp=random&type=ws&host=${hostname}&path=${encodeURIComponent(randomPath())}#`;
1272-
const commonUrlPartHttps = `?encryption=none&security=tls&sni=${hostname}&fp=random&type=ws&host=${hostname}&path=%2F%3Fed%3D2048#`;
1341+
const commonUrlPartHttps = `?encryption=none&security=tls&sni=${hostname}&fp=random&type=ws&host=${hostname}&path=%2F%3Fed%3D2048#${hostname}`;
12731342

12741343
const result = userIDArray.flatMap((userID) => {
1275-
const PartHttp = Array.from(HttpPort).flatMap((port) => {
1276-
if (!hostname.includes('pages.dev')) {
1277-
const urlPart = `${hostname}-HTTP-${port}`;
1278-
const mainProtocolHttp = atob(pt) + '://' + userID + atob(at) + hostname + ':' + port + commonUrlPartHttp + urlPart;
1279-
return proxyIPs.flatMap((proxyIP) => {
1280-
const secondaryProtocolHttp = atob(pt) + '://' + userID + atob(at) + proxyIP.split(':')[0] + ':' + proxyPort + commonUrlPartHttp + urlPart + '-' + proxyIP + '-' + atob(ed);
1281-
return [mainProtocolHttp, secondaryProtocolHttp];
1344+
let allUrls = [];
1345+
// Generate main HTTP URLs first for all domains
1346+
if (!hostname.includes('pages.dev')) {
1347+
mainDomains.forEach(domain => {
1348+
Array.from(HttpPort).forEach((port) => {
1349+
const urlPart = `${hostname.split('.')[0]}-HTTP-${port}`;
1350+
const mainProtocolHttp = atob(pt) + '://' + userID + atob(at) + domain + ':' + port + commonUrlPartHttp + urlPart;
1351+
allUrls.push(mainProtocolHttp);
12821352
});
1283-
}
1284-
return [];
1353+
});
1354+
}
1355+
1356+
// Generate main HTTPS URLs for all domains
1357+
mainDomains.forEach(domain => {
1358+
Array.from(HttpsPort).forEach((port) => {
1359+
const urlPart = `${hostname.split('.')[0]}-HTTPS-${port}`;
1360+
const mainProtocolHttps = atob(pt) + '://' + userID + atob(at) + domain + ':' + port + commonUrlPartHttps + urlPart;
1361+
allUrls.push(mainProtocolHttps);
1362+
});
12851363
});
12861364

1287-
const PartHttps = Array.from(HttpsPort).flatMap((port) => {
1288-
const urlPart = `${hostname}-HTTPS-${port}`;
1289-
const mainProtocolHttps = atob(pt) + '://' + userID + atob(at) + hostname + ':' + port + commonUrlPartHttps + urlPart;
1290-
return proxyIPs.flatMap((proxyIP) => {
1291-
const secondaryProtocolHttps = atob(pt) + '://' + userID + atob(at) + proxyIP.split(':')[0] + ':' + proxyPort + commonUrlPartHttps + urlPart + '-' + proxyIP + '-' + atob(ed);
1292-
return [mainProtocolHttps, secondaryProtocolHttps];
1365+
// Generate proxy HTTPS URLs
1366+
proxyIPArray.forEach((proxyAddr) => {
1367+
const [proxyHost, proxyPort] = proxyAddr.split(':');
1368+
Array.from(HttpsPort).forEach((port) => {
1369+
const urlPart = `${hostname.split('.')[0]}-HTTPS-${port}`;
1370+
const secondaryProtocolHttps = atob(pt) + '://' + userID + atob(at) + proxyHost + ':' + proxyPort + commonUrlPartHttps + urlPart + '-' + proxyAddr + '-' + atob(ed);
1371+
allUrls.push(secondaryProtocolHttps);
12931372
});
12941373
});
12951374

1296-
return [...PartHttp, ...PartHttps];
1375+
return allUrls;
12971376
});
12981377

1299-
return result.join('\n');
1378+
return btoa(result.join('\n'));
1379+
}
1380+
1381+
/**
1382+
* Handles proxy configuration and returns standardized proxy settings
1383+
* @param {string} PROXYIP - Proxy IP configuration from environment
1384+
* @returns {{ip: string, port: string}} Standardized proxy configuration
1385+
*/
1386+
function handleProxyConfig(PROXYIP) {
1387+
if (PROXYIP) {
1388+
const proxyAddresses = PROXYIP.split(',').map(addr => addr.trim());
1389+
const selectedProxy = selectRandomAddress(proxyAddresses);
1390+
const [ip, port = '443'] = selectedProxy.split(':');
1391+
return { ip, port };
1392+
} else {
1393+
const port = proxyIP.includes(':') ? proxyIP.split(':')[1] : '443';
1394+
const ip = proxyIP.split(':')[0];
1395+
return { ip, port };
1396+
}
1397+
}
1398+
1399+
/**
1400+
* Selects a random address from a comma-separated string or array of addresses
1401+
* @param {string|string[]} addresses - Comma-separated string or array of addresses
1402+
* @returns {string} Selected address
1403+
*/
1404+
function selectRandomAddress(addresses) {
1405+
const addressArray = typeof addresses === 'string' ?
1406+
addresses.split(',').map(addr => addr.trim()) :
1407+
addresses;
1408+
return addressArray[Math.floor(Math.random() * addressArray.length)];
13001409
}

0 commit comments

Comments
 (0)