|  | const PORT = 3000 | 
        
          |  | const http = require('http'); | 
        
          |  | const request = require('request'); | 
        
          |  | const path = require('path'); | 
        
          |  | const fs = require('fs'); | 
        
          |  | const src = fs.readFileSync(path.basename(__filename)); | 
        
          |  | const html = src.toString().split('/'+'*TEMPLATE')[1].split('TEMPLATE*'+'/')[0]; | 
        
          |  | const server = http.createServer((req, res) => { | 
        
          |  | // CORS fix | 
        
          |  | if (req.method === 'OPTIONS') { | 
        
          |  | res.writeHead(200, { | 
        
          |  | 'Access-Control-Allow-Origin': '*', | 
        
          |  | 'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE', | 
        
          |  | 'Access-Control-Allow-Headers': 'Authorization, Content-Type', | 
        
          |  | 'Access-Control-Max-Age': '86400' | 
        
          |  | }); | 
        
          |  | res.end(); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | // Serve template | 
        
          |  | if (req.url === '/') { | 
        
          |  | res.writeHead(200, { 'Content-Type': 'text/html' }); | 
        
          |  | res.end(html); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | // Disallow anything not in api | 
        
          |  | if (!req.url.startsWith('/api/')) { | 
        
          |  | res.writeHead(404, { 'Content-Type': 'application/json' }); | 
        
          |  | res.end(JSON.stringify({ success: false, errors: [{ code: 404, message: 'Not found' }] })); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | console.log(req.method, req.url); | 
        
          |  | const apiUrl = `https://api.cloudflare.com/client/v4${req.url.replace('/api', '')}`; | 
        
          |  | const headers = { 'Authorization': req.headers['authorization'], 'Content-Type': 'application/json' }; | 
        
          |  |  | 
        
          |  | // Proxy to Cloudflare API | 
        
          |  | let body = ''; | 
        
          |  | req.on('data', chunk => body += chunk); | 
        
          |  | req.on('end', () => { | 
        
          |  | request({ | 
        
          |  | method: req.method, | 
        
          |  | url: apiUrl, | 
        
          |  | headers, | 
        
          |  | body: body || undefined, | 
        
          |  | json: true | 
        
          |  | }, (error, response, body) => { | 
        
          |  | console.log(error, body); | 
        
          |  | res.writeHead(response.statusCode, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); | 
        
          |  | res.end(JSON.stringify(body)); | 
        
          |  | }); | 
        
          |  | }); | 
        
          |  | }); | 
        
          |  |  | 
        
          |  | server.listen(PORT, () => console.log('Proxy running on http://localhost:'+PORT)); | 
        
          |  |  | 
        
          |  | /*TEMPLATE | 
        
          |  | <!DOCTYPE html> | 
        
          |  | <html lang="en"> | 
        
          |  | <head> | 
        
          |  | <meta charset="UTF-8"> | 
        
          |  | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | 
        
          |  | <title>Cloudflare DNS Manager</title> | 
        
          |  | <script src="https://cdn.tailwindcss.com"></script> | 
        
          |  | </head> | 
        
          |  | <body class="bg-gray-100 font-sans"> | 
        
          |  | <div class="container mx-auto p-4"> | 
        
          |  | <h1 class="text-2xl font-bold mb-4">Cloudflare DNS Manager</h1> | 
        
          |  | <div class="mb-4 flex space-x-2"> | 
        
          |  | <input id="apiToken" type="password" placeholder="API Token" class="border p-2 rounded w-1/3"> | 
        
          |  | <button onclick="fetchZones()" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">Load Domains</button> | 
        
          |  | <select id="zoneSelect" onchange="fetchRecords()" class="border p-2 rounded w-1/2" disabled> | 
        
          |  | <option value="">Select a domain</option> | 
        
          |  | </select> | 
        
          |  | <button onclick="clearCache()" class="bg-yellow-500 text-white px-4 py-2 rounded hover:bg-yellow-600">Clear Cache</button> | 
        
          |  | </div> | 
        
          |  | <div id="errorBox" class="hidden bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4"></div> | 
        
          |  | <table id="dnsTable" class="w-full border-collapse hidden"> | 
        
          |  | <thead> | 
        
          |  | <tr class="bg-gray-200"> | 
        
          |  | <th class="border p-2">Type</th> | 
        
          |  | <th class="border p-2">Name</th> | 
        
          |  | <th class="border p-2">Content</th> | 
        
          |  | <th class="border p-2" style="width: 100px;">Priority</th> | 
        
          |  | <th class="border p-2" style="width: 100px;">TTL</th> | 
        
          |  | <th class="border p-2" style="width: 60px;">Proxy</th> | 
        
          |  | <th class="border p-2">Actions</th> | 
        
          |  | </tr> | 
        
          |  | </thead> | 
        
          |  | <tbody id="dnsTableBody"></tbody> | 
        
          |  | </table> | 
        
          |  | </div> | 
        
          |  |  | 
        
          |  | <script> | 
        
          |  | const recordTypes = ['A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SRV']; | 
        
          |  | const proxyableTypes = ['A', 'AAAA', 'CNAME']; | 
        
          |  | const proxyUrl = '/api/'; | 
        
          |  | let currentDomain = ''; | 
        
          |  |  | 
        
          |  | function showError(error) { | 
        
          |  | const errorBox = document.getElementById('errorBox'); | 
        
          |  | errorBox.innerHTML = `Error ${error.code}: ${error.message}`; | 
        
          |  | errorBox.classList.remove('hidden'); | 
        
          |  | setTimeout(() => errorBox.classList.add('hidden'), 5000); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | async function fetchZones() { | 
        
          |  | const apiToken = document.getElementById('apiToken').value; | 
        
          |  | if (!apiToken) { | 
        
          |  | showError({ code: 0, message: 'Please enter API Token' }); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | try { | 
        
          |  | const response = await fetch(`${proxyUrl}zones`, { | 
        
          |  | headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' } | 
        
          |  | }); | 
        
          |  | const data = await response.json(); | 
        
          |  | if (!data.success) { | 
        
          |  | showError(data.errors[0]); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  | populateZoneSelect(data.result); | 
        
          |  | } catch (error) { | 
        
          |  | showError({ code: 0, message: 'Network error: ' + error.message }); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | function populateZoneSelect(zones) { | 
        
          |  | const zoneSelect = document.getElementById('zoneSelect'); | 
        
          |  | zoneSelect.innerHTML = '<option value="">Select a domain</option>'; | 
        
          |  | zones.forEach(zone => { | 
        
          |  | const option = document.createElement('option'); | 
        
          |  | option.value = zone.id; | 
        
          |  | option.textContent = zone.name; | 
        
          |  | option.dataset.domain = zone.name; | 
        
          |  | zoneSelect.appendChild(option); | 
        
          |  | }); | 
        
          |  | zoneSelect.disabled = false; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | async function fetchRecords() { | 
        
          |  | const apiToken = document.getElementById('apiToken').value; | 
        
          |  | const zoneSelect = document.getElementById('zoneSelect'); | 
        
          |  | const zoneId = zoneSelect.value; | 
        
          |  | currentDomain = zoneSelect.options[zoneSelect.selectedIndex]?.dataset.domain || ''; | 
        
          |  | if (!zoneId) { | 
        
          |  | document.getElementById('dnsTable').classList.add('hidden'); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | try { | 
        
          |  | const response = await fetch(`${proxyUrl}zones/${zoneId}/dns_records`, { | 
        
          |  | headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' } | 
        
          |  | }); | 
        
          |  | const data = await response.json(); | 
        
          |  | if (!data.success) { | 
        
          |  | showError(data.errors[0]); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  | renderTable(data.result); | 
        
          |  | } catch (error) { | 
        
          |  | showError({ code: 0, message: 'Network error: ' + error.message }); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | async function clearCache() { | 
        
          |  | const apiToken = document.getElementById('apiToken').value; | 
        
          |  | const zoneId = document.getElementById('zoneSelect').value; | 
        
          |  | if (!zoneId) { | 
        
          |  | showError({ code: 0, message: 'Please select a domain' }); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | try { | 
        
          |  | const response = await fetch(`${proxyUrl}zones/${zoneId}/purge_cache`, { | 
        
          |  | method: 'POST', | 
        
          |  | headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' }, | 
        
          |  | body: JSON.stringify({ purge_everything: true }) | 
        
          |  | }); | 
        
          |  | const data = await response.json(); | 
        
          |  | if (!data.success) { | 
        
          |  | showError(data.errors[0]); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  | showError({ code: 200, message: 'Cache cleared successfully' }); | 
        
          |  | } catch (error) { | 
        
          |  | showError({ code: 0, message: 'Network error: ' + error.message }); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | function renderTable(records) { | 
        
          |  | const tbody = document.getElementById('dnsTableBody'); | 
        
          |  | tbody.innerHTML = ''; | 
        
          |  | document.getElementById('dnsTable').classList.remove('hidden'); | 
        
          |  |  | 
        
          |  | records.forEach(record => { | 
        
          |  | const row = createRow(record); | 
        
          |  | tbody.appendChild(row); | 
        
          |  | }); | 
        
          |  |  | 
        
          |  | const newRow = createRow({ id: '', type: 'A', name: '', content: '', priority: '', ttl: 1, proxied: false }); | 
        
          |  | newRow.dataset.newRecord = 'true'; | 
        
          |  | tbody.appendChild(newRow); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | function createRow(record) { | 
        
          |  | const name = record.name === currentDomain ? '@' : record.name.replace(`.${currentDomain}`, ''); | 
        
          |  | const priority = record.priority != null ? record.priority : ''; | 
        
          |  | const row = document.createElement('tr'); | 
        
          |  | row.innerHTML = ` | 
        
          |  | <td class="border p-2"> | 
        
          |  | <select class="border p-1 w-full" onchange="toggleProxyAndPriority(this)"> | 
        
          |  | ${recordTypes.map(type => `<option value="${type}" ${record.type === type ? 'selected' : ''}>${type}</option>`).join('')} | 
        
          |  | </select> | 
        
          |  | </td> | 
        
          |  | <td class="border p-2"><input type="text" value="${name}" class="border p-1 w-full"></td> | 
        
          |  | <td class="border p-2"><input type="text" value='${record.content || ''}' class="border p-1 w-full"></td> | 
        
          |  | <td class="border p-2"><input type="number" value="${priority}" min="0" max="65535" class="border p-1 w-full priority-input" ${record.type === 'MX' ? '' : 'disabled'}></td> | 
        
          |  | <td class="border p-2"><input type="number" value="${record.ttl || 3600}" min="1" class="border p-1 w-full"></td> | 
        
          |  | <td class="border p-2 text-center"> | 
        
          |  | <input type="checkbox" ${record.proxied ? 'checked' : ''} ${proxyableTypes.includes(record.type) ? '' : 'disabled'} class="proxy-checkbox"> | 
        
          |  | </td> | 
        
          |  | <td class="border p-2"> | 
        
          |  | <button onclick="saveRecord(this)" class="bg-green-500 text-white px-2 py-1 rounded hover:bg-green-600">Save</button> | 
        
          |  | ${record.id ? `<button onclick="deleteRecord(this, '${record.id}')" class="bg-red-500 text-white px-2 py-1 rounded hover:bg-red-600 ml-2">Delete</button>` : ''} | 
        
          |  | </td> | 
        
          |  | `; | 
        
          |  | row.dataset.id = record.id; | 
        
          |  | return row; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | function toggleProxyAndPriority(select) { | 
        
          |  | const row = select.closest('tr'); | 
        
          |  | const proxyCheckbox = row.querySelector('.proxy-checkbox'); | 
        
          |  | const priorityInput = row.querySelector('.priority-input'); | 
        
          |  | proxyCheckbox.disabled = !proxyableTypes.includes(select.value); | 
        
          |  | priorityInput.disabled = select.value !== 'MX'; | 
        
          |  | if (proxyCheckbox.disabled) proxyCheckbox.checked = false; | 
        
          |  | if (priorityInput.disabled) priorityInput.value = ''; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | async function saveRecord(button) { | 
        
          |  | const row = button.closest('tr'); | 
        
          |  | const apiToken = document.getElementById('apiToken').value; | 
        
          |  | const zoneId = document.getElementById('zoneSelect').value; | 
        
          |  | const isNew = row.dataset.newRecord === 'true'; | 
        
          |  | const recordId = row.dataset.id; | 
        
          |  | const type = row.querySelector('select').value; | 
        
          |  | let name = row.querySelector('input[type="text"]').value; | 
        
          |  | const content = row.querySelectorAll('input[type="text"]')[1].value; | 
        
          |  | const priority = parseInt(row.querySelector('.priority-input').value) || undefined; | 
        
          |  | const ttl = parseInt(row.querySelectorAll('input[type="number"]')[1].value); | 
        
          |  | const proxied = row.querySelector('.proxy-checkbox').checked; | 
        
          |  |  | 
        
          |  | // Append domain to name, convert '@' to domain | 
        
          |  | name = name === '@' ? currentDomain : name ? `${name}.${currentDomain}` : currentDomain; | 
        
          |  |  | 
        
          |  | try { | 
        
          |  | const url = `${proxyUrl}zones/${zoneId}/dns_records${isNew ? '' : `/${recordId}`}`; | 
        
          |  | const method = isNew ? 'POST' : 'PATCH'; | 
        
          |  | const body = JSON.stringify({ type, name, content, ttl, proxied, ...(type === 'MX' && priority ? { priority } : {}) }); | 
        
          |  |  | 
        
          |  | const response = await fetch(url, { | 
        
          |  | method, | 
        
          |  | headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' }, | 
        
          |  | body | 
        
          |  | }); | 
        
          |  | const data = await response.json(); | 
        
          |  | if (!data.success) { | 
        
          |  | showError(data.errors[0]); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  | fetchRecords(); | 
        
          |  | } catch (error) { | 
        
          |  | showError({ code: 0, message: 'Network error: ' + error.message }); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | async function deleteRecord(button, recordId) { | 
        
          |  | const apiToken = document.getElementById('apiToken').value; | 
        
          |  | const zoneId = document.getElementById('zoneSelect').value; | 
        
          |  |  | 
        
          |  | try { | 
        
          |  | const response = await fetch(`${proxyUrl}zones/${zoneId}/dns_records/${recordId}`, { | 
        
          |  | method: 'DELETE', | 
        
          |  | headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' } | 
        
          |  | }); | 
        
          |  | const data = await response.json(); | 
        
          |  | if (!data.success) { | 
        
          |  | showError(data.errors[0]); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  | fetchRecords(); | 
        
          |  | } catch (error) { | 
        
          |  | showError({ code: 0, message: 'Network error: ' + error.message }); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | </script> | 
        
          |  | </body> | 
        
          |  | </html> | 
        
          |  | TEMPLATE*/ |