diff --git a/worker-server.js b/worker-server.js index 2adbc30..f81da20 100644 --- a/worker-server.js +++ b/worker-server.js @@ -6,6 +6,7 @@ const http = require('http'); const httpProxy = require('http-proxy'); const HyperDHTServer = require('hyperdht'); const b32 = require('hi-base32'); +const fetch = require('node-fetch'); // Configuration constants const CONFIG = { @@ -13,7 +14,7 @@ const CONFIG = { WORKER_MULTIPLIER: 4, PROXY_TIMEOUT: 360000, // 6 minutes TUNNEL_TIMEOUT: 3600000, // Increased to 1 hour for long-lived WebSocket connections - DEBUG: false, // Keep enabled for diagnostics + DEBUG: true, // Enabled for diagnostics CONINFO: false, MAX_SOCKETS: 500, MAX_TUNNELS: 1000, // Increased to handle high load @@ -22,6 +23,7 @@ const CONFIG = { CONNECT_RETRY_MS: 100, MAX_CONNECT_RETRIES: 3, TUNNEL_FORCE_CLOSE_MS: 10000, // Used for HTTP requests + LOOKUP_API: 'https://sub-api.my-mc.link', }; // Shared HTTP agent @@ -73,12 +75,55 @@ if (cluster.isMaster) { res.end('Invalid host header'); return; } - const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase())); - if (publicKey.length < 32) { - console.log('Invalid public key'); - res.writeHead(418, { 'Content-Type': 'text/html' }); - res.end(content); - return; + let subdomain = split[0].toLowerCase(); + let publicKey; + + // Try decoding subdomain as base32 hash + try { + publicKey = Buffer.from(b32.decode.asBytes(subdomain.toUpperCase())); + if (publicKey.length !== 32) throw new Error('Invalid public key length'); + if (CONFIG.DEBUG) console.log(`Subdomain ${subdomain} is a valid hash, using directly`); + } catch (e) { + // Not a valid hash, perform API lookup + if (CONFIG.DEBUG) console.log(`Subdomain ${subdomain} is not a valid hash, performing API lookup`); + const isMapRequest = subdomain.endsWith('-map'); + const baseSubdomain = isMapRequest ? subdomain.replace(/-map$/, '') : subdomain; + const lookupUrl = `${CONFIG.LOOKUP_API}/${baseSubdomain}`; + + try { + if (CONFIG.DEBUG) console.log(`Fetching from ${lookupUrl} for ${isMapRequest ? 'map' : 'website'} request`); + const response = await fetch(lookupUrl); + const data = await response.json(); + + if (!data.success || !data.data) { + console.log(`No record found for subdomain ${baseSubdomain}`); + res.writeHead(404, { 'Content-Type': 'text/html' }); + res.end(content); + return; + } + + const hash = isMapRequest ? data.data.connectionHashMap : data.data.connectionHash; + if (CONFIG.DEBUG) console.log(`Using hash: ${hash} for ${isMapRequest ? 'connectionHashMap' : 'connectionHash'}`); + if (!hash) { + console.log(`No ${isMapRequest ? 'map' : 'website'} hash found for ${baseSubdomain}`); + res.writeHead(404, { 'Content-Type': 'text/html' }); + res.end(content); + return; + } + + publicKey = Buffer.from(b32.decode.asBytes(hash.toUpperCase())); + if (publicKey.length !== 32) { + console.log(`Invalid public key from API for ${baseSubdomain}: ${hash}`); + res.writeHead(404, { 'Content-Type': 'text/html' }); + res.end(content); + return; + } + } catch (apiErr) { + console.error(`API lookup error for ${baseSubdomain}:`, apiErr.message); + res.writeHead(404, { 'Content-Type': 'text/html' }); + res.end(content); + return; + } } if (activeTunnels.size >= CONFIG.MAX_TUNNELS) { @@ -128,11 +173,51 @@ if (cluster.isMaster) { socket.destroy(); return; } - const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase())); - if (publicKey.length < 32) { - console.log('Invalid public key'); - socket.destroy(); - return; + let subdomain = split[0].toLowerCase(); + let publicKey; + + // Try decoding subdomain as base32 hash + try { + publicKey = Buffer.from(b32.decode.asBytes(subdomain.toUpperCase())); + if (publicKey.length !== 32) throw new Error('Invalid public key length'); + if (CONFIG.DEBUG) console.log(`Subdomain ${subdomain} is a valid hash, using directly`); + } catch (e) { + // Not a valid hash, perform API lookup + if (CONFIG.DEBUG) console.log(`Subdomain ${subdomain} is not a valid hash, performing API lookup`); + const isMapRequest = subdomain.endsWith('-map'); + const baseSubdomain = isMapRequest ? subdomain.replace(/-map$/, '') : subdomain; + const lookupUrl = `${CONFIG.LOOKUP_API}/${baseSubdomain}`; + + try { + if (CONFIG.DEBUG) console.log(`Fetching from ${lookupUrl} for ${isMapRequest ? 'map' : 'website'} request`); + const response = await fetch(lookupUrl); + const data = await response.json(); + + if (!data.success || !data.data) { + console.log(`No record found for subdomain ${baseSubdomain}`); + socket.destroy(); + return; + } + + const hash = isMapRequest ? data.data.connectionHashMap : data.data.connectionHash; + if (CONFIG.DEBUG) console.log(`Using hash: ${hash} for ${isMapRequest ? 'connectionHashMap' : 'connectionHash'}`); + if (!hash) { + console.log(`No ${isMapRequest ? 'map' : 'website'} hash found for ${baseSubdomain}`); + socket.destroy(); + return; + } + + publicKey = Buffer.from(b32.decode.asBytes(hash.toUpperCase())); + if (publicKey.length !== 32) { + console.log(`Invalid public key from API for ${baseSubdomain}: ${hash}`); + socket.destroy(); + return; + } + } catch (apiErr) { + console.error(`API lookup error for ${baseSubdomain}:`, apiErr.message); + socket.destroy(); + return; + } } if (activeTunnels.size >= CONFIG.MAX_TUNNELS) {