602 lines
22 KiB
JavaScript
602 lines
22 KiB
JavaScript
const https = require('https');
|
|
const http = require('http');
|
|
const tls = require('tls');
|
|
const WebSocket = require('ws');
|
|
const { logDebug, logError, logWarn, logInfo } = require('../infrastructure/logger');
|
|
const { getHashForDomain } = require('../core/core');
|
|
const { createInterfaceForDomain } = require('./virtual_interfaces');
|
|
const { restartHolesailClient } = require('./holesail');
|
|
const state = require('../infrastructure/state');
|
|
const ca = require('../security/certificate_authority');
|
|
// Lazy load admin module to avoid circular dependency
|
|
// const { handleAdminRequest, adminWss } = require('../admin');
|
|
const { handlePluginRequest, serveStaticFiles, hasPlugin } = require('../plugins/plugin-handler');
|
|
|
|
const certCache = new Map();
|
|
const MAX_CERT_CACHE_SIZE = parseInt(process.env.MAX_CERT_CACHE_SIZE || '1000', 10); // Default 1000 entries
|
|
|
|
// Store internal domains in module-level variable so it can be updated dynamically
|
|
let internalDomainsList = ['p2ns.admin']; // Default to p2ns.admin
|
|
|
|
// Helper function to set certificate in cache with size limit enforcement
|
|
function setCertCache(domain, cert) {
|
|
// If cache is at limit, remove oldest entries (simple FIFO - remove first key)
|
|
if (certCache.size >= MAX_CERT_CACHE_SIZE) {
|
|
const firstKey = certCache.keys().next().value;
|
|
if (firstKey) {
|
|
certCache.delete(firstKey);
|
|
logDebug('Proxy', `Removed oldest certificate from cache (${firstKey}) to maintain size limit`);
|
|
}
|
|
}
|
|
certCache.set(domain, cert);
|
|
}
|
|
|
|
/**
|
|
* Update proxy server certificates for current internal domains
|
|
* This should be called when plugins are enabled/disabled to update certificates
|
|
*/
|
|
async function updateProxyServerCertificates() {
|
|
if (process.env.DISABLE_PROXY_SERVER === 'true') {
|
|
return;
|
|
}
|
|
|
|
// Get internal domains from plugin system
|
|
let internalDomains;
|
|
try {
|
|
const { getInternalDomains } = require('../plugins/plugin-handler');
|
|
internalDomains = await getInternalDomains();
|
|
} catch (err) {
|
|
// Fallback if plugin system not initialized yet
|
|
logWarn('Proxy', 'Plugin system not initialized, using default internal domains');
|
|
internalDomains = ['p2ns.admin'];
|
|
}
|
|
|
|
// Update module-level variable
|
|
internalDomainsList = internalDomains;
|
|
|
|
// Create comprehensive SAN list for localhost certificate
|
|
const localhostSANs = [
|
|
{ type: 2, value: 'localhost' },
|
|
{ type: 2, value: '127.0.0.1' },
|
|
{ type: 7, value: '127.0.0.1' },
|
|
{ type: 7, value: '::1' },
|
|
...internalDomains.map(domain => ({ type: 2, value: domain }))
|
|
];
|
|
|
|
// Update localhost certificate with all internal domains in SAN
|
|
let cert = ca.getOrCreateDomainCert('localhost', localhostSANs);
|
|
setCertCache('localhost', cert);
|
|
setCertCache('127.0.0.1', cert);
|
|
|
|
// Create/update individual certificates for each internal domain
|
|
for (const domain of internalDomains) {
|
|
const domainSANs = [
|
|
{ type: 2, value: domain },
|
|
{ type: 2, value: 'localhost' },
|
|
{ type: 2, value: '127.0.0.1' },
|
|
{ type: 7, value: '127.0.0.1' },
|
|
{ type: 7, value: '::1' }
|
|
];
|
|
cert = ca.getOrCreateDomainCert(domain, domainSANs);
|
|
setCertCache(domain, cert);
|
|
}
|
|
|
|
logInfo('Proxy', `Updated proxy server certificates for internal domains: ${internalDomains.join(', ')}`);
|
|
}
|
|
|
|
async function setupProxyServer() {
|
|
if (process.env.DISABLE_PROXY_SERVER === 'true') {
|
|
logInfo('Internal Proxy', 'Proxy server disabled via DISABLE_PROXY_SERVER=true');
|
|
return;
|
|
}
|
|
|
|
// Get internal domains from plugin system
|
|
let internalDomains;
|
|
try {
|
|
const { getInternalDomains } = require('../plugins/plugin-handler');
|
|
internalDomains = await getInternalDomains();
|
|
} catch (err) {
|
|
// Fallback if plugin system not initialized yet
|
|
logWarn('Proxy', 'Plugin system not initialized, using default internal domains');
|
|
internalDomains = ['p2ns.admin'];
|
|
}
|
|
|
|
// Store in module-level variable
|
|
internalDomainsList = internalDomains;
|
|
|
|
// Create comprehensive SAN list for localhost certificate
|
|
const localhostSANs = [
|
|
{ type: 2, value: 'localhost' },
|
|
{ type: 2, value: '127.0.0.1' },
|
|
{ type: 7, value: '127.0.0.1' },
|
|
{ type: 7, value: '::1' },
|
|
...internalDomains.map(domain => ({ type: 2, value: domain }))
|
|
];
|
|
|
|
// Create localhost certificate with all internal domains in SAN
|
|
let cert = ca.getOrCreateDomainCert('localhost', localhostSANs);
|
|
setCertCache('localhost', cert);
|
|
setCertCache('127.0.0.1', cert);
|
|
|
|
// Create individual certificates for each internal domain
|
|
for (const domain of internalDomains) {
|
|
const domainSANs = [
|
|
{ type: 2, value: domain },
|
|
{ type: 2, value: 'localhost' },
|
|
{ type: 2, value: '127.0.0.1' },
|
|
{ type: 7, value: '127.0.0.1' },
|
|
{ type: 7, value: '::1' }
|
|
];
|
|
cert = ca.getOrCreateDomainCert(domain, domainSANs);
|
|
setCertCache(domain, cert);
|
|
}
|
|
|
|
const defaultDomain = 'localhost';
|
|
|
|
// Create HTTP server for redirecting to HTTPS
|
|
const httpServer = http.createServer((req, res) => {
|
|
try {
|
|
const host = req.headers.host;
|
|
let domain = host ? host.split(':')[0].toLowerCase() : defaultDomain;
|
|
if (domain === '127.0.0.1') {
|
|
domain = 'localhost';
|
|
}
|
|
logInfo('HTTP Proxy', `HTTP request for domain: ${domain}, path: ${req.url}`);
|
|
|
|
// Only redirect for internal domains or localhost
|
|
if (internalDomainsList.includes(domain) || domain === 'localhost') {
|
|
const redirectUrl = `https://${host}${req.url}`;
|
|
res.writeHead(301, {
|
|
Location: redirectUrl,
|
|
'X-Content-Type-Options': 'nosniff',
|
|
'X-Frame-Options': 'SAMEORIGIN',
|
|
'Referrer-Policy': 'strict-origin-when-cross-origin'
|
|
});
|
|
res.end(`Redirecting to ${redirectUrl}`);
|
|
logDebug('HTTP Proxy', `Redirected HTTP request for ${domain} to ${redirectUrl}`);
|
|
} else {
|
|
res.writeHead(403);
|
|
res.end('HTTP access not allowed for non-internal domains');
|
|
logWarn('HTTP Proxy', `Blocked HTTP request for non-internal domain: ${domain}`);
|
|
}
|
|
} catch (err) {
|
|
logError('HTTP Proxy', `Error handling HTTP request: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end('Internal Server Error');
|
|
}
|
|
});
|
|
|
|
httpServer.on('error', (err) => {
|
|
logError('HTTP Proxy', `HTTP server error: ${err.message}`);
|
|
});
|
|
|
|
httpServer.on('clientError', (err, socket) => {
|
|
// Filter out common benign errors like "socket hang up"
|
|
if (err.message && !err.message.toLowerCase().includes('socket hang up')) {
|
|
logError('HTTP Proxy', `Client error: ${err.message}`);
|
|
}
|
|
if (socket.writable) {
|
|
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
|
}
|
|
});
|
|
|
|
// Start HTTP server on port 80
|
|
httpServer.listen(process.env.HTTP_PORT || 80, '127.0.0.1', () => {
|
|
logInfo('HTTP Proxy', `HTTP server running on port ${process.env.HTTP_PORT || 80} at 127.0.0.1 for redirects to HTTPS`);
|
|
});
|
|
|
|
const httpsServer = https.createServer({
|
|
SNICallback: async (servername, cb) => {
|
|
logDebug('Proxy', `SNI request for ${servername || 'undefined'}`);
|
|
const normalizedServername = servername?.toLowerCase();
|
|
|
|
// Handle localhost or 127.0.0.1
|
|
if (!servername || normalizedServername === 'localhost' || normalizedServername === '127.0.0.1') {
|
|
const cert = certCache.get('localhost');
|
|
logDebug('Proxy', 'Using localhost certificate');
|
|
try {
|
|
const secureContext = tls.createSecureContext({
|
|
key: cert.key,
|
|
cert: cert.cert
|
|
});
|
|
cb(null, secureContext);
|
|
} catch (err) {
|
|
logError('Proxy', `Error creating secure context for localhost: ${err.message}`);
|
|
cb(err);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Check for internal domains
|
|
if (internalDomainsList.includes(normalizedServername)) {
|
|
const cert = certCache.get(normalizedServername) || certCache.get('localhost');
|
|
logDebug('Proxy', `Using internal domain certificate for ${normalizedServername}`);
|
|
try {
|
|
const secureContext = tls.createSecureContext({
|
|
key: cert.key,
|
|
cert: cert.cert
|
|
});
|
|
cb(null, secureContext);
|
|
} catch (err) {
|
|
logError('Proxy', `Error creating secure context for ${normalizedServername}: ${err.message}`);
|
|
cb(err);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Check if DNS service is initialized
|
|
if (!state.dnsPass) {
|
|
logWarn('Proxy', `DNS service not initialized, rejecting SNI request for ${normalizedServername}`);
|
|
cb(new Error(`DNS service not initialized for ${normalizedServername}`));
|
|
return;
|
|
}
|
|
|
|
// Check if it's a P2P domain
|
|
try {
|
|
const hash = await getHashForDomain(normalizedServername);
|
|
if (hash) {
|
|
let cert = certCache.get(normalizedServername);
|
|
if (!cert) {
|
|
const domainSANs = [
|
|
{ type: 2, value: normalizedServername },
|
|
{ type: 2, value: 'localhost' },
|
|
{ type: 7, value: '127.0.0.1' }
|
|
];
|
|
cert = ca.getOrCreateDomainCert(normalizedServername, domainSANs);
|
|
setCertCache(normalizedServername, cert);
|
|
}
|
|
logDebug('Proxy', `Using/created certificate for P2P domain ${normalizedServername}`);
|
|
try {
|
|
const secureContext = tls.createSecureContext({
|
|
key: cert.key,
|
|
cert: cert.cert
|
|
});
|
|
cb(null, secureContext);
|
|
} catch (err) {
|
|
logError('Proxy', `Error creating secure context for ${normalizedServername}: ${err.message}`);
|
|
cb(err);
|
|
}
|
|
return;
|
|
}
|
|
} catch (err) {
|
|
logError('Proxy', `Error checking P2P domain ${normalizedServername}: ${err.message}`);
|
|
}
|
|
},
|
|
key: certCache.get(defaultDomain).key,
|
|
cert: certCache.get(defaultDomain).cert
|
|
});
|
|
|
|
httpsServer.on('request', async (req, res) => {
|
|
try {
|
|
const host = req.headers.host;
|
|
let domain = host ? host.split(':')[0].toLowerCase() : defaultDomain;
|
|
if (domain === '127.0.0.1') {
|
|
domain = 'localhost';
|
|
}
|
|
const path = req.url;
|
|
logInfo('Internal Proxy', `HTTPS request for domain: ${domain}, path: ${path}`);
|
|
|
|
// Enhanced HSTS header removal
|
|
const originalSetHeader = res.setHeader.bind(res);
|
|
res.setHeader = function(name, value) {
|
|
const lowerName = name.toLowerCase();
|
|
if (lowerName === 'strict-transport-security' || lowerName === 'hsts') {
|
|
logDebug('Proxy', `Blocked ${name} header`);
|
|
return this;
|
|
}
|
|
return originalSetHeader(name, value);
|
|
};
|
|
|
|
// Set security headers for all responses
|
|
const setSecurityHeaders = (res) => {
|
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
};
|
|
|
|
// Handle internal domains
|
|
if (internalDomainsList.includes(domain) || domain === 'localhost') {
|
|
setSecurityHeaders(res);
|
|
|
|
// Check if domain has a plugin
|
|
if (hasPlugin(domain)) {
|
|
// First, try serving static files from www/ directory
|
|
const staticHandled = await serveStaticFiles(domain, req, res);
|
|
if (staticHandled) {
|
|
return;
|
|
}
|
|
// If no static file found, try plugin handler
|
|
const handled = await handlePluginRequest(domain, req, res);
|
|
if (handled) {
|
|
return;
|
|
}
|
|
// If neither static files nor handler handled it, return 404
|
|
res.writeHead(404);
|
|
res.end('Not Found');
|
|
return;
|
|
}
|
|
|
|
// Try serving static files if no plugin exists
|
|
const staticHandled = await serveStaticFiles(domain, req, res);
|
|
if (staticHandled) {
|
|
return;
|
|
}
|
|
|
|
// Fallback to default handlers for backward compatibility
|
|
if (domain === 'p2ns.admin') {
|
|
// Lazy load to avoid circular dependency
|
|
const { handleAdminRequest } = require('../admin');
|
|
await handleAdminRequest(req, res);
|
|
return;
|
|
} else {
|
|
// All internal domains should be plugins or p2ns.admin
|
|
// If we reach here, it's an unexpected state
|
|
res.writeHead(404);
|
|
res.end('Not Found');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Check if it's a P2P domain
|
|
const hash = await getHashForDomain(domain);
|
|
if (!hash) {
|
|
logWarn('Proxy', `Ignoring request for non-P2P domain: ${domain}`);
|
|
setSecurityHeaders(res);
|
|
res.writeHead(404);
|
|
return res.end('Domain not found: Not an internal or P2P domain');
|
|
}
|
|
|
|
// Proceed with P2P domain handling
|
|
if (!state.dnsPass) {
|
|
logError('Proxy', 'DNS service not initialized');
|
|
setSecurityHeaders(res);
|
|
res.writeHead(503);
|
|
return res.end('Service Unavailable: DNS service not initialized');
|
|
}
|
|
|
|
const localIP = (state.domainToIPMap.get ? state.domainToIPMap.get(domain) : state.domainToIPMap[domain]) || await createInterfaceForDomain(domain);
|
|
if (!localIP) {
|
|
logError('Proxy', `No DNS records for ${domain}`);
|
|
setSecurityHeaders(res);
|
|
res.writeHead(404);
|
|
return res.end('Domain not found');
|
|
}
|
|
|
|
// Ensure holesail client is running and responsive
|
|
await restartHolesailClient(domain, hash, localIP, state.internalPort);
|
|
|
|
// Verify connection is actually responsive before proxying
|
|
const { checkPortResponsive } = require('../infrastructure/utils');
|
|
const key = `${domain}:${state.internalPort}`;
|
|
const isResponsive = await checkPortResponsive(localIP, state.internalPort);
|
|
|
|
if (!isResponsive) {
|
|
logWarn('Proxy', `Connection for ${key} is not responsive, attempting restart`);
|
|
// Force restart by cleaning up first
|
|
const existing = state.holesails.get(key);
|
|
if (existing) {
|
|
try {
|
|
await existing.close();
|
|
state.holesails.delete(key);
|
|
if (state.holesailStartTimes) {
|
|
state.holesailStartTimes.delete(key);
|
|
}
|
|
} catch (err) {
|
|
logError('Proxy', `Error closing unresponsive connection: ${err.message}`);
|
|
}
|
|
}
|
|
// Restart the connection
|
|
await restartHolesailClient(domain, hash, localIP, state.internalPort);
|
|
|
|
// Check again after restart
|
|
const stillUnresponsive = !(await checkPortResponsive(localIP, state.internalPort));
|
|
if (stillUnresponsive) {
|
|
logError('Proxy', `Connection for ${key} still unresponsive after restart`);
|
|
setSecurityHeaders(res);
|
|
res.writeHead(503);
|
|
return res.end('Service Unavailable: Connection not ready');
|
|
}
|
|
}
|
|
|
|
const options = {
|
|
hostname: localIP,
|
|
port: state.internalPort,
|
|
path: path,
|
|
method: req.method,
|
|
headers: req.headers,
|
|
};
|
|
|
|
const proxyRequest = http.request(options, (proxyRes) => {
|
|
const headers = {};
|
|
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
|
const lowerKey = key.toLowerCase();
|
|
if (lowerKey !== 'strict-transport-security' && lowerKey !== 'hsts') {
|
|
headers[key] = value;
|
|
}
|
|
}
|
|
|
|
setSecurityHeaders(res);
|
|
res.writeHead(proxyRes.statusCode, headers);
|
|
proxyRes.pipe(res, { end: true });
|
|
});
|
|
|
|
proxyRequest.on('error', (err) => {
|
|
logError('Proxy', `Error proxying request for ${domain}: ${err.message}`);
|
|
setSecurityHeaders(res);
|
|
res.writeHead(500);
|
|
res.end('Internal Server Error');
|
|
});
|
|
|
|
req.pipe(proxyRequest, { end: true });
|
|
} catch (err) {
|
|
logError('Proxy', `Failed to handle request: ${err.message}`);
|
|
res.writeHead(500);
|
|
res.end('Internal Server Error');
|
|
}
|
|
});
|
|
|
|
httpsServer.on('upgrade', async (req, socket, head) => {
|
|
try {
|
|
const host = req.headers.host;
|
|
let domain = host ? host.split(':')[0].toLowerCase() : defaultDomain;
|
|
if (domain === '127.0.0.1') {
|
|
domain = 'localhost';
|
|
}
|
|
const path = req.url;
|
|
logInfo('Internal Proxy', `WebSocket upgrade for domain: ${domain}, path: ${path}`);
|
|
|
|
if (domain === 'p2ns.admin' && path === '/ws') {
|
|
// Lazy load to avoid circular dependency
|
|
const { adminWss } = require('../admin');
|
|
adminWss.handleUpgrade(req, socket, head, (ws) => {
|
|
adminWss.emit('connection', ws, req);
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (internalDomainsList.includes(domain) || domain === 'localhost') {
|
|
// Check if domain has a plugin with WebSocket support
|
|
if (hasPlugin(domain)) {
|
|
const { getPluginWebSocket } = require('../plugins/plugin-handler');
|
|
const pluginWss = getPluginWebSocket(domain);
|
|
if (pluginWss && path === '/ws') {
|
|
logInfo('Internal Proxy', `Handling WebSocket upgrade for plugin ${domain}`);
|
|
try {
|
|
pluginWss.handleUpgrade(req, socket, head, (ws) => {
|
|
pluginWss.emit('connection', ws, req);
|
|
});
|
|
return;
|
|
} catch (err) {
|
|
logError('Internal Proxy', `Error handling WebSocket upgrade for ${domain}: ${err.message}`);
|
|
if (err.stack) {
|
|
logError('Internal Proxy', `Stack trace: ${err.stack}`);
|
|
}
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
} else {
|
|
logWarn('Internal Proxy', `Plugin ${domain} has no WebSocket server registered (wss: ${pluginWss ? 'exists' : 'null'}, path: ${path})`);
|
|
}
|
|
} else {
|
|
logDebug('Internal Proxy', `Domain ${domain} has no plugin`);
|
|
}
|
|
socket.end('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
return;
|
|
}
|
|
|
|
const hash = await getHashForDomain(domain);
|
|
if (!hash) {
|
|
logWarn('Proxy', `Ignoring WebSocket upgrade for non-P2P domain: ${domain}`);
|
|
socket.end('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
return;
|
|
}
|
|
|
|
if (!state.dnsPass) {
|
|
logError('Proxy', 'DNS service not initialized');
|
|
socket.end('HTTP/1.1 503 Service Unavailable\r\n\r\n');
|
|
return;
|
|
}
|
|
|
|
const localIP = (state.domainToIPMap.get ? state.domainToIPMap.get(domain) : state.domainToIPMap[domain]) || await createInterfaceForDomain(domain);
|
|
if (!localIP) {
|
|
socket.end('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
return;
|
|
}
|
|
|
|
// Ensure holesail client is running and responsive
|
|
await restartHolesailClient(domain, hash, localIP, state.internalPort);
|
|
|
|
// Verify connection is actually responsive before proxying
|
|
const { checkPortResponsive } = require('../infrastructure/utils');
|
|
const key = `${domain}:${state.internalPort}`;
|
|
const isResponsive = await checkPortResponsive(localIP, state.internalPort);
|
|
|
|
if (!isResponsive) {
|
|
logWarn('Proxy', `WebSocket connection for ${key} is not responsive, attempting restart`);
|
|
// Force restart by cleaning up first
|
|
const existing = state.holesails.get(key);
|
|
if (existing) {
|
|
try {
|
|
await existing.close();
|
|
state.holesails.delete(key);
|
|
if (state.holesailStartTimes) {
|
|
state.holesailStartTimes.delete(key);
|
|
}
|
|
} catch (err) {
|
|
logError('Proxy', `Error closing unresponsive WebSocket connection: ${err.message}`);
|
|
}
|
|
}
|
|
// Restart the connection
|
|
await restartHolesailClient(domain, hash, localIP, state.internalPort);
|
|
|
|
// Check again after restart
|
|
const stillUnresponsive = !(await checkPortResponsive(localIP, state.internalPort));
|
|
if (stillUnresponsive) {
|
|
logError('Proxy', `WebSocket connection for ${key} still unresponsive after restart`);
|
|
socket.end('HTTP/1.1 503 Service Unavailable\r\n\r\n');
|
|
return;
|
|
}
|
|
}
|
|
|
|
const clientReq = http.request({
|
|
hostname: localIP,
|
|
port: state.internalPort,
|
|
path: path,
|
|
method: req.method,
|
|
headers: req.headers
|
|
});
|
|
|
|
clientReq.end();
|
|
clientReq.on('upgrade', (clientRes, clientSocket, clientHead) => {
|
|
let headers = '';
|
|
for (const [key, value] of Object.entries(clientRes.headers)) {
|
|
const lowerKey = key.toLowerCase();
|
|
if (lowerKey !== 'strict-transport-security' && lowerKey !== 'hsts') {
|
|
headers += `${key}: ${value}\r\n`;
|
|
}
|
|
}
|
|
socket.write(`HTTP/1.1 101 Switching Protocols\r\n${headers}\r\n`);
|
|
if (clientHead.length > 0) {
|
|
socket.write(clientHead);
|
|
}
|
|
clientSocket.pipe(socket);
|
|
socket.pipe(clientSocket);
|
|
});
|
|
|
|
clientReq.on('response', (res) => {
|
|
socket.end(`HTTP/1.1 ${res.statusCode} ${res.statusMessage}\r\n\r\n`);
|
|
});
|
|
|
|
clientReq.on('error', (err) => {
|
|
logError('Proxy', `WebSocket proxy error for ${domain}: ${err.message}`);
|
|
socket.end('HTTP/1.1 500 Internal Server Error\r\n\r\n');
|
|
});
|
|
} catch (err) {
|
|
logError('Proxy', `Failed to handle WebSocket upgrade: ${err.message}`);
|
|
socket.end('HTTP/1.1 500 Internal Server Error\r\n\r\n');
|
|
}
|
|
});
|
|
|
|
httpsServer.on('clientError', (err, socket) => {
|
|
// Filter out common benign errors like "socket hang up"
|
|
if (err.message && !err.message.toLowerCase().includes('socket hang up')) {
|
|
logError('Proxy', `Client error: ${err.message}`);
|
|
}
|
|
if (socket.writable) {
|
|
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
|
}
|
|
});
|
|
|
|
httpsServer.listen(process.env.HTTPS_PORT || 443, '127.0.0.1', () => {
|
|
logInfo('Internal Proxy', `HTTPS server running on port ${process.env.HTTPS_PORT || 443} at 127.0.0.1`);
|
|
logInfo('Internal Proxy', `Internal domains configured: ${internalDomainsList.join(', ')}`);
|
|
});
|
|
|
|
httpsServer.on('error', (err) => {
|
|
logError('Proxy', `HTTPS server error: ${err.message}`);
|
|
});
|
|
}
|
|
|
|
module.exports = { setupProxyServer, updateProxyServerCertificates };
|
|
|