#!/usr/bin/env node const fs=require("fs"); const net=require("net"); const https=require("https"); const WebSocket=require("uWebSockets.js"); let listenport=null; let upstream=null; function parseUpstream(arg){ const [host, port]=arg.split(":"); return {host, port}; } let httpsConfig=null; if(process.argv.length==6){ upstream=parseUpstream(process.argv[2]); listenport=+process.argv[3]; console.log("Reading keys for https"); httpsConfig={ key_file_name: process.argv[4], cert_file_name: process.argv[5], }; } else if(process.argv.length==4){ upstream=parseUpstream(process.argv[2]); listenport=+process.argv[3]; console.log("WARNING: Running without SSL!"); } else { console.error("Usage: ./server.js # proxy without SSL"); console.error(" ./server.js # proxy with SSL"); console.error("'' indicates the plain-tcp tomsg server to proxy to."); console.error("'' indicates the port to listen for websocket connections on."); process.exit(1); } if(process.getuid()==0){ console.log(`Old uid: ${process.getuid()}, old gid: ${process.getgid()}; setting to nobody...`); process.setgid("nobody"); process.setuid("nobody"); console.log(`New uid: ${process.getuid()}, new gid: ${process.getgid()}`); } let wsServer; if(httpsConfig){ wsServer=WebSocket.SSLApp(httpsConfig); } else { wsServer=WebSocket.App(); } wsServer=wsServer.ws("/*",{ open: sock=>{ const stateobj={netconn: null, buffer: [], sock_closed: false}; sock["tomsgdata"]=stateobj; let linebuf=""; stateobj.netconn=net.connect(upstream.port,upstream.host,()=>{ for(const item of stateobj.buffer){ stateobj.netconn.write(item); stateobj.netconn.write("\n"); } stateobj.buffer=[]; }); stateobj.netconn.on("close",()=>{ if(!stateobj.sock_closed)sock.close(); }); stateobj.netconn.on("data",(data)=>{ linebuf+=data; let idx; while((idx=linebuf.indexOf("\n"))!=-1){ sock.send(linebuf.slice(0,idx)); linebuf=linebuf.slice(idx+1); } }); stateobj.netconn.on("error",()=>{ if(!stateobj.sock_closed)sock.close(); }); }, message: (sock,data,isBinary)=>{ const stateobj=sock["tomsgdata"]; data=new Uint8Array(data); if(stateobj.netconn.connecting){ stateobj.buffer.push(data); } else { stateobj.netconn.write(data); stateobj.netconn.write("\n"); } }, close: sock=>{ const stateobj=sock["tomsgdata"]; stateobj.sock_closed=true; try {stateobj.netconn.end();} catch (e) {} } }); wsServer=wsServer.listen(listenport,listenSocket=>{ if(listenSocket){ console.log(`Websocket server${httpsConfig?" (SSL)":""} bound on port ${listenport}`); } });