diff --git a/index.js b/index.js index 095f1ec4..f9351475 100644 --- a/index.js +++ b/index.js @@ -69,24 +69,15 @@ export default { userID = UUID || userID; socks5Address = SOCKS5 || socks5Address; socks5Relay = SOCKS5_RELAY || socks5Relay; - if (PROXYIP) { - // Split PROXYIP into an array of proxy addresses - const proxyAddresses = PROXYIP.split(',').map(addr => addr.trim()); - // Randomly select one proxy address - const selectedProxy = proxyAddresses[Math.floor(Math.random() * proxyAddresses.length)]; - [proxyIP, proxyPort = '443'] = selectedProxy.split(':'); - } else { - proxyPort = proxyIP.includes(':') ? proxyIP.split(':')[1] : '443'; - proxyIP = proxyIP.split(':')[0]; - } - console.log('ProxyIP:', proxyIP); - console.log('ProxyPort:', proxyPort); + + // Handle proxy configuration + const proxyConfig = handleProxyConfig(PROXYIP); + proxyIP = proxyConfig.ip; + proxyPort = proxyConfig.port; + if (socks5Address) { try { - // Split SOCKS5 into an array of addresses - const socks5Addresses = socks5Address.split(',').map(addr => addr.trim()); - // Randomly select one SOCKS5 address - const selectedSocks5 = socks5Addresses[Math.floor(Math.random() * socks5Addresses.length)]; + const selectedSocks5 = selectRandomAddress(socks5Address); parsedSocks5Address = socks5AddressParser(selectedSocks5); enableSocks = true; } catch (err) { @@ -95,32 +86,49 @@ export default { } } - const userID_Path = userID.includes(',') ? userID.split(',')[0] : userID; + const userIDs = userID.split(',').map(id => id.trim()); const url = new URL(request.url); const host = request.headers.get('Host'); + const requestedPath = url.pathname.substring(1); // Remove leading slash + const matchingUserID = userIDs.find(id => { + // Check if the path starts with the UUID or sub/UUID or bestip/UUID + const patterns = [ + id, + `sub/${id}`, + `bestip/${id}` + ]; + return patterns.some(pattern => requestedPath.startsWith(pattern)); + }); if (request.headers.get('Upgrade') !== 'websocket') { - switch (url.pathname) { - case '/cf': - return new Response(JSON.stringify(request.cf, null, 4), { - status: 200, - headers: { "Content-Type": "application/json;charset=utf-8" }, - }); - case `/${userID_Path}`: - return new Response(getConfig(userID, host), { - status: 200, - headers: { "Content-Type": "text/html; charset=utf-8" }, - }); - case `/sub/${userID_Path}`: - return new Response(btoa(GenSub(userID, host)), { + if (url.pathname === '/cf') { + return new Response(JSON.stringify(request.cf, null, 4), { + status: 200, + headers: { "Content-Type": "application/json;charset=utf-8" }, + }); + } + + if (matchingUserID) { + if (url.pathname === `/${matchingUserID}` || url.pathname === `/sub/${matchingUserID}`) { + const isSubscription = url.pathname.startsWith('/sub/'); + const proxyAddresses = PROXYIP ? PROXYIP.split(',').map(addr => addr.trim()) : proxyIP; + const content = isSubscription ? + GenSub(matchingUserID, host, proxyAddresses) : + getConfig(matchingUserID, host, proxyAddresses); + + return new Response(content, { status: 200, - headers: { "Content-Type": "text/plain;charset=utf-8" }, + headers: { + "Content-Type": isSubscription ? + "text/plain;charset=utf-8" : + "text/html; charset=utf-8" + }, }); - case `/bestip/${userID_Path}`: - return fetch(`https://sub.xf.free.hr/auto?host=${host}&uuid=${userID}&path=/`, { headers: request.headers }); - default: - return handleDefaultPath(url, request); + } else if (url.pathname === `/bestip/${matchingUserID}`) { + return fetch(`https://sub.xf.free.hr/auto?host=${host}&uuid=${matchingUserID}&path=/`, { headers: request.headers }); + } } + return handleDefaultPath(url, request); } else { return await ProtocolOverWSHandler(request); } @@ -482,16 +490,16 @@ async function ProtocolOverWSHandler(request) { /** * Handles outbound TCP connections for the proxy. * Establishes connection to remote server and manages data flow. - * @param {Socket} remoteSocket - Socket for remote connection + * @param {Socket} remoteSocket - Remote socket connection * @param {string} addressType - Type of address (IPv4/IPv6) * @param {string} addressRemote - Remote server address * @param {number} portRemote - Remote server port * @param {Uint8Array} rawClientData - Raw data from client * @param {WebSocket} webSocket - WebSocket connection - * @param {Uint8Array} ProtocolResponseHeader - Protocol response header + * @param {Uint8Array} protocolResponseHeader - Protocol response header * @param {Function} log - Logging function */ -async function HandleTCPOutBound(remoteSocket, addressType, addressRemote, portRemote, rawClientData, webSocket, ProtocolResponseHeader, log,) { +async function HandleTCPOutBound(remoteSocket, addressType, addressRemote, portRemote, rawClientData, webSocket, protocolResponseHeader, log,) { async function connectAndWrite(address, port, socks = false) { /** @type {import("@cloudflare/workers-types").Socket} */ let tcpSocket; @@ -525,14 +533,14 @@ async function HandleTCPOutBound(remoteSocket, addressType, addressRemote, portR }).finally(() => { safeCloseWebSocket(webSocket); }) - RemoteSocketToWS(tcpSocket, webSocket, ProtocolResponseHeader, null, log); + RemoteSocketToWS(tcpSocket, webSocket, protocolResponseHeader, null, log); } let tcpSocket = await connectAndWrite(addressRemote, portRemote); // when remoteSocket is ready, pass to websocket // remote--> ws - RemoteSocketToWS(tcpSocket, webSocket, ProtocolResponseHeader, retry, log); + RemoteSocketToWS(tcpSocket, webSocket, protocolResponseHeader, retry, log); } /** @@ -1039,9 +1047,10 @@ const ed = 'RUR0dW5uZWw='; * Generates configuration for VLESS client. * @param {string} userIDs - Single or comma-separated user IDs * @param {string} hostName - Host name for configuration + * @param {string|string[]} proxyIP - Proxy IP address or array of addresses * @returns {string} Configuration HTML */ -function getConfig(userIDs, hostName) { +function getConfig(userIDs, hostName, proxyIP) { const commonUrlPart = `?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2048#${hostName}`; // Split the userIDs into an array @@ -1050,7 +1059,7 @@ function getConfig(userIDs, hostName) { // Prepare output string for each userID const sublink = `https://${hostName}/sub/${userIDArray[0]}?format=clash` const subbestip = `https://${hostName}/bestip/${userIDArray[0]}`; - 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`; + 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`; // HTML Head with CSS and FontAwesome library const htmlHead = `
@@ -1061,12 +1070,12 @@ function getConfig(userIDs, hostName) { - + - + @@ -1191,7 +1200,7 @@ function getConfig(userIDs, hostName) { const header = `Welcome! This function generates configuration for the vless protocol. If you found this useful, please check our GitHub project:
EDtunnel - https://github.com/6Kmfi6HP/EDtunnel
@@ -1216,7 +1225,7 @@ function getConfig(userIDs, hostName) { const configOutput = userIDArray.map((userID) => { const protocolMain = atob(pt) + '://' + userID + atob(at) + hostName + ":443" + commonUrlPart; - const protocolSec = atob(pt) + '://' + userID + atob(at) + proxyIP + ":" + proxyPort + commonUrlPart; + const protocolSec = atob(pt) + '://' + userID + atob(at) + proxyIP[0].split(':')[0] + ":" + proxyPort + commonUrlPart; return `${protocolSec}
-
+ ${protocolSec}
+