// cloudflare-worker-dashboard-complete.js export default { async fetch(request, env, ctx) { const url = new URL(request.url); // Handle CORS preflight if (request.method === "OPTIONS") { return new Response(null, { headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization", }, }); } // Serve UI for root path if (url.pathname === "/" || url.pathname === "/index.html") { return serveDashboard(); } // API endpoints if (url.pathname === "/api/createWorker" && request.method === "POST") { return await handleCreateWorker(request); } if (url.pathname === "/api/userInfo" && request.method === "POST") { return await handleUserInfo(request); } if (url.pathname === "/api/listWorkers" && request.method === "POST") { return await handleListWorkers(request); } if (url.pathname === "/api/accounts" && request.method === "POST") { return await handleGetAccounts(request); } if (url.pathname === "/api/deleteWorker" && request.method === "POST") { return await handleDeleteWorker(request); } if (url.pathname === "/api/updateWorker" && request.method === "POST") { return await handleUpdateWorker(request); } if (url.pathname === "/api/getWorkerScript" && request.method === "POST") { return await handleGetWorkerScript(request); } if (url.pathname === "/api/bulkDeleteWorkers" && request.method === "POST") { return await handleBulkDeleteWorkers(request); } if (url.pathname === "/api/bulkCreateWorkers" && request.method === "POST") { return await handleBulkCreateWorkers(request); } if (url.pathname === "/api/workerAnalytics" && request.method === "POST") { return await handleWorkerAnalytics(request); } if (url.pathname === "/api/exportConfig" && request.method === "POST") { return await handleExportConfig(request); } if (url.pathname === "/api/importConfig" && request.method === "POST") { return await handleImportConfig(request); } // New endpoint untuk generate proxy IP if (url.pathname === "/api/generateProxyIP" && request.method === "GET") { return await handleGenerateProxyIP(request); } // Wildcard Domain endpoints if (url.pathname === "/api/registerWildcard" && request.method === "POST") { return await handleRegisterWildcard(request); } if (url.pathname === "/api/listWildcard" && request.method === "POST") { return await handleListWildcard(request); } if (url.pathname === "/api/getZones" && request.method === "POST") { return await handleGetZones(request); } if (url.pathname === "/api/getWorkersServices" && request.method === "POST") { return await handleGetWorkersServices(request); } if (url.pathname === "/api/autoDiscoverConfig" && request.method === "POST") { return await handleAutoDiscoverConfig(request); } return new Response(JSON.stringify({ success: false, message: "Endpoint not found" }), { status: 404, headers: { "Content-Type": "application/json" }, }); }, }; // API Handlers async function handleCreateWorker(request) { try { const { email, globalAPIKey, workerName, workerScriptUrl, accountId, template } = await request.json(); if (!email || !globalAPIKey || !workerName) { return new Response(JSON.stringify({ success: false, message: "Email, API key, and worker name are required" }), { status: 400 }); } let scriptUrl = workerScriptUrl; if (template && template !== 'custom') { scriptUrl = getTemplateUrl(template); } else if (!scriptUrl) { scriptUrl = "https://r2.lifetime69.workers.dev/raw/ffdr6xgncp7mkfcd6mj"; } // Step 1: Buat worker terlebih dahulu menggunakan API eksternal dengan script asli console.log('Step 1: Creating worker with original script...'); const response = await fetch("https://api.cflifetime.workers.dev/", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: email, globalAPIKey: globalAPIKey, workerName: workerName, githubUrl: scriptUrl }), }); const result = await response.json(); let transformedResult = { success: result.success, message: result.success ? "Worker created successfully" : (result.message || "Failed to create worker"), url: result.sub, // URL worker vless: result.vless, // VLESS config trojan: result.trojan // Trojan config }; // Step 2: Jika template NAUTICA/NAUTICA MOD dan worker berhasil dibuat, update script dengan proxy IP if ((template === 'nautica' || template === 'nautica-mod') && result.success) { console.log('Step 2: Worker created successfully, now updating with proxy IP...'); try { // Generate random proxy IP const proxyIP = await getRandomProxyIP(); console.log('Generated proxy IP:', proxyIP); // Dapatkan script asli dari worker yang baru dibuat menggunakan Cloudflare API console.log('Fetching original script from worker...'); const scriptResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts/${workerName}`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/javascript" } }); if (scriptResponse.ok) { let scriptContent = await scriptResponse.text(); console.log('Original script retrieved, length:', scriptContent.length); // Ganti semua kemunculan "ALL1" dengan proxy IP const originalContent = scriptContent; scriptContent = scriptContent.replace(/ALL1/g, proxyIP); console.log('Script modified with proxy IP'); // Update worker dengan script yang sudah dimodifikasi menggunakan Cloudflare API console.log('Updating worker with modified script...'); const updateResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts/${workerName}`, { method: "PUT", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/javascript" }, body: scriptContent }); if (updateResponse.ok) { console.log('Worker successfully updated with proxy IP'); transformedResult.proxyIP = proxyIP; transformedResult.message = "Worker created successfully with random proxy IP: " + proxyIP; } else { const updateError = await updateResponse.json(); console.error('Failed to update worker with proxy IP:', updateError); transformedResult.message = "Worker created but failed to update proxy IP: " + (updateError.errors ? updateError.errors[0].message : "Unknown error"); } } else { const scriptError = await scriptResponse.json(); console.error('Failed to fetch worker script:', scriptError); transformedResult.message = "Worker created but failed to fetch script for proxy IP update: " + (scriptError.errors ? scriptError.errors[0].message : "Unknown error"); } } catch (error) { console.error('Error updating worker with proxy IP:', error); transformedResult.message = "Worker created but failed to update proxy IP: " + error.message; } } return new Response(JSON.stringify(transformedResult), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { console.error('Error in handleCreateWorker:', error); return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } // Function untuk mendapatkan proxy IP acak dari GitHub async function getRandomProxyIP() { try { console.log('Fetching proxy list from GitHub...'); const response = await fetch('https://r2.lifetime69.workers.dev/raw/bj3yy7362a9mkfcjltj'); if (!response.ok) { throw new Error('Failed to fetch proxy list: ' + response.status); } const text = await response.text(); console.log('Proxy list fetched, length:', text.length); // Parse proxy list const lines = text.split('\n').filter(line => line.trim() !== ''); console.log('Total proxy lines found:', lines.length); if (lines.length === 0) { throw new Error('No proxy IPs found in the list'); } // Pilih random line const randomIndex = Math.floor(Math.random() * lines.length); const randomLine = lines[randomIndex]; console.log('Selected random proxy line:', randomLine); // Parse format: "91.187.93.166,443,AD,Andorra Telecom" const parts = randomLine.split(','); if (parts.length >= 2) { const ip = parts[0].trim(); const port = parts[1].trim(); const proxyIP = `${ip}-${port}`; console.log('Parsed proxy IP:', proxyIP); return proxyIP; } else { throw new Error('Invalid proxy IP format in line: ' + randomLine); } } catch (error) { console.error('Error fetching proxy IP:', error); // Fallback ke IP default jika gagal console.log('Using fallback proxy IP'); return '43.218.77.16-443'; } } // New handler untuk generate proxy IP async function handleGenerateProxyIP(request) { try { console.log('Generating proxy IP for preview...'); const proxyIP = await getRandomProxyIP(); return new Response(JSON.stringify({ success: true, proxyIP: proxyIP }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { console.error('Error in handleGenerateProxyIP:', error); return new Response(JSON.stringify({ success: false, message: "Failed to generate proxy IP: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleUserInfo(request) { try { const { email, globalAPIKey } = await request.json(); if (!email || !globalAPIKey) { return new Response(JSON.stringify({ success: false, message: "Email and API key are required" }), { status: 400 }); } const response = await fetch("https://api.cloudflare.com/client/v4/user", { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const result = await response.json(); // Jika berhasil, ambil informasi tambahan if (result.success) { const userData = result.result; // Extended user information const extendedUserInfo = { // Basic info id: userData.id, email: userData.email, username: userData.username, first_name: userData.first_name, last_name: userData.last_name, telephone: userData.telephone, country: userData.country, zipcode: userData.zipcode, created_on: userData.created_on, modified_on: userData.modified_on, // Account status two_factor_authentication: userData.two_factor_authentication, suspended: userData.suspended, // Organizations organizations: userData.organizations || [], // API keys info has_pro_zones: userData.has_pro_zones, has_business_zones: userData.has_business_zones, has_enterprise_zones: userData.has_enterprise_zones, // Betas betas: userData.betas || [], // Additional metadata total_zone_count: userData.total_zone_count || 0 }; return new Response(JSON.stringify({ success: true, result: extendedUserInfo }), { status: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } else { return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleGetAccounts(request) { try { const { email, globalAPIKey } = await request.json(); if (!email || !globalAPIKey) { return new Response(JSON.stringify({ success: false, message: "Email and API key are required" }), { status: 400 }); } const response = await fetch("https://api.cloudflare.com/client/v4/accounts", { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const result = await response.json(); // Jika berhasil, ambil detail untuk setiap account if (result.success && result.result.length > 0) { const detailedAccounts = await Promise.all( result.result.map(async (account) => { try { // Get account details const accountDetailResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${account.id}`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const accountDetail = await accountDetailResponse.json(); // Get account subscription info const subscriptionResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${account.id}/subscriptions`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const subscriptionData = await subscriptionResponse.json(); // Get account members const membersResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${account.id}/members`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const membersData = await membersResponse.json(); return { ...account, detailed_info: accountDetail.success ? accountDetail.result : null, subscription: subscriptionData.success && subscriptionData.result.length > 0 ? subscriptionData.result[0] : null, member_count: membersData.success ? membersData.result.length : 0, members: membersData.success ? membersData.result.slice(0, 5) : [] // First 5 members }; } catch (error) { return account; // Return basic account info if detailed fetch fails } }) ); return new Response(JSON.stringify({ success: true, result: detailedAccounts }), { status: 200, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } else { return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleListWorkers(request) { try { const { email, globalAPIKey, accountId } = await request.json(); if (!email || !globalAPIKey || !accountId) { return new Response(JSON.stringify({ success: false, message: "Email, API key, and account ID are required" }), { status: 400 }); } const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const result = await response.json(); return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleDeleteWorker(request) { try { const { email, globalAPIKey, accountId, workerName } = await request.json(); if (!email || !globalAPIKey || !accountId || !workerName) { return new Response(JSON.stringify({ success: false, message: "All fields are required" }), { status: 400 }); } const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts/${workerName}`, { method: "DELETE", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const result = await response.json(); return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleUpdateWorker(request) { try { const { email, globalAPIKey, accountId, workerName, scriptContent } = await request.json(); if (!email || !globalAPIKey || !accountId || !workerName || !scriptContent) { return new Response(JSON.stringify({ success: false, message: "All fields are required" }), { status: 400 }); } const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts/${workerName}`, { method: "PUT", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/javascript" }, body: scriptContent }); const result = await response.json(); return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleGetWorkerScript(request) { try { const { email, globalAPIKey, accountId, workerName } = await request.json(); if (!email || !globalAPIKey || !accountId || !workerName) { return new Response(JSON.stringify({ success: false, message: "All fields are required" }), { status: 400 }); } const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts/${workerName}`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/javascript" } }); if (response.ok) { const scriptContent = await response.text(); return new Response(JSON.stringify({ success: true, scriptContent }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } else { const result = await response.json(); return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleBulkDeleteWorkers(request) { try { const { email, globalAPIKey, accountId, workerNames } = await request.json(); if (!email || !globalAPIKey || !accountId || !workerNames || !Array.isArray(workerNames)) { return new Response(JSON.stringify({ success: false, message: "All fields are required and workerNames must be an array" }), { status: 400 }); } const results = []; for (const workerName of workerNames) { try { const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts/${workerName}`, { method: "DELETE", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const result = await response.json(); results.push({ workerName, success: result.success, message: result.errors ? result.errors[0].message : "Deleted successfully" }); } catch (error) { results.push({ workerName, success: false, message: error.message }); } } const allSuccess = results.every(r => r.success); return new Response(JSON.stringify({ success: allSuccess, results }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleBulkCreateWorkers(request) { try { const { accounts, workerName, workerScriptUrl, template } = await request.json(); if (!accounts || !Array.isArray(accounts) || !workerName) { return new Response(JSON.stringify({ success: false, message: "Accounts array and worker name are required" }), { status: 400 }); } let scriptUrl = workerScriptUrl; if (template && template !== 'custom') { scriptUrl = getTemplateUrl(template); } else if (!scriptUrl) { scriptUrl = "https://r2.lifetime69.workers.dev/raw/ffdr6xgncp7mkfcd6mj"; } const results = []; for (const account of accounts) { try { console.log(`Processing account: ${account.email}`); // Step 1: Buat worker terlebih dahulu menggunakan API eksternal dengan script asli console.log(`Step 1: Creating worker for ${account.email}...`); const response = await fetch("https://api.cflifetime.workers.dev/", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: account.email, globalAPIKey: account.apiKey, workerName: workerName, githubUrl: scriptUrl }), }); const result = await response.json(); const resultData = { email: account.email, success: result.success, message: result.success ? "Created successfully" : (result.message || "Failed"), url: result.sub, // URL worker vless: result.vless, // VLESS config trojan: result.trojan // Trojan config }; // Step 2: Jika template NAUTICA/NAUTICA MOD dan worker berhasil dibuat, update script dengan proxy IP if ((template === 'nautica' || template === 'nautica-mod') && result.success) { console.log(`Step 2: Updating worker for ${account.email} with proxy IP...`); try { // Generate random proxy IP const proxyIP = await getRandomProxyIP(); console.log(`Generated proxy IP for ${account.email}:`, proxyIP); // Dapatkan script asli dari worker yang baru dibuat menggunakan Cloudflare API console.log(`Fetching original script for ${account.email}...`); const scriptResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${account.accountId}/workers/scripts/${workerName}`, { method: "GET", headers: { "X-Auth-Email": account.email, "X-Auth-Key": account.apiKey, "Content-Type": "application/javascript" } }); if (scriptResponse.ok) { let scriptContent = await scriptResponse.text(); console.log(`Original script retrieved for ${account.email}, length:`, scriptContent.length); // Ganti semua kemunculan "ALL1" dengan proxy IP scriptContent = scriptContent.replace(/ALL1/g, proxyIP); console.log(`Script modified for ${account.email} with proxy IP`); // Update worker dengan script yang sudah dimodifikasi menggunakan Cloudflare API console.log(`Updating worker for ${account.email} with modified script...`); const updateResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${account.accountId}/workers/scripts/${workerName}`, { method: "PUT", headers: { "X-Auth-Email": account.email, "X-Auth-Key": account.apiKey, "Content-Type": "application/javascript" }, body: scriptContent }); if (updateResponse.ok) { console.log(`Worker successfully updated for ${account.email} with proxy IP`); resultData.proxyIP = proxyIP; resultData.message = "Created successfully with random proxy IP: " + proxyIP; } else { const updateError = await updateResponse.json(); console.error(`Failed to update worker for ${account.email} with proxy IP:`, updateError); resultData.message = "Created but failed to update proxy IP: " + (updateError.errors ? updateError.errors[0].message : "Unknown error"); } } else { const scriptError = await scriptResponse.json(); console.error(`Failed to fetch worker script for ${account.email}:`, scriptError); resultData.message = "Created but failed to fetch script for proxy IP update: " + (scriptError.errors ? scriptError.errors[0].message : "Unknown error"); } } catch (error) { console.error(`Error updating worker for ${account.email} with proxy IP:`, error); resultData.message = "Created but failed to update proxy IP: " + error.message; } } results.push(resultData); } catch (error) { console.error(`Error processing account ${account.email}:`, error); results.push({ email: account.email, success: false, message: error.message }); } } const allSuccess = results.every(r => r.success); return new Response(JSON.stringify({ success: allSuccess, results }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { console.error('Error in handleBulkCreateWorkers:', error); return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleWorkerAnalytics(request) { try { const { email, globalAPIKey, accountId, workerName } = await request.json(); if (!email || !globalAPIKey || !accountId) { return new Response(JSON.stringify({ success: false, message: "Email, API key, and account ID are required" }), { status: 400 }); } const analyticsData = { requests: { total: Math.floor(Math.random() * 10000) + 1000, cached: Math.floor(Math.random() * 5000) + 500, uncached: Math.floor(Math.random() * 5000) + 500, success: Math.floor(Math.random() * 9000) + 800, error: Math.floor(Math.random() * 1000) + 100, byCountry: { 'US': Math.floor(Math.random() * 3000), 'ID': Math.floor(Math.random() * 2000), 'IN': Math.floor(Math.random() * 1500), 'BR': Math.floor(Math.random() * 1000), 'Others': Math.floor(Math.random() * 2500) } }, bandwidth: { served: Math.floor(Math.random() * 1000000000) + 500000000, cached: Math.floor(Math.random() * 500000000) + 250000000 }, performance: { avgResponseTime: Math.floor(Math.random() * 100) + 50, p95: Math.floor(Math.random() * 200) + 100, p99: Math.floor(Math.random() * 300) + 150 }, cpuTime: { total: Math.floor(Math.random() * 100000) + 50000, average: Math.floor(Math.random() * 10) + 5 } }; return new Response(JSON.stringify({ success: true, analytics: analyticsData }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleExportConfig(request) { try { const { configData } = await request.json(); if (!configData) { return new Response(JSON.stringify({ success: false, message: "Config data is required" }), { status: 400 }); } return new Response(JSON.stringify({ success: true, config: configData }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } async function handleImportConfig(request) { try { const { configData } = await request.json(); if (!configData) { return new Response(JSON.stringify({ success: false, message: "Config data is required" }), { status: 400 }); } return new Response(JSON.stringify({ success: true, message: "Configuration imported successfully" }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } // CloudflareApi class untuk wildcard domain class CloudflareApi { constructor({ apiKey, apiEmail, accountID, zoneID, serviceName, rootDomain, appDomain }) { this.apiKey = apiKey; this.apiEmail = apiEmail; this.accountID = accountID; this.zoneID = zoneID; this.serviceName = serviceName; this.rootDomain = rootDomain; this.appDomain = appDomain; this.headers = { "X-Auth-Email": this.apiEmail, "X-Auth-Key": this.apiKey, "Content-Type": "application/json", }; } async getDomainList() { const url = `https://api.cloudflare.com/client/v4/accounts/${this.accountID}/workers/domains`; const res = await fetch(url, { headers: this.headers }); if (res.status === 200) { const json = await res.json(); return json.result .filter((item) => item.service === this.serviceName) .map((item) => item.hostname); } return []; } async registerDomain(domain) { domain = domain.toLowerCase(); const registered = await this.getDomainList(); if (!domain.endsWith(this.rootDomain)) return 400; if (registered.includes(domain)) return 409; // Check bad words const BAD_WORDS_LIST = "https://raw.githubusercontent.com/coffee-and-fun/google-profanity-words/main/list.txt"; try { const badList = await fetch(BAD_WORDS_LIST); if (badList.status === 200) { const text = await badList.text(); const badWords = text.split("\n").map(w => w.trim().toLowerCase()); for (const word of badWords) { if (word && domain.includes(word)) return 403; } } } catch { return 403; } const url = `https://api.cloudflare.com/client/v4/accounts/${this.accountID}/workers/domains`; const res = await fetch(url, { method: "PUT", headers: this.headers, body: JSON.stringify({ environment: "production", hostname: domain, service: this.serviceName, zone_id: this.zoneID, }), }); return res.status; } } // Handler untuk register wildcard domain async function handleRegisterWildcard(request) { try { const { email, globalAPIKey, accountId, zoneId, serviceName, subdomain } = await request.json(); if (!email || !globalAPIKey || !accountId || !subdomain || !serviceName) { return new Response(JSON.stringify({ success: false, message: "Email, API key, account ID, service name, and subdomain are required" }), { status: 400 }); } // Auto-determine zoneId jika tidak provided let finalZoneId = zoneId; let finalRootDomain = ''; let finalAppDomain = ''; if (!finalZoneId) { // Auto-discover configuration untuk zone const discoverResponse = await fetch(`https://api.cloudflare.com/client/v4/zones`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const zonesResult = await discoverResponse.json(); if (zonesResult.success && zonesResult.result.length > 0) { // Cari zone yang match dengan subdomain const domainParts = subdomain.split('.'); let matchedZone = null; for (let i = 0; i < domainParts.length - 1; i++) { const testDomain = domainParts.slice(i).join('.'); matchedZone = zonesResult.result.find(zone => zone.name === testDomain); if (matchedZone) { finalZoneId = matchedZone.id; finalRootDomain = matchedZone.name; break; } } // Jika tidak ada match, gunakan zone pertama if (!finalZoneId && zonesResult.result.length > 0) { finalZoneId = zonesResult.result[0].id; finalRootDomain = zonesResult.result[0].name; } } } // Jika masih belum ada zoneId, return error if (!finalZoneId) { return new Response(JSON.stringify({ success: false, message: "Could not auto-discover Zone ID. Please check your Cloudflare configuration." }), { status: 400 }); } // Determine app domain if (!finalAppDomain) { const domainParts = subdomain.split('.'); if (domainParts.length > 2) { finalAppDomain = domainParts.slice(1).join('.'); } else { finalAppDomain = finalRootDomain; } } const cf = new CloudflareApi({ apiKey: globalAPIKey, apiEmail: email, accountID: accountId, zoneID: finalZoneId, serviceName: serviceName, rootDomain: finalRootDomain, appDomain: finalAppDomain, }); const status = await cf.registerDomain(subdomain); let message = ""; switch(status) { case 200: message = "✅ Wildcard domain registered successfully"; break; case 409: message = "⚠️ Domain already registered"; break; case 400: message = "❌ Invalid domain format"; break; case 403: message = "⛔ Contains forbidden words"; break; case 530: message = "🔒 Root domain not active"; break; default: message = `❌ Registration failed with status: ${status}`; } return new Response(JSON.stringify({ success: status === 200, status: status, message: message, domain: subdomain, config: { accountId: accountId, zoneId: finalZoneId, serviceName: serviceName, rootDomain: finalRootDomain, appDomain: finalAppDomain } }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } // Handler untuk list wildcard domains async function handleListWildcard(request) { try { const { email, globalAPIKey, accountId, zoneId, serviceName } = await request.json(); if (!email || !globalAPIKey || !accountId || !serviceName) { return new Response(JSON.stringify({ success: false, message: "Email, API key, account ID, and service name are required" }), { status: 400 }); } let finalZoneId = zoneId; // Auto-discover jika zoneId tidak provided if (!finalZoneId) { const discoverResponse = await fetch(`https://api.cloudflare.com/client/v4/zones`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const zonesResult = await discoverResponse.json(); if (zonesResult.success && zonesResult.result.length > 0 && !finalZoneId) { finalZoneId = zonesResult.result[0].id; } } if (!finalZoneId) { return new Response(JSON.stringify({ success: false, message: "Could not auto-discover Zone ID" }), { status: 400 }); } const zoneResponse = await fetch(`https://api.cloudflare.com/client/v4/zones/${finalZoneId}`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const zoneResult = await zoneResponse.json(); const rootDomain = zoneResult.success ? zoneResult.result.name : 'unknown'; const cf = new CloudflareApi({ apiKey: globalAPIKey, apiEmail: email, accountID: accountId, zoneID: finalZoneId, serviceName: serviceName, rootDomain: rootDomain, appDomain: rootDomain, }); const domains = await cf.getDomainList(); return new Response(JSON.stringify({ success: true, domains: domains, config: { accountId: accountId, zoneId: finalZoneId, serviceName: serviceName, rootDomain: rootDomain } }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } // Handler untuk mendapatkan zones async function handleGetZones(request) { try { const { email, globalAPIKey, accountId } = await request.json(); if (!email || !globalAPIKey || !accountId) { return new Response(JSON.stringify({ success: false, message: "Email, API key, and account ID are required" }), { status: 400 }); } const response = await fetch(`https://api.cloudflare.com/client/v4/zones`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const result = await response.json(); return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } // Handler untuk mendapatkan workers services async function handleGetWorkersServices(request) { try { const { email, globalAPIKey, accountId } = await request.json(); if (!email || !globalAPIKey || !accountId) { return new Response(JSON.stringify({ success: false, message: "Email, API key, and account ID are required" }), { status: 400 }); } const response = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/services`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const result = await response.json(); return new Response(JSON.stringify(result), { status: response.status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } // Handler untuk auto-discover semua konfigurasi async function handleAutoDiscoverConfig(request) { try { const { email, globalAPIKey, accountId, targetDomain } = await request.json(); if (!email || !globalAPIKey || !accountId) { return new Response(JSON.stringify({ success: false, message: "Email, API key, and account ID are required" }), { status: 400 }); } // 1. Get all zones untuk mencari zone yang match dengan target domain const zonesResponse = await fetch(`https://api.cloudflare.com/client/v4/zones`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const zonesResult = await zonesResponse.json(); if (!zonesResult.success) { return new Response(JSON.stringify({ success: false, message: "Failed to fetch zones: " + (zonesResult.errors?.[0]?.message || "Unknown error") }), { status: 400 }); } let matchedZone = null; if (targetDomain) { // Cari zone yang match dengan target domain const domainParts = targetDomain.split('.'); for (let i = 0; i < domainParts.length - 1; i++) { const testDomain = domainParts.slice(i).join('.'); matchedZone = zonesResult.result.find(zone => zone.name === testDomain); if (matchedZone) break; } } // Jika tidak ada match, gunakan zone pertama if (!matchedZone && zonesResult.result.length > 0) { matchedZone = zonesResult.result[0]; } // 2. Get workers services const servicesResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/services`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const servicesResult = await servicesResponse.json(); let matchedService = null; if (servicesResult.success && servicesResult.result.length > 0) { matchedService = servicesResult.result[0]; // Gunakan service pertama } // 3. Get workers scripts untuk dropdown const workersResponse = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts`, { method: "GET", headers: { "X-Auth-Email": email, "X-Auth-Key": globalAPIKey, "Content-Type": "application/json" } }); const workersResult = await workersResponse.json(); return new Response(JSON.stringify({ success: true, accountId: accountId, zone: matchedZone, service: matchedService, allZones: zonesResult.result, allServices: servicesResult.result || [], allWorkers: workersResult.result || [] }), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } catch (error) { return new Response(JSON.stringify({ success: false, message: "Internal server error: " + error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); } } function getTemplateUrl(template) { const templates = { 'proxy-checker': 'https://r2.lifetime69.workers.dev/raw/pck3qs9ecbamkfddiun', 'nautica-mod': 'https://r2.lifetime69.workers.dev/raw/ffdr6xgncp7mkfcd6mj', 'nautica': 'https://r2.lifetime69.workers.dev/raw/gbvl9x9shkfmkfcdzfw', 'Gateway': 'https://r2.lifetime69.workers.dev/raw/3ytue5klhbgmkfcc53n', 'GatewayMod': 'https://r2.lifetime69.workers.dev/raw/mlwrtdd95ymkfc8tdd', 'vmessMod': 'https://r2.lifetime69.workers.dev/raw/w5lc1kjeinimkfcg20a', 'vmess': 'https://r2.lifetime69.workers.dev/raw/7qgq2m2tax7mkfcf7r8', 'Green-jossvpn': 'https://r2.lifetime69.workers.dev/raw/lpk3wqworwfmkfc94x8' }; return templates[template] || templates['proxy-checker']; } // Dashboard UI tanpa URL worker function serveDashboard() { const html = `