melq
Version:
Quantum-secure chat network with ML-KEM-768 encryption and host-based architecture
179 lines (152 loc) • 5.52 kB
JavaScript
import dgram from 'dgram';
import { networkInterfaces } from 'os';
import chalk from 'chalk';
const DISCOVERY_PORT = 41234;
const DISCOVERY_MESSAGE = 'MELQ_DISCOVERY_REQUEST';
const DISCOVERY_RESPONSE = 'MELQ_DISCOVERY_RESPONSE';
export class NetworkDiscovery {
constructor() {
this.socket = null;
this.isListening = false;
this.discoveredNetworks = new Map();
}
// Start advertising this node as a MELQ network host
async startAdvertising(nodeInfo) {
this.socket = dgram.createSocket('udp4');
this.socket.on('message', (msg, rinfo) => {
const message = msg.toString();
if (message === DISCOVERY_MESSAGE) {
// Someone is looking for MELQ networks, respond with our info
const response = JSON.stringify({
type: DISCOVERY_RESPONSE,
nodeId: nodeInfo.nodeId,
networkName: `${nodeInfo.nodeId.slice(-8)}'s Network`,
host: this.getLocalIP(),
port: nodeInfo.port,
connectionCode: `melq://${this.getLocalIP()}:${nodeInfo.port}`,
timestamp: Date.now()
});
this.socket.send(response, rinfo.port, rinfo.address);
}
});
await new Promise((resolve, reject) => {
this.socket.bind(DISCOVERY_PORT, (err) => {
if (err) reject(err);
else {
this.isListening = true;
console.log(chalk.gray(`🔍 Network discovery active on port ${DISCOVERY_PORT}`));
resolve();
}
});
});
}
// Discover MELQ networks on the local network
async discoverNetworks(timeoutMs = 3000) {
return new Promise((resolve) => {
const discoverySocket = dgram.createSocket('udp4');
this.discoveredNetworks.clear();
// Listen for responses
discoverySocket.on('message', (msg, rinfo) => {
try {
const response = JSON.parse(msg.toString());
if (response.type === DISCOVERY_RESPONSE) {
this.discoveredNetworks.set(response.nodeId, {
nodeId: response.nodeId,
networkName: response.networkName,
host: response.host,
port: response.port,
connectionCode: response.connectionCode,
address: rinfo.address,
timestamp: response.timestamp
});
}
} catch (error) {
// Ignore invalid messages
}
});
// Bind and start discovery
discoverySocket.bind(() => {
discoverySocket.setBroadcast(true);
// Send discovery request to broadcast addresses
const broadcastAddresses = this.getBroadcastAddresses();
broadcastAddresses.forEach(addr => {
discoverySocket.send(
DISCOVERY_MESSAGE,
DISCOVERY_PORT,
addr,
(err) => {
if (err) {
console.error(chalk.gray(`Discovery broadcast to ${addr} failed:`, err.message));
}
}
);
});
// Wait for responses
setTimeout(() => {
discoverySocket.close();
resolve(Array.from(this.discoveredNetworks.values()));
}, timeoutMs);
});
});
}
// Get all broadcast addresses for the local network interfaces
getBroadcastAddresses() {
const addresses = [];
const nets = networkInterfaces();
for (const name of Object.keys(nets)) {
for (const net of nets[name]) {
// Skip internal and non-IPv4 addresses
if (net.family === 'IPv4' && !net.internal) {
// Calculate broadcast address
const ip = net.address.split('.').map(Number);
const netmask = net.netmask.split('.').map(Number);
const broadcast = ip.map((octet, i) =>
octet | (255 ^ netmask[i])
).join('.');
addresses.push(broadcast);
}
}
}
// Also add common broadcast address
addresses.push('255.255.255.255');
return [...new Set(addresses)]; // Remove duplicates
}
getLocalIP() {
const nets = networkInterfaces();
for (const name of Object.keys(nets)) {
for (const net of nets[name]) {
if (net.family === 'IPv4' && !net.internal) {
return net.address;
}
}
}
return '127.0.0.1';
}
stop() {
if (this.socket) {
this.socket.close();
this.isListening = false;
}
}
}
export async function discoverLocalNetworks() {
console.log(chalk.yellow('🔍 Scanning for local MELQ networks...'));
const discovery = new NetworkDiscovery();
const networks = await discovery.discoverNetworks(5000);
if (networks.length === 0) {
console.log(chalk.gray('No local MELQ networks found.'));
console.log(chalk.gray('Try:'));
console.log(chalk.gray('• Make sure other nodes are running on this network'));
console.log(chalk.gray('• Check your firewall settings'));
console.log(chalk.gray('• Use connection codes for remote networks'));
return [];
}
console.log(chalk.green(`Found ${networks.length} local network(s):`));
networks.forEach((network, index) => {
const age = Math.floor((Date.now() - network.timestamp) / 1000);
console.log(chalk.cyan(`${index + 1}. ${network.networkName}`));
console.log(chalk.gray(` Host: ${network.host}:${network.port} (${age}s ago)`));
console.log(chalk.gray(` Code: ${network.connectionCode}`));
});
return networks;
}