176 lines
6.2 KiB
JavaScript
176 lines
6.2 KiB
JavaScript
const fs = require('fs').promises;
|
|
const dns = require('dns').promises;
|
|
const state = require('../../../infrastructure/state');
|
|
const { logError, logWarn, logInfo } = require('../../../infrastructure/logger');
|
|
const { saveSelectorCache } = require('../cache');
|
|
const { broadcast } = require('../websocket');
|
|
|
|
const localDnsFile = process.env.LOCAL_DNS_FILE || 'cache/local_dns.json';
|
|
|
|
async function handleLocalDnsRoutes(req, res) {
|
|
const urlPath = req.urlPath || new URL(req.url, `https://${req.headers.host}`).pathname;
|
|
const method = req.method;
|
|
|
|
if (method === 'GET' && urlPath === '/api/local-dns') {
|
|
try {
|
|
let records = state.localDnsRecords || [];
|
|
let conflicts = [];
|
|
const domains = new Set([...state.domainsWithBoth, ...state.versionPreferences.keys()]);
|
|
for (const domain of domains) {
|
|
let publicIP = state.publicIpForDomain[domain];
|
|
if (!publicIP && state.versionPreferences.has(domain)) {
|
|
try {
|
|
const ips = await dns.resolve4(domain);
|
|
publicIP = ips[0] || 'N/A';
|
|
state.publicIpForDomain[domain] = publicIP;
|
|
} catch (err) {
|
|
logWarn('Admin', `Failed to resolve public IP for ${domain}: ${err.message}`);
|
|
publicIP = 'N/A';
|
|
}
|
|
}
|
|
conflicts.push({
|
|
domain,
|
|
version: state.versionPreferences.get(domain) || 'p2p',
|
|
publicIP: publicIP || 'N/A'
|
|
});
|
|
}
|
|
records = records.map((rec, index) => ({ ...rec, index }));
|
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify({ records, conflicts }));
|
|
} catch (err) {
|
|
logError('Admin', `Failed to fetch local DNS and conflicts: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end(JSON.stringify({ error: 'Failed to fetch local DNS and conflicts' }));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (method === 'GET' && urlPath === '/api/selector-cache') {
|
|
try {
|
|
const preferences = Object.fromEntries(state.versionPreferences);
|
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify(preferences));
|
|
} catch (err) {
|
|
logError('Admin', `Failed to fetch selector cache: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end(JSON.stringify({ error: 'Failed to fetch selector cache' }));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (method === 'POST' && urlPath === '/api/add-local-dns') {
|
|
let body = '';
|
|
req.on('data', chunk => { body += chunk; });
|
|
req.on('end', async () => {
|
|
try {
|
|
const record = JSON.parse(body);
|
|
if (!record.name || !record.type || !record.ttl || isNaN(record.ttl)) {
|
|
throw new Error('Missing or invalid required fields: name, type, ttl');
|
|
}
|
|
record.class = record.class || 'IN';
|
|
let records = state.localDnsRecords || [];
|
|
records.push(record);
|
|
await fs.writeFile(localDnsFile, JSON.stringify(records, null, 2));
|
|
state.localDnsRecords = records;
|
|
broadcast({ type: 'update-local-dns' });
|
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
res.end('OK');
|
|
} catch (err) {
|
|
logError('Admin', `Failed to add local DNS record: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end(err.message);
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (method === 'POST' && urlPath === '/api/update-local-dns') {
|
|
let body = '';
|
|
req.on('data', chunk => { body += chunk; });
|
|
req.on('end', async () => {
|
|
try {
|
|
const { index, record } = JSON.parse(body);
|
|
if (!record.name || !record.type || !record.ttl || isNaN(record.ttl)) {
|
|
throw new Error('Missing or invalid required fields: name, type, ttl');
|
|
}
|
|
let records = state.localDnsRecords || [];
|
|
if (index >= 0 && index < records.length) {
|
|
record.class = record.class || 'IN';
|
|
records[index] = record;
|
|
await fs.writeFile(localDnsFile, JSON.stringify(records, null, 2));
|
|
state.localDnsRecords = records;
|
|
broadcast({ type: 'update-local-dns' });
|
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
res.end('OK');
|
|
} else {
|
|
res.writeHead(400);
|
|
res.end('Invalid index');
|
|
}
|
|
} catch (err) {
|
|
logError('Admin', `Failed to update local DNS record: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end(err.message);
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (method === 'POST' && urlPath === '/api/delete-local-dns') {
|
|
let body = '';
|
|
req.on('data', chunk => { body += chunk; });
|
|
req.on('end', async () => {
|
|
try {
|
|
const { index } = JSON.parse(body);
|
|
let records = state.localDnsRecords || [];
|
|
if (index >= 0 && index < records.length) {
|
|
records.splice(index, 1);
|
|
await fs.writeFile(localDnsFile, JSON.stringify(records, null, 2));
|
|
state.localDnsRecords = records;
|
|
broadcast({ type: 'update-local-dns' });
|
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
res.end('OK');
|
|
} else {
|
|
res.writeHead(400);
|
|
res.end('Invalid index');
|
|
}
|
|
} catch (err) {
|
|
logError('Admin', `Failed to delete local DNS record: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end(err.message);
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (method === 'POST' && urlPath === '/api/update-version-preference') {
|
|
let body = '';
|
|
req.on('data', chunk => { body += chunk; });
|
|
req.on('end', async () => {
|
|
try {
|
|
const { domain, version } = JSON.parse(body);
|
|
if (version !== 'p2p' && version !== 'public') {
|
|
res.writeHead(400);
|
|
res.end('Invalid version, must be "p2p" or "public"');
|
|
return;
|
|
}
|
|
state.versionPreferences.set(domain, version);
|
|
await saveSelectorCache();
|
|
broadcast({ type: 'update-local-dns' });
|
|
logInfo('Admin', `Updated version preference for ${domain} to ${version}`);
|
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
res.end('OK');
|
|
} catch (err) {
|
|
logError('Admin', `Failed to update version preference: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end(err.message);
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
module.exports = { handleLocalDnsRoutes };
|
|
|