From b086e1c0a5f67ef078a4d251250455e64acc4a6b Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 1 Jun 2018 06:41:32 +0000 Subject: [PATCH] add dynamic tcp and cleanup --- bin/telebitd.js | 37 ++++++---------- handlers.js | 56 ++++++++++-------------- lib/pipe-ws.js | 54 +++++++++++++++++++++++ lib/unwrap-tls.js | 102 ++++++++++++------------------------------- telebitd.js | 108 +++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 214 insertions(+), 143 deletions(-) create mode 100644 lib/pipe-ws.js diff --git a/bin/telebitd.js b/bin/telebitd.js index 804920a..d7425e9 100755 --- a/bin/telebitd.js +++ b/bin/telebitd.js @@ -63,7 +63,7 @@ function applyConfig(config) { } function approveDomains(opts, certs, cb) { - console.log('[debug] approveDomains', opts.domains); + if (state.debug) { console.log('[debug] approveDomains', opts.domains); } // This is where you check your database and associated // email addresses with domains and agreements and such @@ -75,11 +75,12 @@ function applyConfig(config) { return; } - if (state.config.vhost) { - console.log('[sni] vhost checking is turned on'); + if (!state.validHosts) { state.validHosts = {}; } + if (!state.validHosts[opts.domains[0]] && state.config.vhost) { + if (state.debug) { console.log('[sni] vhost checking is turned on'); } var vhost = state.config.vhost.replace(/:hostname/, opts.domains[0]); require('fs').readdir(vhost, function (err, nodes) { - console.log('[sni] checking fs vhost'); + if (state.debug) { console.log('[sni] checking fs vhost', opts.domains[0], !err); } if (err) { check(); return; } if (nodes) { approve(); } }); @@ -87,8 +88,10 @@ function applyConfig(config) { } function approve() { + state.validHosts[opts.domains[0]] = true; opts.email = state.config.email; opts.agreeTos = state.config.agreeTos; + opts.communityMember = state.config.communityMember || state.config.greenlock.communityMember; opts.challenges = { // TODO dns-01 'http-01': require('le-challenge-fs').create({ webrootPath: '/tmp/acme-challenges' }) @@ -98,41 +101,28 @@ function applyConfig(config) { } function check() { - console.log('[sni] checking servername'); + if (state.debug) { console.log('[sni] checking servername'); } if (-1 !== state.servernames.indexOf(opts.domain) || -1 !== (state._servernames||[]).indexOf(opts.domain)) { approve(); } else { cb(new Error("failed the approval chain '" + opts.domains[0] + "'")); } - console.log('Approve Domains cb'); } + check(); } -/* - if (!config.email || !config.agreeTos) { - console.error("You didn't specify --email and --agree-tos"); - console.error("(required for ACME / Let's Encrypt / Greenlock TLS/SSL certs)"); - console.error(""); - process.exit(1); - } -*/ - state.greenlock = Greenlock.create({ version: state.config.greenlock.version || 'draft-11' , server: state.config.greenlock.server || 'https://acme-v02.api.letsencrypt.org/directory' - //, server: 'https://acme-staging-v02.api.letsencrypt.org/directory' - , store: require('le-store-certbot').create({ debug: true, webrootPath: '/tmp/acme-challenges' }) + , store: require('le-store-certbot').create({ debug: state.config.debug || state.config.greenlock.debug, webrootPath: '/tmp/acme-challenges' }) , approveDomains: approveDomains - + , telemetry: state.config.telemetry || state.config.greenlock.telemetry , configDir: state.config.greenlock.configDir , debug: state.config.debug || state.config.greenlock.debug - - //, approvedDomains: program.servernames - }); require('../handlers').create(state); // adds directly to config for now... @@ -147,14 +137,13 @@ function applyConfig(config) { wss.on('connection', netConnHandlers.ws); state.ports.forEach(function (port) { if (state.tcp[port]) { - console.error("skipping previously added port " + port); + console.warn("[cli] skipping previously added port " + port); return; } state.tcp[port] = net.createServer(); state.tcp[port].listen(port, function () { - console.log('listening plain TCP on ' + port); + console.info('[cli] Listening for TCP connections on', port); }); - //state.tcp[port].on('connection', function (conn) { netConnHandlers.tcp(conn, port); }); state.tcp[port].on('connection', netConnHandlers.tcp); }); //}); diff --git a/handlers.js b/handlers.js index de0fda3..bd69a15 100644 --- a/handlers.js +++ b/handlers.js @@ -19,7 +19,7 @@ module.exports.create = function (state) { var setupTlsOpts = { SNICallback: function (servername, cb) { if (!setupSniCallback) { - console.error("No way to get https certificates..."); + console.error("[setup.SNICallback] No way to get https certificates..."); cb(new Error("telebitd sni setup fail")); return; } @@ -29,7 +29,6 @@ module.exports.create = function (state) { // Probably a reverse proxy on an internal network (or ACME challenge) function notFound(req, res) { - console.log('req.socket.encrypted', req.socket.encrypted); res.statusCode = 404; res.end("File not found.\n"); } @@ -79,10 +78,10 @@ module.exports.create = function (state) { // tlsServer.emit('connection', socket); // this didn't work either //console.log('chunkLen', firstChunk.byteLength); - console.log('httpsInvalid servername', servername); + console.log('[httpsInvalid] servername', servername); //state.tlsInvalidSniServer.emit('connection', wrapSocket(socket)); var tlsInvalidSniServer = tls.createServer(state.tlsOptions, function (tlsSocket) { - console.log('tls connection'); + console.log('[tlsInvalid] tls connection'); // things get a little messed up here var httpInvalidSniServer = http.createServer(function (req, res) { if (!servername) { @@ -118,10 +117,8 @@ module.exports.create = function (state) { var serveAdmin = require('serve-static')(__dirname + '/admin', { redirect: true }); var finalhandler = require('finalhandler'); state.httpTunnelServer = http.createServer(function (req, res) { - console.log('admin req.socket.encrypted', req.socket.encrypted); res.setHeader('connection', 'close'); serveAdmin(req, res, function () { - console.log("serveAdmin fail"); finalhandler(req, res) }); }); @@ -129,17 +126,13 @@ module.exports.create = function (state) { tunnelAdminTlsOpts[key] = state.tlsOptions[key]; }); if (state.greenlock && state.greenlock.tlsOptions) { - console.log('greenlock tlsOptions for SNICallback'); - tunnelAdminTlsOpts.SNICallback = function (servername, cb) { - console.log("time to handle '" + servername + "'"); - state.greenlock.tlsOptions.SNICallback(servername, cb); - }; + tunnelAdminTlsOpts.SNICallback = state.greenlock.tlsOptions.SNICallback; } else { - console.log('custom or null tlsOptions for SNICallback'); + console.log('[Admin] custom or null tlsOptions for SNICallback'); tunnelAdminTlsOpts.SNICallback = tunnelAdminTlsOpts.SNICallback || noSniCallback('admin'); } state.tlsTunnelServer = tls.createServer(tunnelAdminTlsOpts, function (tlsSocket) { - console.log('(Admin) tls connection'); + if (state.debug) { console.log('[Admin] new tls-terminated connection'); } // things get a little messed up here (state.httpTunnelServer || state.httpServer).emit('connection', tlsSocket); }); @@ -152,7 +145,7 @@ module.exports.create = function (state) { // tlsServer.emit('connection', socket); // this didn't work either //console.log('chunkLen', firstChunk.byteLength); - console.log('httpsTunnel (Admin) servername', servername); + if (state.debug) { console.log('[Admin] new raw tls connection for', servername); } state.tlsTunnelServer.emit('connection', wrapSocket(socket)); }; @@ -162,28 +155,26 @@ module.exports.create = function (state) { var serveSetup = require('serve-static')(__dirname + '/admin/setup', { redirect: true }); var finalhandler = require('finalhandler'); state.httpSetupServer = http.createServer(function (req, res) { - console.log('req.socket.encrypted', req.socket.encrypted); if (req.socket.encrypted) { serveSetup(req, res, finalhandler(req, res)); return; } - console.log('try greenlock middleware'); (state.greenlock && state.greenlock.middleware(redirectHttpsAndClose) || redirectHttpsAndClose)(req, res, function () { - console.log('fallthrough to setup ui'); + console.log('[Setup] fallthrough to setup ui'); serveSetup(req, res, finalhandler(req, res)); }); }); state.tlsSetupServer = tls.createServer(setupTlsOpts, function (tlsSocket) { - console.log('tls connection'); + console.log('[Setup] terminated tls connection'); // things get a little messed up here state.httpSetupServer.emit('connection', tlsSocket); }); state.tlsSetupServer.on('tlsClientError', function () { - console.error('tlsClientError SetupServer'); + console.error('[Setup] tlsClientError SetupServer'); }); state.httpsSetupServer = function (servername, socket) { - console.log('httpsTunnel (Setup) servername', servername); + console.log('[Setup] raw tls connection for', servername); state._servernames = [servername]; state.config.agreeTos = true; // TODO: BUG XXX BAD, make user accept setupSniCallback = state.greenlock.tlsOptions.SNICallback || noSniCallback('setup'); @@ -194,31 +185,30 @@ module.exports.create = function (state) { // vhost // state.httpVhost = http.createServer(function (req, res) { - console.log('httpVhost (local)'); - console.log('req.socket.encrypted', req.socket.encrypted); + if (state.debug) { console.log('[vhost] encrypted?', req.socket.encrypted); } var finalhandler = require('finalhandler'); // TODO compare SNI to hostname? var host = (req.headers.host||'').toLowerCase().trim(); - var serveSetup = require('serve-static')(state.config.vhost.replace(/:hostname/g, host), { redirect: true }); + var serveVhost = require('serve-static')(state.config.vhost.replace(/:hostname/g, host), { redirect: true }); - if (req.socket.encrypted) { serveSetup(req, res, finalhandler(req, res)); return; } + if (req.socket.encrypted) { serveVhost(req, res, finalhandler(req, res)); return; } - console.log('try greenlock middleware for vhost'); - (state.greenlock && state.greenlock.middleware(redirectHttpsAndClose) - || redirectHttpsAndClose)(req, res, function () { - console.log('fallthrough to vhost serving???'); - serveSetup(req, res, finalhandler(req, res)); - }); + if (!state.greenlock) { + console.error("Cannot vhost without greenlock options"); + res.end("Cannot vhost without greenlock options"); + } + + state.greenlock.middleware(redirectHttpsAndClose); }); state.tlsVhost = tls.createServer( { SNICallback: function (servername, cb) { - console.log('tlsVhost debug SNICallback', servername); + if (state.debug) { console.log('[vhost] SNICallback for', servername); } tunnelAdminTlsOpts.SNICallback(servername, cb); } } , function (tlsSocket) { - console.log('tlsVhost (local)'); + if (state.debug) { console.log('tlsVhost (local)'); } state.httpVhost.emit('connection', tlsSocket); } ); @@ -226,7 +216,7 @@ module.exports.create = function (state) { console.error('tlsClientError Vhost'); }); state.httpsVhost = function (servername, socket) { - console.log('httpsVhost (local)', servername); + if (state.debug) { console.log('[vhost] httpsVhost (local) for', servername); } state.tlsVhost.emit('connection', wrapSocket(socket)); }; }; diff --git a/lib/pipe-ws.js b/lib/pipe-ws.js new file mode 100644 index 0000000..089bd89 --- /dev/null +++ b/lib/pipe-ws.js @@ -0,0 +1,54 @@ +'use strict'; + +var Packer = require('proxy-packer'); + +module.exports = function pipeWs(servername, service, conn, remote, serviceport) { + var browserAddr = Packer.socketToAddr(conn); + var cid = Packer.addrToId(browserAddr); + browserAddr.service = service; + browserAddr.serviceport = serviceport; + browserAddr.name = servername; + conn.tunnelCid = cid; + var rid = Packer.socketToId(remote.upgradeReq.socket); + + //if (state.debug) { console.log('[pipeWs] client', cid, '=> remote', rid, 'for', servername, 'via', service); } + + function sendWs(data, serviceOverride) { + if (remote.ws && (!conn.tunnelClosing || serviceOverride)) { + try { + remote.ws.send(Packer.pack(browserAddr, data, serviceOverride), { binary: true }); + // If we can't send data over the websocket as fast as this connection can send it to us + // (or there are a lot of connections trying to send over the same websocket) then we + // need to pause the connection for a little. We pause all connections if any are paused + // to make things more fair so a connection doesn't get stuck waiting for everyone else + // to finish because it got caught on the boundary. Also if serviceOverride is set it + // means the connection is over, so no need to pause it. + if (!serviceOverride && (remote.pausedConns.length || remote.ws.bufferedAmount > 1024*1024)) { + // console.log('pausing', cid, 'to allow web socket to catch up'); + conn.pause(); + remote.pausedConns.push(conn); + } + } catch (err) { + console.warn('[pipeWs] remote', rid, ' => client', cid, 'error sending websocket message', err); + } + } + } + + remote.clients[cid] = conn; + + conn.on('data', function (chunk) { + //if (state.debug) { console.log('[pipeWs] client', cid, ' => remote', rid, chunk.byteLength, 'bytes'); } + sendWs(chunk); + }); + + conn.on('error', function (err) { + console.warn('[pipeWs] client', cid, 'connection error:', err); + }); + + conn.on('close', function (hadErr) { + //if (state.debug) { console.log('[pipeWs] client', cid, 'closing'); } + sendWs(null, hadErr ? 'error': 'end'); + delete remote.clients[cid]; + }); + +}; diff --git a/lib/unwrap-tls.js b/lib/unwrap-tls.js index ba1b2a8..84ff236 100644 --- a/lib/unwrap-tls.js +++ b/lib/unwrap-tls.js @@ -1,57 +1,10 @@ 'use strict'; -var Packer = require('proxy-packer'); var sni = require('sni'); +var pipeWs = require('./pipe-ws.js'); -function pipeWs(servername, service, conn, remote, serviceport) { - console.log('[pipeWs] servername:', servername, 'service:', service); - - var browserAddr = Packer.socketToAddr(conn); - browserAddr.service = service; - browserAddr.serviceport = serviceport; - browserAddr.name = servername; - var cid = Packer.addrToId(browserAddr); - conn.tunnelCid = cid; - console.log('[pipeWs] browser is', cid, 'home-cloud is', Packer.socketToId(remote.upgradeReq.socket)); - - function sendWs(data, serviceOverride) { - if (remote.ws && (!conn.tunnelClosing || serviceOverride)) { - try { - remote.ws.send(Packer.pack(browserAddr, data, serviceOverride), { binary: true }); - // If we can't send data over the websocket as fast as this connection can send it to us - // (or there are a lot of connections trying to send over the same websocket) then we - // need to pause the connection for a little. We pause all connections if any are paused - // to make things more fair so a connection doesn't get stuck waiting for everyone else - // to finish because it got caught on the boundary. Also if serviceOverride is set it - // means the connection is over, so no need to pause it. - if (!serviceOverride && (remote.pausedConns.length || remote.ws.bufferedAmount > 1024*1024)) { - // console.log('pausing', cid, 'to allow web socket to catch up'); - conn.pause(); - remote.pausedConns.push(conn); - } - } catch (err) { - console.warn('[pipeWs] error sending websocket message', err); - } - } - } - - remote.clients[cid] = conn; - conn.on('data', function (chunk) { - console.log('[pipeWs] data from browser to tunneler', chunk.byteLength); - sendWs(chunk); - }); - conn.on('error', function (err) { - console.warn('[pipeWs] browser connection error', err); - }); - conn.on('close', function (hadErr) { - console.log('[pipeWs] browser connection closing'); - sendWs(null, hadErr ? 'error': 'end'); - delete remote.clients[cid]; - }); -} - -module.exports.createTcpConnectionHandler = function (copts) { - var Devices = copts.Devices; +module.exports.createTcpConnectionHandler = function (state) { + var Devices = state.Devices; return function onTcpConnection(conn, serviceport) { serviceport = serviceport || conn.localPort; @@ -78,7 +31,7 @@ module.exports.createTcpConnectionHandler = function (copts) { // defer after return (instead of being in many places) function deferData(fn) { if (fn) { - copts[fn](servername, conn) + state[fn](servername, conn) } process.nextTick(function () { conn.resume(); @@ -93,51 +46,50 @@ module.exports.createTcpConnectionHandler = function (copts) { function tryTls() { var vhost; - console.log(""); - - if (!copts.servernames.length) { - console.log("https => admin => setup => (needs bogus tls certs to start?)"); + if (!state.servernames.length) { + console.info("[Setup] https => admin => setup => (needs bogus tls certs to start?)"); deferData('httpsSetupServer'); return; } - if (-1 !== copts.servernames.indexOf(servername)) { - console.log("Lock and load, admin interface time!"); + if (-1 !== state.servernames.indexOf(servername)) { + if (state.debug) { console.log("[Admin]", servername); } deferData('httpsTunnel'); return; } - if (copts.config.nowww && /^www\./i.test(servername)) { + if (state.config.nowww && /^www\./i.test(servername)) { console.log("TODO: use www bare redirect"); } function run() { if (!servername) { - console.log("No SNI was given, so there's nothing we can do here"); + if (state.debug) { console.log("No SNI was given, so there's nothing we can do here"); } deferData('httpsInvalid'); return; } - var nextDevice = Devices.next(copts.deviceLists, servername); + var nextDevice = Devices.next(state.deviceLists, servername); if (!nextDevice) { - console.log("No devices match the given servername"); + if (state.debug) { console.log("No devices match the given servername"); } deferData('httpsInvalid'); return; } - console.log("pipeWs(servername, service, socket, deviceLists['" + servername + "'])"); + if (state.debug) { console.log("pipeWs(servername, service, socket, deviceLists['" + servername + "'])"); } deferData(); pipeWs(servername, service, conn, nextDevice, serviceport); } - if (copts.config.vhost) { - console.log("VHOST path", copts.config.vhost); - vhost = copts.config.vhost.replace(/:hostname/, (servername||'')); - console.log("VHOST name", vhost); - //copts.httpsVhost(servername, conn); + // TODO don't run an fs check if we already know this is working elsewhere + //if (!state.validHosts) { state.validHosts = {}; } + if (state.config.vhost) { + vhost = state.config.vhost.replace(/:hostname/, (servername||'')); + if (state.debug) { console.log("[tcp] [vhost]", state.config.vhost, "=>", vhost); } + //state.httpsVhost(servername, conn); //return; require('fs').readdir(vhost, function (err, nodes) { - console.log("VHOST error?", err); + if (state.debug && err) { console.log("VHOST error", err); } if (err) { run(); return; } if (nodes) { deferData('httpsVhost'); } }); @@ -152,7 +104,7 @@ module.exports.createTcpConnectionHandler = function (copts) { // TLS service = 'https'; servername = (sni(firstChunk)||'').toLowerCase(); - console.log("tls hello servername:", servername); + if (state.debug) { console.log("[tcp] tls hello from '" + servername + "'"); } tryTls(); return; } @@ -161,13 +113,13 @@ module.exports.createTcpConnectionHandler = function (copts) { str = firstChunk.toString(); m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im); servername = (m && m[1].toLowerCase() || '').split(':')[0]; - console.log('servername', servername); + if (state.debug) { console.log("[tcp] http hostname '" + servername + "'"); } if (/HTTP\//i.test(str)) { - if (!copts.servernames.length) { - console.log('copts.httpSetupServer', copts.httpSetupServer); + if (!state.servernames.length) { + console.info("[tcp] No admin servername. Entering setup mode."); deferData(); - copts.httpSetupServer.emit('connection', conn); + state.httpSetupServer.emit('connection', conn); return; } @@ -176,9 +128,9 @@ module.exports.createTcpConnectionHandler = function (copts) { // /^\/\.well-known\/acme-challenge\//.test(str) if (/well-known/.test(str)) { // HTTP - if (Devices.exist(copts.deviceLists, servername)) { + if (Devices.exist(state.deviceLists, servername)) { deferData(); - pipeWs(servername, service, conn, Devices.next(copts.deviceLists, servername), serviceport); + pipeWs(servername, service, conn, Devices.next(state.deviceLists, servername), serviceport); return; } deferData('handleHttp'); diff --git a/telebitd.js b/telebitd.js index 1f383cc..d6e233c 100644 --- a/telebitd.js +++ b/telebitd.js @@ -12,6 +12,7 @@ function timeoutPromise(duration) { } var Devices = require('./lib/device-tracker'); +var pipeWs = require('./lib/pipe-ws.js'); module.exports.store = { Devices: Devices }; module.exports.create = function (state) { @@ -22,8 +23,70 @@ module.exports.create = function (state) { state.Devices = Devices; var onTcpConnection = require('./lib/unwrap-tls').createTcpConnectionHandler(state); + // TODO Use a Single TCP Handler + // Issues: + // * dynamic ports are dedicated to a device or cluster + // * servernames could come in on ports that belong to a different device + // * servernames could come in that belong to no device + // * this could lead to an attack / security vulnerability with ACME certificates + // Solutions + // * Restrict dynamic ports to a particular device + // * Restrict the use of servernames + function onDynTcpConn(conn) { + var serviceport = this.address().port; + console.log('[DynTcpConn] new connection on', serviceport); + var remote = Devices.next(state.deviceLists, serviceport) + + if (!remote) { + conn.write("[Sanity Error] I've got a blank space baby, but nowhere to write your name."); + conn.end(); + try { + this.close(); + } catch(e) { + console.error("[DynTcpConn] failed to close server:", e); + } + return; + } + + conn.once('data', function (firstChunk) { + console.log("[DynTcp] examining firstChunk", serviceport); + conn.pause(); + conn.unshift(firstChunk); + + var servername; + var hostname; + var str; + var m; + + if (22 === firstChunk[0]) { + servername = (sni(firstChunk)||'').toLowerCase(); + } else if (firstChunk[0] > 32 && firstChunk[0] < 127) { + str = firstChunk.toString(); + m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im); + hostname = (m && m[1].toLowerCase() || '').split(':')[0]; + } + + if (servername || hostname) { + if (servername) { + conn.write("TLS with sni is allowed only on standard ports. If you've registered '" + servername + "' use port 443."); + } else { + conn.write("HTTP with Host headers is not allowed on dynamic ports. If you've registered '" + hostname + "' use port 80."); + } + conn.end(); + return; + } + + // pipeWs(servername, servicename, client, remote, serviceport) + // remote.clients is managed as part of the piping process + console.log("[DynTcp] piping to remote", serviceport); + pipeWs(null, 'tcp', conn, remote, serviceport) + + process.nextTick(function () { conn.resume(); }); + }); + } + function onWsConnection(ws, upgradeReq) { - console.log(ws); + if (state.debug) { console.log('[ws] connection'); } var socketId = Packer.socketToId(upgradeReq.socket); var remotes = {}; @@ -131,6 +194,7 @@ module.exports.create = function (state) { token.ws = ws; token.upgradeReq = upgradeReq; token.clients = {}; + token.dynamicPorts = []; token.pausedConns = []; ws._socket.on('drain', function () { @@ -153,11 +217,26 @@ module.exports.create = function (state) { }); token.domains.forEach(function (domainname) { - console.log('domainname', domainname); Devices.add(state.deviceLists, domainname, token); }); + + function handleTcpServer() { + var serviceport = this.address().port; + console.info('[DynTcpConn] Port', serviceport, 'now open for', token.deviceId); + token.dynamicPorts.push(serviceport); + Devices.add(state.deviceLists, serviceport, token); + } + + try { + token.server = require('net').createServer(onDynTcpConn).listen(0, handleTcpServer); + } catch(e) { + // what a wonderful problem it will be the day that this bug needs to be fixed + // (i.e. there are enough users to run out of ports) + console.error("Error assigning a dynamic port to a new connection:", e); + } + remotes[jwtoken] = token; - console.log("added token '" + token.deviceId + "' to websocket", socketId); + console.info("[ws] authorized", socketId, "for", token.deviceId); return null; } @@ -172,15 +251,22 @@ module.exports.create = function (state) { remote.domains.forEach(function (domainname) { Devices.remove(state.deviceLists, domainname, remote); }); + remote.dynamicPorts.forEach(function (portnumber) { + Devices.remove(state.deviceLists, portnumber, remote); + }); remote.ws = null; remote.upgradeReq = null; + remote.server.close(function () { + console.log("[DynTcpConn] closing server for ", remote.server.address().port); + }); + remote.server = null; // Close all of the existing browser connections associated with this websocket connection. Object.keys(remote.clients).forEach(function (cid) { closeBrowserConn(cid); }); delete remotes[jwtoken]; - console.log("removed token '" + remote.deviceId + "' from websocket", socketId); + console.log("[ws] removed token '" + remote.deviceId + "' from", socketId); return null; } @@ -236,7 +322,7 @@ module.exports.create = function (state) { // We only ever send one command and we send it once, so we just hard coded the ID as 1. if (cmd[0] === -1) { if (cmd[1]) { - console.log('received error response to hello from', socketId, cmd[1]); + console.warn('received error response to hello from', socketId, cmd[1]); } } else { @@ -262,7 +348,7 @@ module.exports.create = function (state) { , onmessage: function (tun) { var cid = Packer.addrToId(tun); - console.log("remote '" + logName() + "' has data for '" + cid + "'", tun.data.byteLength); + if (state.debug) { console.log("remote '" + logName() + "' has data for '" + cid + "'", tun.data.byteLength); } var browserConn = getBrowserConn(cid); if (!browserConn) { @@ -319,7 +405,7 @@ module.exports.create = function (state) { } , onerror: function (tun) { var cid = Packer.addrToId(tun); - console.log('[TunnelError]', cid, tun.message); + console.warn('[TunnelError]', cid, tun.message); closeBrowserConn(cid); } }; @@ -343,7 +429,7 @@ module.exports.create = function (state) { // Otherwise we check to see if the pong has also timed out, and if not we send a ping // and call this function again when the pong will have timed out. else if (silent < activityTimeout + pongTimeout) { - console.log('pinging', logName()); + if (state.debug) { console.log('pinging', logName()); } try { ws.ping(); } catch (err) { @@ -355,7 +441,7 @@ module.exports.create = function (state) { // Last case means the ping we sent before didn't get a response soon enough, so we // need to close the websocket connection. else { - console.log('home cloud', logName(), 'connection timed out'); + console.warn('home cloud', logName(), 'connection timed out'); ws.close(1013, 'connection timeout'); } } @@ -367,14 +453,14 @@ module.exports.create = function (state) { ws.on('pong', refreshTimeout); ws.on('message', function forwardMessage(chunk) { refreshTimeout(); - console.log('message from home cloud to tunneler to browser', chunk.byteLength); + if (state.debug) { console.log('[ws] device => client : demultiplexing message ', chunk.byteLength, 'bytes'); } //console.log(chunk.toString()); unpacker.fns.addChunk(chunk); }); function hangup() { clearTimeout(timeoutId); - console.log('home cloud', logName(), 'connection closing'); + console.log('[ws] device hangup', logName(), 'connection closing'); Object.keys(remotes).forEach(function (jwtoken) { removeToken(jwtoken); });