// Developed by Surfboardv2ray // https://github.com/Surfboardv2ray/v2ray-refiner // Version 1.2.1 export default { async fetch(request) { return handleRequest(request); } }; async function handleRequest(request) { const headers = new Headers(); headers.set('Access-Control-Allow-Origin', '*'); headers.set('Access-Control-Allow-Methods', 'GET, POST'); headers.set('Access-Control-Allow-Headers', 'Content-Type'); if (request.headers.get('Upgrade') === 'websocket') { return handleWebSocket(request); } if (request.method === 'OPTIONS') { return new Response(null, { headers, }); } if (request.method === 'GET') { return new Response(renderHTML(), { headers: { 'content-type': 'text/html;charset=UTF-8' }, }); } else if (request.method === 'POST') { const formData = await request.formData(); const config = formData.get('config'); const cleanIp = formData.get('cleanIp'); const workerHost = new URL(request.url).hostname; try { const refinedConfig = await refineConfig(config, cleanIp, workerHost); return new Response(JSON.stringify({ refinedConfig }), { headers: { 'content-type': 'application/json', ...headers }, }); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { headers: { 'content-type': 'application/json', ...headers }, status: 400, }); } } return new Response('Method not allowed', { status: 405 }); } async function handleWebSocket(request) { const url = new URL(request.url); const newUrl = new URL("https://" + url.pathname.replace(/^\/|\/$/g, "")); return fetch(new Request(newUrl, request)); } function renderHTML() { return ` TLS Config Refiner

TLS Config Refiner

Refined Config:

`; } async function refineConfig(config, cleanIp, workerHost) { const allowedPorts = ['443', '8443', '2053', '2083', '2087', '2096']; if (config.startsWith('vmess://')) { return refineVmess(config, cleanIp, workerHost, allowedPorts); } else if (config.startsWith('vless://')) { return refineVless(config, cleanIp, workerHost, allowedPorts); } else if (config.startsWith('trojan://')) { return refineTrojan(config, cleanIp, workerHost, allowedPorts); } else { throw new Error('Invalid config format. Please enter a valid vmess, vless or trojan config with WS+TLS.'); } } function refineVmess(config, cleanIp, workerHost, allowedPorts) { const base64Data = config.slice(8); // Remove 'vmess://' const decodedString = atob(base64Data); // Decode base64 string const decoded = JSON.parse(decodeURIComponent(escape(decodedString))); // Handle non-Latin1 characters if (decoded.net !== 'ws') throw new Error('Network must be WS'); if (decoded.tls !== 'tls') throw new Error('Security must be TLS'); // Check if the input port is allowed if (!allowedPorts.includes(String(decoded.port))) { throw new Error('Config must use a Cloudflare TLS Port (443, 8443, 2053, 2083, 2087, or 2096) to proceed'); } // Preserve the original `host` and `sni` values before overwriting const originalHost = decoded.host || ''; // Original host const originalSni = decoded.sni || decoded.host || ''; // Original SNI or fallback to host // Set the port to 443 regardless of input config decoded.port = 443; decoded.add = cleanIp; // Set clean IP for "address" decoded.host = workerHost; // New worker host decoded.sni = workerHost; // New worker SNI const originalPath = decoded.path || ''; // Original path decoded.path = `/${originalSni}${originalPath}`; // Concatenated path with original SNI const newConfig = 'vmess://' + btoa(unescape(encodeURIComponent(JSON.stringify(decoded)))); return newConfig; } function refineVless(config, cleanIp, workerHost, allowedPorts) { const url = new URL(config); if (url.searchParams.get('type') !== 'ws') throw new Error('Network must be WS'); if (url.searchParams.get('security') !== 'tls') throw new Error('Security must be TLS'); // Check if the input port is allowed if (!allowedPorts.includes(url.port)) { throw new Error('Config must use a Cloudflare TLS Port (443, 8443, 2053, 2083, 2087, or 2096) to proceed'); } // Set the port to 443 regardless of input config url.port = 443; url.host = cleanIp; // Set clean IP for "address" const originalHost = url.searchParams.get('host') || ''; // Original host const originalPath = url.searchParams.get('path') || ''; // Original path url.searchParams.set('host', workerHost); url.searchParams.set('sni', workerHost); url.searchParams.set('path', `/${originalHost}${originalPath}`); // Concatenated path return url.toString(); } function refineTrojan(config, cleanIp, workerHost, allowedPorts) { const url = new URL(config); if (url.searchParams.get('type') !== 'ws') throw new Error('Network must be WS'); if (url.searchParams.get('security') !== 'tls') throw new Error('Security must be TLS'); // Check if the input port is allowed if (!allowedPorts.includes(url.port)) { throw new Error('Config must use a Cloudflare TLS Port (443, 8443, 2053, 2083, 2087, or 2096) to proceed'); } // Set the port to 443 regardless of input config url.port = 443; url.host = cleanIp; // Set clean IP for "address" const originalHost = url.searchParams.get('host') || ''; // Original host const originalPath = url.searchParams.get('path') || ''; // Original path url.searchParams.set('host', workerHost); url.searchParams.set('sni', workerHost); url.searchParams.set('path', `/${originalHost}${originalPath}`); // Concatenated path return url.toString(); }