forked from 3Kmfi6HP/EDtunnel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path_worker.js.map
8 lines (8 loc) · 39 KB
/
_worker.js.map
1
2
3
4
5
6
7
8
{
"version": 3,
"sources": ["../_worker.js"],
"sourceRoot": "minify",
"sourcesContent": ["// <!--GAMFC-->version base on commit 43fad05dcdae3b723c53c226f8181fc5bd47223e, time is 2023-06-22 15:20:02 UTC<!--GAMFC-END-->.\r\n// @ts-ignore\r\nimport { connect } from 'cloudflare:sockets';\r\n\r\n// How to generate your own UUID:\r\n// [Windows] Press \"Win + R\", input cmd and run: Powershell -NoExit -Command \"[guid]::NewGuid()\"\r\nlet userID = 'd342d11e-d424-4583-b36e-524ab1f0afa4';\r\n\r\nconst proxyIPs = ['cdn-all.xn--b6gac.eu.org', 'cdn.xn--b6gac.eu.org', 'cdn-b100.xn--b6gac.eu.org', 'edgetunnel.anycast.eu.org', 'cdn.anycast.eu.org'];\r\nlet proxyIP = proxyIPs[Math.floor(Math.random() * proxyIPs.length)];\r\n\r\nlet dohURL = 'https://sky.rethinkdns.com/1:-Pf_____9_8A_AMAIgE8kMABVDDmKOHTAKg='; // https://cloudflare-dns.com/dns-query or https://dns.google/dns-query\r\n\r\n// v2board api environment variables\r\nlet nodeId = ''; // 1\r\n\r\nlet apiToken = ''; //abcdefghijklmnopqrstuvwxyz123456\r\n\r\nlet apiHost = ''; // api.v2board.com\r\n\r\nif (!isValidUUID(userID)) {\r\n\tthrow new Error('uuid is not valid');\r\n}\r\n\r\nexport default {\r\n\t/**\r\n\t * @param {import(\"@cloudflare/workers-types\").Request} request\r\n\t * @param {{UUID: string, PROXYIP: string, DNS_RESOLVER_URL: string, NODE_ID: int, API_HOST: string, API_TOKEN: string}} env\r\n\t * @param {import(\"@cloudflare/workers-types\").ExecutionContext} ctx\r\n\t * @returns {Promise<Response>}\r\n\t */\r\n\tasync fetch(request, env, ctx) {\r\n\t\ttry {\r\n\t\t\tuserID = env.UUID || userID;\r\n\t\t\tproxyIP = env.PROXYIP || proxyIP;\r\n\t\t\tdohURL = env.DNS_RESOLVER_URL || dohURL;\r\n\t\t\tnodeId = env.NODE_ID || nodeId;\r\n\t\t\tapiToken = env.API_TOKEN || apiToken;\r\n\t\t\tapiHost = env.API_HOST || apiHost;\r\n\t\t\tconst upgradeHeader = request.headers.get('Upgrade');\r\n\t\t\tif (!upgradeHeader || upgradeHeader !== 'websocket') {\r\n\t\t\t\tconst url = new URL(request.url);\r\n\t\t\t\tswitch (url.pathname) {\r\n\t\t\t\t\tcase '/':\r\n\t\t\t\t\t\treturn new Response(JSON.stringify(request.cf, null, 4), {\r\n\t\t\t\t\t\t\tstatus: 200,\r\n\t\t\t\t\t\t\theaders: {\r\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/json;charset=utf-8\",\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\tcase '/connect': // for test connect to cf socket\r\n\t\t\t\t\t\tconst [hostname, port] = ['cloudflare.com', '80'];\r\n\t\t\t\t\t\tconsole.log(`Connecting to ${hostname}:${port}...`);\r\n\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tconst socket = await connect({\r\n\t\t\t\t\t\t\t\thostname: hostname,\r\n\t\t\t\t\t\t\t\tport: parseInt(port, 10),\r\n\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\tconst writer = socket.writable.getWriter();\r\n\r\n\t\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\t\tawait writer.write(new TextEncoder().encode('GET / HTTP/1.1\\r\\nHost: ' + hostname + '\\r\\n\\r\\n'));\r\n\t\t\t\t\t\t\t} catch (writeError) {\r\n\t\t\t\t\t\t\t\twriter.releaseLock();\r\n\t\t\t\t\t\t\t\tawait socket.close();\r\n\t\t\t\t\t\t\t\treturn new Response(writeError.message, { status: 500 });\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\twriter.releaseLock();\r\n\r\n\t\t\t\t\t\t\tconst reader = socket.readable.getReader();\r\n\t\t\t\t\t\t\tlet value;\r\n\r\n\t\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\t\tconst result = await reader.read();\r\n\t\t\t\t\t\t\t\tvalue = result.value;\r\n\t\t\t\t\t\t\t} catch (readError) {\r\n\t\t\t\t\t\t\t\tawait reader.releaseLock();\r\n\t\t\t\t\t\t\t\tawait socket.close();\r\n\t\t\t\t\t\t\t\treturn new Response(readError.message, { status: 500 });\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tawait reader.releaseLock();\r\n\t\t\t\t\t\t\tawait socket.close();\r\n\r\n\t\t\t\t\t\t\treturn new Response(new TextDecoder().decode(value), { status: 200 });\r\n\t\t\t\t\t\t} catch (connectError) {\r\n\t\t\t\t\t\t\treturn new Response(connectError.message, { status: 500 });\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\tcase `/${userID}`: {\r\n\t\t\t\t\t\tconst vlessConfig = getVLESSConfig(userID, request.headers.get('Host'));\r\n\t\t\t\t\t\treturn new Response(`${vlessConfig}`, {\r\n\t\t\t\t\t\t\tstatus: 200,\r\n\t\t\t\t\t\t\theaders: {\r\n\t\t\t\t\t\t\t\t\"Content-Type\": \"text/plain;charset=utf-8\",\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\treturn new Response('Not found', { status: 404 });\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\treturn await vlessOverWSHandler(request);\r\n\t\t\t}\r\n\t\t} catch (err) {\r\n\t\t\t/** @type {Error} */ let e = err;\r\n\t\t\treturn new Response(e.toString());\r\n\t\t}\r\n\t},\r\n};\r\n\r\n\r\n\r\n\r\n/**\r\n * \r\n * @param {import(\"@cloudflare/workers-types\").Request} request\r\n */\r\nasync function vlessOverWSHandler(request) {\r\n\r\n\t/** @type {import(\"@cloudflare/workers-types\").WebSocket[]} */\r\n\t// @ts-ignore\r\n\tconst webSocketPair = new WebSocketPair();\r\n\tconst [client, webSocket] = Object.values(webSocketPair);\r\n\r\n\twebSocket.accept();\r\n\r\n\tlet address = '';\r\n\tlet portWithRandomLog = '';\r\n\tconst log = (/** @type {string} */ info, /** @type {string | undefined} */ event) => {\r\n\t\tconsole.log(`[${address}:${portWithRandomLog}] ${info}`, event || '');\r\n\t};\r\n\tconst earlyDataHeader = request.headers.get('sec-websocket-protocol') || '';\r\n\r\n\tconst readableWebSocketStream = makeReadableWebSocketStream(webSocket, earlyDataHeader, log);\r\n\r\n\t/** @type {{ value: import(\"@cloudflare/workers-types\").Socket | null}}*/\r\n\tlet remoteSocketWapper = {\r\n\t\tvalue: null,\r\n\t};\r\n\tlet udpStreamWrite = null;\r\n\tlet isDns = false;\r\n\r\n\t// ws --> remote\r\n\treadableWebSocketStream.pipeTo(new WritableStream({\r\n\t\tasync write(chunk, controller) {\r\n\t\t\tif (isDns && udpStreamWrite) {\r\n\t\t\t\treturn udpStreamWrite(chunk);\r\n\t\t\t}\r\n\t\t\tif (remoteSocketWapper.value) {\r\n\t\t\t\tconst writer = remoteSocketWapper.value.writable.getWriter()\r\n\t\t\t\tawait writer.write(chunk);\r\n\t\t\t\twriter.releaseLock();\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconst {\r\n\t\t\t\thasError,\r\n\t\t\t\tmessage,\r\n\t\t\t\tportRemote = 443,\r\n\t\t\t\taddressRemote = '',\r\n\t\t\t\trawDataIndex,\r\n\t\t\t\tvlessVersion = new Uint8Array([0, 0]),\r\n\t\t\t\tisUDP,\r\n\t\t\t} = await processVlessHeader(chunk, userID);\r\n\t\t\taddress = addressRemote;\r\n\t\t\tportWithRandomLog = `${portRemote}--${Math.random()} ${isUDP ? 'udp ' : 'tcp '\r\n\t\t\t\t} `;\r\n\t\t\tif (hasError) {\r\n\t\t\t\t// controller.error(message);\r\n\t\t\t\tthrow new Error(message); // cf seems has bug, controller.error will not end stream\r\n\t\t\t\t// webSocket.close(1000, message);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\t// if UDP but port not DNS port, close it\r\n\t\t\tif (isUDP) {\r\n\t\t\t\tif (portRemote === 53) {\r\n\t\t\t\t\tisDns = true;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// controller.error('UDP proxy only enable for DNS which is port 53');\r\n\t\t\t\t\tthrow new Error('UDP proxy only enable for DNS which is port 53'); // cf seems has bug, controller.error will not end stream\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// [\"version\", \"\u9644\u52A0\u4FE1\u606F\u957F\u5EA6 N\"]\r\n\t\t\tconst vlessResponseHeader = new Uint8Array([vlessVersion[0], 0]);\r\n\t\t\tconst rawClientData = chunk.slice(rawDataIndex);\r\n\r\n\t\t\t// TODO: support udp here when cf runtime has udp support\r\n\t\t\tif (isDns) {\r\n\t\t\t\tconst { write } = await handleUDPOutBound(webSocket, vlessResponseHeader, log);\r\n\t\t\t\tudpStreamWrite = write;\r\n\t\t\t\tudpStreamWrite(rawClientData);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\thandleTCPOutBound(remoteSocketWapper, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log);\r\n\t\t},\r\n\t\tclose() {\r\n\t\t\tlog(`readableWebSocketStream is close`);\r\n\t\t},\r\n\t\tabort(reason) {\r\n\t\t\tlog(`readableWebSocketStream is abort`, JSON.stringify(reason));\r\n\t\t},\r\n\t})).catch((err) => {\r\n\t\tlog('readableWebSocketStream pipeTo error', err);\r\n\t});\r\n\r\n\treturn new Response(null, {\r\n\t\tstatus: 101,\r\n\t\t// @ts-ignore\r\n\t\twebSocket: client,\r\n\t});\r\n}\r\n\r\nlet apiResponseCache = null;\r\nlet cacheTimeout = null;\r\n\r\n/**\r\n * Fetches the API response from the server and caches it for future use.\r\n * @returns {Promise<object|null>} A Promise that resolves to the API response object or null if there was an error.\r\n */\r\nasync function fetchApiResponse() {\r\n\tconst requestOptions = {\r\n\t\tmethod: 'GET',\r\n\t\tredirect: 'follow'\r\n\t};\r\n\r\n\ttry {\r\n\t\tconst response = await fetch(`https://${apiHost}/api/v1/server/UniProxy/user?node_id=${nodeId}&node_type=v2ray&token=${apiToken}`, requestOptions);\r\n\r\n\t\tif (!response.ok) {\r\n\t\t\tconsole.error('Error: Network response was not ok');\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tconst apiResponse = await response.json();\r\n\t\tapiResponseCache = apiResponse;\r\n\r\n\t\t// Refresh the cache every 5 minutes (300000 milliseconds)\r\n\t\tif (cacheTimeout) {\r\n\t\t\tclearTimeout(cacheTimeout);\r\n\t\t}\r\n\t\tcacheTimeout = setTimeout(() => fetchApiResponse(), 300000);\r\n\r\n\t\treturn apiResponse;\r\n\t} catch (error) {\r\n\t\tconsole.error('Error:', error);\r\n\t\treturn null;\r\n\t}\r\n}\r\n\r\n/**\r\n * Returns the cached API response if it exists, otherwise fetches the API response from the server and caches it for future use.\r\n * @returns {Promise<object|null>} A Promise that resolves to the cached API response object or the fetched API response object, or null if there was an error.\r\n */\r\nasync function getApiResponse() {\r\n\tif (!apiResponseCache) {\r\n\t\treturn await fetchApiResponse();\r\n\t}\r\n\treturn apiResponseCache;\r\n}\r\n\r\n/**\r\n * Checks if a given UUID is present in the API response.\r\n * @param {string} targetUuid The UUID to search for.\r\n * @returns {Promise<boolean>} A Promise that resolves to true if the UUID is present in the API response, false otherwise.\r\n */\r\nasync function checkUuidInApiResponse(targetUuid) {\r\n\t// Check if any of the environment variables are empty\r\n\tif (!nodeId || !apiToken || !apiHost) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\ttry {\r\n\t\tconst apiResponse = await getApiResponse();\r\n\t\tif (!apiResponse) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\tconst isUuidInResponse = apiResponse.users.some(user => user.uuid === targetUuid);\r\n\t\treturn isUuidInResponse;\r\n\t} catch (error) {\r\n\t\tconsole.error('Error:', error);\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\n// Usage example:\r\n// const targetUuid = \"65590e04-a94c-4c59-a1f2-571bce925aad\";\r\n// checkUuidInApiResponse(targetUuid).then(result => console.log(result));\r\n\r\n/**\r\n * Handles outbound TCP connections.\r\n *\r\n * @param {any} remoteSocket \r\n * @param {string} addressRemote The remote address to connect to.\r\n * @param {number} portRemote The remote port to connect to.\r\n * @param {Uint8Array} rawClientData The raw client data to write.\r\n * @param {import(\"@cloudflare/workers-types\").WebSocket} webSocket The WebSocket to pass the remote socket to.\r\n * @param {Uint8Array} vlessResponseHeader The VLESS response header.\r\n * @param {function} log The logging function.\r\n * @returns {Promise<void>} The remote socket.\r\n */\r\nasync function handleTCPOutBound(remoteSocket, addressRemote, portRemote, rawClientData, webSocket, vlessResponseHeader, log,) {\r\n\tasync function connectAndWrite(address, port) {\r\n\t\t/** @type {import(\"@cloudflare/workers-types\").Socket} */\r\n\t\tconst tcpSocket = connect({\r\n\t\t\thostname: address,\r\n\t\t\tport: port,\r\n\t\t});\r\n\t\tremoteSocket.value = tcpSocket;\r\n\t\tlog(`connected to ${address}:${port}`);\r\n\t\tconst writer = tcpSocket.writable.getWriter();\r\n\t\tawait writer.write(rawClientData); // first write, nomal is tls client hello\r\n\t\twriter.releaseLock();\r\n\t\treturn tcpSocket;\r\n\t}\r\n\r\n\t// if the cf connect tcp socket have no incoming data, we retry to redirect ip\r\n\tasync function retry() {\r\n\t\tconst tcpSocket = await connectAndWrite(proxyIP || addressRemote, portRemote)\r\n\t\t// no matter retry success or not, close websocket\r\n\t\ttcpSocket.closed.catch(error => {\r\n\t\t\tconsole.log('retry tcpSocket closed error', error);\r\n\t\t}).finally(() => {\r\n\t\t\tsafeCloseWebSocket(webSocket);\r\n\t\t})\r\n\t\tremoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, null, log);\r\n\t}\r\n\r\n\tconst tcpSocket = await connectAndWrite(addressRemote, portRemote);\r\n\r\n\t// when remoteSocket is ready, pass to websocket\r\n\t// remote--> ws\r\n\tremoteSocketToWS(tcpSocket, webSocket, vlessResponseHeader, retry, log);\r\n}\r\n\r\n/**\r\n * \r\n * @param {import(\"@cloudflare/workers-types\").WebSocket} webSocketServer\r\n * @param {string} earlyDataHeader for ws 0rtt\r\n * @param {(info: string)=> void} log for ws 0rtt\r\n */\r\nfunction makeReadableWebSocketStream(webSocketServer, earlyDataHeader, log) {\r\n\tlet readableStreamCancel = false;\r\n\tconst stream = new ReadableStream({\r\n\t\tstart(controller) {\r\n\t\t\twebSocketServer.addEventListener('message', (event) => {\r\n\t\t\t\tif (readableStreamCancel) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tconst message = event.data;\r\n\t\t\t\tcontroller.enqueue(message);\r\n\t\t\t});\r\n\r\n\t\t\t// The event means that the client closed the client -> server stream.\r\n\t\t\t// However, the server -> client stream is still open until you call close() on the server side.\r\n\t\t\t// The WebSocket protocol says that a separate close message must be sent in each direction to fully close the socket.\r\n\t\t\twebSocketServer.addEventListener('close', () => {\r\n\t\t\t\t// client send close, need close server\r\n\t\t\t\t// if stream is cancel, skip controller.close\r\n\t\t\t\tsafeCloseWebSocket(webSocketServer);\r\n\t\t\t\tif (readableStreamCancel) {\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\tcontroller.close();\r\n\t\t\t}\r\n\t\t\t);\r\n\t\t\twebSocketServer.addEventListener('error', (err) => {\r\n\t\t\t\tlog('webSocketServer has error');\r\n\t\t\t\tcontroller.error(err);\r\n\t\t\t}\r\n\t\t\t);\r\n\t\t\t// for ws 0rtt\r\n\t\t\tconst { earlyData, error } = base64ToArrayBuffer(earlyDataHeader);\r\n\t\t\tif (error) {\r\n\t\t\t\tcontroller.error(error);\r\n\t\t\t} else if (earlyData) {\r\n\t\t\t\tcontroller.enqueue(earlyData);\r\n\t\t\t}\r\n\t\t},\r\n\r\n\t\tpull(controller) {\r\n\t\t\t// if ws can stop read if stream is full, we can implement backpressure\r\n\t\t\t// https://streams.spec.whatwg.org/#example-rs-push-backpressure\r\n\t\t},\r\n\t\tcancel(reason) {\r\n\t\t\t// 1. pipe WritableStream has error, this cancel will called, so ws handle server close into here\r\n\t\t\t// 2. if readableStream is cancel, all controller.close/enqueue need skip,\r\n\t\t\t// 3. but from testing controller.error still work even if readableStream is cancel\r\n\t\t\tif (readableStreamCancel) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlog(`ReadableStream was canceled, due to ${reason}`)\r\n\t\t\treadableStreamCancel = true;\r\n\t\t\tsafeCloseWebSocket(webSocketServer);\r\n\t\t}\r\n\t});\r\n\r\n\treturn stream;\r\n\r\n}\r\n\r\n// https://xtls.github.io/development/protocols/vless.html\r\n// https://github.com/zizifn/excalidraw-backup/blob/main/v2ray-protocol.excalidraw\r\n\r\n/**\r\n * \r\n * @param { ArrayBuffer} vlessBuffer \r\n * @param {string} userID \r\n * @returns \r\n */\r\nasync function processVlessHeader(\r\n\tvlessBuffer,\r\n\tuserID\r\n) {\r\n\tif (vlessBuffer.byteLength < 24) {\r\n\t\treturn {\r\n\t\t\thasError: true,\r\n\t\t\tmessage: 'invalid data',\r\n\t\t};\r\n\t}\r\n\tconst version = new Uint8Array(vlessBuffer.slice(0, 1));\r\n\tlet isValidUser = false;\r\n\tlet isUDP = false;\r\n\tconst slicedBuffer = new Uint8Array(vlessBuffer.slice(1, 17));\r\n\tconst slicedBufferString = stringify(slicedBuffer);\r\n\r\n\tconst uuids = userID.includes(',') ? userID.split(\",\") : [userID];\r\n\r\n\tconst checkUuidInApi = await checkUuidInApiResponse(slicedBufferString);\r\n\tisValidUser = uuids.some(userUuid => checkUuidInApi || slicedBufferString === userUuid.trim());\r\n\r\n\tconsole.log(`checkUuidInApi: ${await checkUuidInApiResponse(slicedBufferString)}, userID: ${slicedBufferString}`);\r\n\r\n\tif (!isValidUser) {\r\n\t\treturn {\r\n\t\t\thasError: true,\r\n\t\t\tmessage: 'invalid user',\r\n\t\t};\r\n\t}\r\n\r\n\tconst optLength = new Uint8Array(vlessBuffer.slice(17, 18))[0];\r\n\t//skip opt for now\r\n\r\n\tconst command = new Uint8Array(\r\n\t\tvlessBuffer.slice(18 + optLength, 18 + optLength + 1)\r\n\t)[0];\r\n\r\n\t// 0x01 TCP\r\n\t// 0x02 UDP\r\n\t// 0x03 MUX\r\n\tif (command === 1) {\r\n\t} else if (command === 2) {\r\n\t\tisUDP = true;\r\n\t} else {\r\n\t\treturn {\r\n\t\t\thasError: true,\r\n\t\t\tmessage: `command ${command} is not support, command 01-tcp,02-udp,03-mux`,\r\n\t\t};\r\n\t}\r\n\tconst portIndex = 18 + optLength + 1;\r\n\tconst portBuffer = vlessBuffer.slice(portIndex, portIndex + 2);\r\n\t// port is big-Endian in raw data etc 80 == 0x005d\r\n\tconst portRemote = new DataView(portBuffer).getUint16(0);\r\n\r\n\tlet addressIndex = portIndex + 2;\r\n\tconst addressBuffer = new Uint8Array(\r\n\t\tvlessBuffer.slice(addressIndex, addressIndex + 1)\r\n\t);\r\n\r\n\t// 1--> ipv4 addressLength =4\r\n\t// 2--> domain name addressLength=addressBuffer[1]\r\n\t// 3--> ipv6 addressLength =16\r\n\tconst addressType = addressBuffer[0];\r\n\tlet addressLength = 0;\r\n\tlet addressValueIndex = addressIndex + 1;\r\n\tlet addressValue = '';\r\n\tswitch (addressType) {\r\n\t\tcase 1:\r\n\t\t\taddressLength = 4;\r\n\t\t\taddressValue = new Uint8Array(\r\n\t\t\t\tvlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)\r\n\t\t\t).join('.');\r\n\t\t\tbreak;\r\n\t\tcase 2:\r\n\t\t\taddressLength = new Uint8Array(\r\n\t\t\t\tvlessBuffer.slice(addressValueIndex, addressValueIndex + 1)\r\n\t\t\t)[0];\r\n\t\t\taddressValueIndex += 1;\r\n\t\t\taddressValue = new TextDecoder().decode(\r\n\t\t\t\tvlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)\r\n\t\t\t);\r\n\t\t\tbreak;\r\n\t\tcase 3:\r\n\t\t\taddressLength = 16;\r\n\t\t\tconst dataView = new DataView(\r\n\t\t\t\tvlessBuffer.slice(addressValueIndex, addressValueIndex + addressLength)\r\n\t\t\t);\r\n\t\t\t// 2001:0db8:85a3:0000:0000:8a2e:0370:7334\r\n\t\t\tconst ipv6 = [];\r\n\t\t\tfor (let i = 0; i < 8; i++) {\r\n\t\t\t\tipv6.push(dataView.getUint16(i * 2).toString(16));\r\n\t\t\t}\r\n\t\t\taddressValue = ipv6.join(':');\r\n\t\t\t// seems no need add [] for ipv6\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\treturn {\r\n\t\t\t\thasError: true,\r\n\t\t\t\tmessage: `invild addressType is ${addressType}`,\r\n\t\t\t};\r\n\t}\r\n\tif (!addressValue) {\r\n\t\treturn {\r\n\t\t\thasError: true,\r\n\t\t\tmessage: `addressValue is empty, addressType is ${addressType}`,\r\n\t\t};\r\n\t}\r\n\r\n\treturn {\r\n\t\thasError: false,\r\n\t\taddressRemote: addressValue,\r\n\t\taddressType,\r\n\t\tportRemote,\r\n\t\trawDataIndex: addressValueIndex + addressLength,\r\n\t\tvlessVersion: version,\r\n\t\tisUDP,\r\n\t};\r\n}\r\n\r\n\r\n/**\r\n * \r\n * @param {import(\"@cloudflare/workers-types\").Socket} remoteSocket \r\n * @param {import(\"@cloudflare/workers-types\").WebSocket} webSocket \r\n * @param {ArrayBuffer} vlessResponseHeader \r\n * @param {(() => Promise<void>) | null} retry\r\n * @param {*} log \r\n */\r\nasync function remoteSocketToWS(remoteSocket, webSocket, vlessResponseHeader, retry, log) {\r\n\t// remote--> ws\r\n\tlet remoteChunkCount = 0;\r\n\tlet chunks = [];\r\n\t/** @type {ArrayBuffer | null} */\r\n\tlet vlessHeader = vlessResponseHeader;\r\n\tlet hasIncomingData = false; // check if remoteSocket has incoming data\r\n\tawait remoteSocket.readable\r\n\t\t.pipeTo(\r\n\t\t\tnew WritableStream({\r\n\t\t\t\tstart() {\r\n\t\t\t\t},\r\n\t\t\t\t/**\r\n\t\t\t\t * \r\n\t\t\t\t * @param {Uint8Array} chunk \r\n\t\t\t\t * @param {*} controller \r\n\t\t\t\t */\r\n\t\t\t\tasync write(chunk, controller) {\r\n\t\t\t\t\thasIncomingData = true;\r\n\t\t\t\t\t// remoteChunkCount++;\r\n\t\t\t\t\tif (webSocket.readyState !== WS_READY_STATE_OPEN) {\r\n\t\t\t\t\t\tcontroller.error(\r\n\t\t\t\t\t\t\t'webSocket.readyState is not open, maybe close'\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (vlessHeader) {\r\n\t\t\t\t\t\twebSocket.send(await new Blob([vlessHeader, chunk]).arrayBuffer());\r\n\t\t\t\t\t\tvlessHeader = null;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// seems no need rate limit this, CF seems fix this??..\r\n\t\t\t\t\t\t// if (remoteChunkCount > 20000) {\r\n\t\t\t\t\t\t// \t// cf one package is 4096 byte(4kb), 4096 * 20000 = 80M\r\n\t\t\t\t\t\t// \tawait delay(1);\r\n\t\t\t\t\t\t// }\r\n\t\t\t\t\t\twebSocket.send(chunk);\r\n\t\t\t\t\t}\r\n\t\t\t\t},\r\n\t\t\t\tclose() {\r\n\t\t\t\t\tlog(`remoteConnection!.readable is close with hasIncomingData is ${hasIncomingData}`);\r\n\t\t\t\t\t// safeCloseWebSocket(webSocket); // no need server close websocket frist for some case will casue HTTP ERR_CONTENT_LENGTH_MISMATCH issue, client will send close event anyway.\r\n\t\t\t\t},\r\n\t\t\t\tabort(reason) {\r\n\t\t\t\t\tconsole.error(`remoteConnection!.readable abort`, reason);\r\n\t\t\t\t},\r\n\t\t\t})\r\n\t\t)\r\n\t\t.catch((error) => {\r\n\t\t\tconsole.error(\r\n\t\t\t\t`remoteSocketToWS has exception `,\r\n\t\t\t\terror.stack || error\r\n\t\t\t);\r\n\t\t\tsafeCloseWebSocket(webSocket);\r\n\t\t});\r\n\r\n\t// seems is cf connect socket have error,\r\n\t// 1. Socket.closed will have error\r\n\t// 2. Socket.readable will be close without any data coming\r\n\tif (hasIncomingData === false && retry) {\r\n\t\tlog(`retry`)\r\n\t\tretry();\r\n\t}\r\n}\r\n\r\n/**\r\n * \r\n * @param {string} base64Str \r\n * @returns \r\n */\r\nfunction base64ToArrayBuffer(base64Str) {\r\n\tif (!base64Str) {\r\n\t\treturn { error: null };\r\n\t}\r\n\ttry {\r\n\t\t// go use modified Base64 for URL rfc4648 which js atob not support\r\n\t\tbase64Str = base64Str.replace(/-/g, '+').replace(/_/g, '/');\r\n\t\tconst decode = atob(base64Str);\r\n\t\tconst arryBuffer = Uint8Array.from(decode, (c) => c.charCodeAt(0));\r\n\t\treturn { earlyData: arryBuffer.buffer, error: null };\r\n\t} catch (error) {\r\n\t\treturn { error };\r\n\t}\r\n}\r\n\r\n/**\r\n * This is not real UUID validation\r\n * @param {string} uuid \r\n */\r\nfunction isValidUUID(uuid) {\r\n\tconst uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\r\n\treturn uuidRegex.test(uuid);\r\n}\r\n\r\nconst WS_READY_STATE_OPEN = 1;\r\nconst WS_READY_STATE_CLOSING = 2;\r\n/**\r\n * Normally, WebSocket will not has exceptions when close.\r\n * @param {import(\"@cloudflare/workers-types\").WebSocket} socket\r\n */\r\nfunction safeCloseWebSocket(socket) {\r\n\ttry {\r\n\t\tif (socket.readyState === WS_READY_STATE_OPEN || socket.readyState === WS_READY_STATE_CLOSING) {\r\n\t\t\tsocket.close();\r\n\t\t}\r\n\t} catch (error) {\r\n\t\tconsole.error('safeCloseWebSocket error', error);\r\n\t}\r\n}\r\n\r\nconst byteToHex = [];\r\nfor (let i = 0; i < 256; ++i) {\r\n\tbyteToHex.push((i + 256).toString(16).slice(1));\r\n}\r\nfunction unsafeStringify(arr, offset = 0) {\r\n\treturn (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + \"-\" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + \"-\" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + \"-\" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + \"-\" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();\r\n}\r\nfunction stringify(arr, offset = 0) {\r\n\tconst uuid = unsafeStringify(arr, offset);\r\n\tif (!isValidUUID(uuid)) {\r\n\t\tthrow TypeError(\"Stringified UUID is invalid\");\r\n\t}\r\n\treturn uuid;\r\n}\r\n\r\n\r\n/**\r\n * \r\n * @param {import(\"@cloudflare/workers-types\").WebSocket} webSocket \r\n * @param {ArrayBuffer} vlessResponseHeader \r\n * @param {(string)=> void} log \r\n */\r\nasync function handleUDPOutBound(webSocket, vlessResponseHeader, log) {\r\n\r\n\tlet isVlessHeaderSent = false;\r\n\tconst transformStream = new TransformStream({\r\n\t\tstart(controller) {\r\n\r\n\t\t},\r\n\t\ttransform(chunk, controller) {\r\n\t\t\t// udp message 2 byte is the the length of udp data\r\n\t\t\t// TODO: this should have bug, beacsue maybe udp chunk can be in two websocket message\r\n\t\t\tfor (let index = 0; index < chunk.byteLength;) {\r\n\t\t\t\tconst lengthBuffer = chunk.slice(index, index + 2);\r\n\t\t\t\tconst udpPakcetLength = new DataView(lengthBuffer).getUint16(0);\r\n\t\t\t\tconst udpData = new Uint8Array(\r\n\t\t\t\t\tchunk.slice(index + 2, index + 2 + udpPakcetLength)\r\n\t\t\t\t);\r\n\t\t\t\tindex = index + 2 + udpPakcetLength;\r\n\t\t\t\tcontroller.enqueue(udpData);\r\n\t\t\t}\r\n\t\t},\r\n\t\tflush(controller) {\r\n\t\t}\r\n\t});\r\n\r\n\t// only handle dns udp for now\r\n\ttransformStream.readable.pipeTo(new WritableStream({\r\n\t\tasync write(chunk) {\r\n\t\t\tconst resp = await fetch(dohURL, // dns server url\r\n\t\t\t\t{\r\n\t\t\t\t\tmethod: 'POST',\r\n\t\t\t\t\theaders: {\r\n\t\t\t\t\t\t'content-type': 'application/dns-message',\r\n\t\t\t\t\t},\r\n\t\t\t\t\tbody: chunk,\r\n\t\t\t\t})\r\n\t\t\tconst dnsQueryResult = await resp.arrayBuffer();\r\n\t\t\tconst udpSize = dnsQueryResult.byteLength;\r\n\t\t\t// console.log([...new Uint8Array(dnsQueryResult)].map((x) => x.toString(16)));\r\n\t\t\tconst udpSizeBuffer = new Uint8Array([(udpSize >> 8) & 0xff, udpSize & 0xff]);\r\n\t\t\tif (webSocket.readyState === WS_READY_STATE_OPEN) {\r\n\t\t\t\tlog(`doh success and dns message length is ${udpSize}`);\r\n\t\t\t\tif (isVlessHeaderSent) {\r\n\t\t\t\t\twebSocket.send(await new Blob([udpSizeBuffer, dnsQueryResult]).arrayBuffer());\r\n\t\t\t\t} else {\r\n\t\t\t\t\twebSocket.send(await new Blob([vlessResponseHeader, udpSizeBuffer, dnsQueryResult]).arrayBuffer());\r\n\t\t\t\t\tisVlessHeaderSent = true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t})).catch((error) => {\r\n\t\tlog('dns udp has error' + error)\r\n\t});\r\n\r\n\tconst writer = transformStream.writable.getWriter();\r\n\r\n\treturn {\r\n\t\t/**\r\n\t\t * \r\n\t\t * @param {Uint8Array} chunk \r\n\t\t */\r\n\t\twrite(chunk) {\r\n\t\t\twriter.write(chunk);\r\n\t\t}\r\n\t};\r\n}\r\n\r\n/**\r\n * \r\n * @param {string} userID \r\n * @param {string | null} hostName\r\n * @returns {string}\r\n */\r\nfunction getVLESSConfig(userID, hostName) {\r\n\tconst vlessMain = `vless://${userID}@${hostName}:443?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2048#${hostName}`\r\n\tconst vlessSec = `vless://${userID}@${proxyIP}:443?encryption=none&security=tls&sni=${hostName}&fp=randomized&type=ws&host=${hostName}&path=%2F%3Fed%3D2048#${hostName}`\r\n\treturn `\r\n################################################################\r\nv2ray default ip\r\n---------------------------------------------------------------\r\n${vlessMain}\r\n---------------------------------------------------------------\r\n################################################################\r\nv2ray with best ip\r\n---------------------------------------------------------------\r\n${vlessSec}\r\n---------------------------------------------------------------\r\n################################################################\r\nclash-meta\r\n---------------------------------------------------------------\r\n- type: vless\r\n name: ${hostName}\r\n server: ${hostName}\r\n port: 443\r\n uuid: ${userID}\r\n network: ws\r\n tls: true\r\n udp: false\r\n sni: ${hostName}\r\n client-fingerprint: chrome\r\n ws-opts:\r\n path: \"/?ed=2048\"\r\n headers:\r\n host: ${hostName}\r\n---------------------------------------------------------------\r\n################################################################\r\n`;\r\n}\r\n"],
"mappings": "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",
"names": ["connect", "userID", "proxyIPs", "proxyIP", "dohURL", "nodeId", "apiToken", "apiHost", "isValidUUID", "worker_default", "request", "env", "ctx", "upgradeHeader", "hostname", "port", "socket", "writer", "writeError", "reader", "value", "readError", "connectError", "vlessConfig", "getVLESSConfig", "vlessOverWSHandler", "err", "e", "webSocketPair", "client", "webSocket", "address", "portWithRandomLog", "log", "info", "event", "earlyDataHeader", "readableWebSocketStream", "makeReadableWebSocketStream", "remoteSocketWapper", "udpStreamWrite", "isDns", "chunk", "controller", "hasError", "message", "portRemote", "addressRemote", "rawDataIndex", "vlessVersion", "isUDP", "processVlessHeader", "vlessResponseHeader", "rawClientData", "write", "handleUDPOutBound", "handleTCPOutBound", "reason", "apiResponseCache", "cacheTimeout", "fetchApiResponse", "requestOptions", "response", "apiResponse", "error", "getApiResponse", "checkUuidInApiResponse", "targetUuid", "user", "remoteSocket", "connectAndWrite", "tcpSocket", "retry", "safeCloseWebSocket", "remoteSocketToWS", "webSocketServer", "readableStreamCancel", "earlyData", "base64ToArrayBuffer", "vlessBuffer", "version", "isValidUser", "slicedBuffer", "slicedBufferString", "stringify", "uuids", "checkUuidInApi", "userUuid", "optLength", "command", "portIndex", "portBuffer", "addressIndex", "addressType", "addressLength", "addressValueIndex", "addressValue", "dataView", "ipv6", "i", "remoteChunkCount", "chunks", "vlessHeader", "hasIncomingData", "WS_READY_STATE_OPEN", "base64Str", "decode", "c", "uuid", "WS_READY_STATE_CLOSING", "byteToHex", "unsafeStringify", "arr", "offset", "isVlessHeaderSent", "transformStream", "index", "lengthBuffer", "udpPakcetLength", "udpData", "dnsQueryResult", "udpSize", "udpSizeBuffer", "hostName", "vlessMain", "vlessSec"]
}