Merge branch 'master' into commercial
This commit is contained in:
		
						commit
						ab35fdc40e
					
				@ -120,7 +120,7 @@ module.exports.create = function (state) {
 | 
				
			|||||||
    serveAdmin(req, res, finalhandler(req, res));
 | 
					    serveAdmin(req, res, finalhandler(req, res));
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  state.httpTunnelServer = http.createServer(function (req, res) {
 | 
					  state.httpTunnelServer = http.createServer(function (req, res) {
 | 
				
			||||||
    //res.setHeader('connection', 'close');
 | 
					    res.setHeader('connection', 'close');
 | 
				
			||||||
    if (state.extensions.webadmin) {
 | 
					    if (state.extensions.webadmin) {
 | 
				
			||||||
      state.extensions.webadmin(state, req, res);
 | 
					      state.extensions.webadmin(state, req, res);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										391
									
								
								lib/relay.js
									
									
									
									
									
								
							
							
						
						
									
										391
									
								
								lib/relay.js
									
									
									
									
									
								
							@ -113,228 +113,227 @@ module.exports.create = function (state) {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function next() {
 | 
					    function logName() {
 | 
				
			||||||
 | 
					      var result = Object.keys(remotes).map(function (jwtoken) {
 | 
				
			||||||
 | 
					        return remotes[jwtoken].deviceId;
 | 
				
			||||||
 | 
					      }).join(';');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      function logName() {
 | 
					      return result || socketId;
 | 
				
			||||||
        var result = Object.keys(remotes).map(function (jwtoken) {
 | 
					    }
 | 
				
			||||||
          return remotes[jwtoken].deviceId;
 | 
					 | 
				
			||||||
        }).join(';');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return result || socketId;
 | 
					    function sendTunnelMsg(addr, data, service) {
 | 
				
			||||||
 | 
					      ws.send(Packer.pack(addr, data, service), {binary: true});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function getBrowserConn(cid) {
 | 
				
			||||||
 | 
					      var browserConn;
 | 
				
			||||||
 | 
					      Object.keys(remotes).some(function (jwtoken) {
 | 
				
			||||||
 | 
					        if (remotes[jwtoken].clients[cid]) {
 | 
				
			||||||
 | 
					          browserConn = remotes[jwtoken].clients[cid];
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return browserConn;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function closeBrowserConn(cid) {
 | 
				
			||||||
 | 
					      var remote;
 | 
				
			||||||
 | 
					      Object.keys(remotes).some(function (jwtoken) {
 | 
				
			||||||
 | 
					        if (remotes[jwtoken].clients[cid]) {
 | 
				
			||||||
 | 
					          remote = remotes[jwtoken];
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (!remote) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      function sendTunnelMsg(addr, data, service) {
 | 
					      PromiseA.resolve().then(function () {
 | 
				
			||||||
        ws.send(Packer.pack(addr, data, service), {binary: true});
 | 
					        var conn = remote.clients[cid];
 | 
				
			||||||
      }
 | 
					        conn.tunnelClosing = true;
 | 
				
			||||||
 | 
					        conn.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      function getBrowserConn(cid) {
 | 
					        // If no data is buffered for writing then we don't need to wait for it to drain.
 | 
				
			||||||
        var browserConn;
 | 
					        if (!conn.bufferSize) {
 | 
				
			||||||
        Object.keys(remotes).some(function (jwtoken) {
 | 
					          return timeoutPromise(500);
 | 
				
			||||||
          if (remotes[jwtoken].clients[cid]) {
 | 
					        }
 | 
				
			||||||
            browserConn = remotes[jwtoken].clients[cid];
 | 
					        // Otherwise we want the connection to be able to finish, but we also want to impose
 | 
				
			||||||
            return true;
 | 
					        // a time limit for it to drain, since it shouldn't have more than 1MB buffered.
 | 
				
			||||||
          }
 | 
					        return new PromiseA(function (resolve) {
 | 
				
			||||||
 | 
					          var timeoutId = setTimeout(resolve, 60*1000);
 | 
				
			||||||
 | 
					          conn.once('drain', function () {
 | 
				
			||||||
 | 
					            clearTimeout(timeoutId);
 | 
				
			||||||
 | 
					            setTimeout(resolve, 500);
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					      }).then(function () {
 | 
				
			||||||
 | 
					        if (remote.clients[cid]) {
 | 
				
			||||||
 | 
					          console.warn(cid, 'browser connection still present after calling `end`');
 | 
				
			||||||
 | 
					          remote.clients[cid].destroy();
 | 
				
			||||||
 | 
					          return timeoutPromise(500);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }).then(function () {
 | 
				
			||||||
 | 
					        if (remote.clients[cid]) {
 | 
				
			||||||
 | 
					          console.error(cid, 'browser connection still present after calling `destroy`');
 | 
				
			||||||
 | 
					          delete remote.clients[cid];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }).catch(function (err) {
 | 
				
			||||||
 | 
					        console.warn('failed to close browser connection', cid, err);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return browserConn;
 | 
					    function addToken(jwtoken) {
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      function closeBrowserConn(cid) {
 | 
					      function onAuth(token) {
 | 
				
			||||||
        var remote;
 | 
					        var err;
 | 
				
			||||||
        Object.keys(remotes).some(function (jwtoken) {
 | 
					        if (!token) {
 | 
				
			||||||
          if (remotes[jwtoken].clients[cid]) {
 | 
					          err = new Error("invalid access token");
 | 
				
			||||||
            remote = remotes[jwtoken];
 | 
					          err.code = "E_INVALID_TOKEN";
 | 
				
			||||||
            return true;
 | 
					          return state.Promise.reject(err);
 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        if (!remote) {
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PromiseA.resolve().then(function () {
 | 
					        if (!Array.isArray(token.domains)) {
 | 
				
			||||||
          var conn = remote.clients[cid];
 | 
					          if ('string' === typeof token.name) {
 | 
				
			||||||
          conn.tunnelClosing = true;
 | 
					            token.domains = [ token.name ];
 | 
				
			||||||
          conn.end();
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // If no data is buffered for writing then we don't need to wait for it to drain.
 | 
					        if (!Array.isArray(token.domains) || !token.domains.length) {
 | 
				
			||||||
          if (!conn.bufferSize) {
 | 
					          err = new Error("invalid domains array");
 | 
				
			||||||
            return timeoutPromise(500);
 | 
					          err.code = "E_INVALID_NAME";
 | 
				
			||||||
 | 
					          return state.Promise.reject(err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (token.domains.some(function (name) { return typeof name !== 'string'; })) {
 | 
				
			||||||
 | 
					          err = new Error("invalid domain name(s)");
 | 
				
			||||||
 | 
					          err.code = "E_INVALID_NAME";
 | 
				
			||||||
 | 
					          return state.Promise.reject(err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add the custom properties we need to manage this remote, then add it to all the relevant
 | 
				
			||||||
 | 
					        // domains and the list of all this websocket's remotes.
 | 
				
			||||||
 | 
					        token.deviceId = (token.device && (token.device.id || token.device.hostname)) || token.domains.join(',');
 | 
				
			||||||
 | 
					        token.ws = ws;
 | 
				
			||||||
 | 
					        token.upgradeReq = upgradeReq;
 | 
				
			||||||
 | 
					        token.clients = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        token.pausedConns = [];
 | 
				
			||||||
 | 
					        ws._socket.on('drain', function () {
 | 
				
			||||||
 | 
					          // the websocket library has it's own buffer apart from node's socket buffer, but that one
 | 
				
			||||||
 | 
					          // is much more difficult to watch, so we watch for the lower level buffer to drain and
 | 
				
			||||||
 | 
					          // then check to see if the upper level buffer is still too full to write to. Note that
 | 
				
			||||||
 | 
					          // the websocket library buffer has something to do with compression, so I'm not requiring
 | 
				
			||||||
 | 
					          // that to be 0 before we start up again.
 | 
				
			||||||
 | 
					          if (ws.bufferedAmount > 128*1024) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          // Otherwise we want the connection to be able to finish, but we also want to impose
 | 
					
 | 
				
			||||||
          // a time limit for it to drain, since it shouldn't have more than 1MB buffered.
 | 
					          token.pausedConns.forEach(function (conn) {
 | 
				
			||||||
          return new PromiseA(function (resolve) {
 | 
					            if (!conn.manualPause) {
 | 
				
			||||||
            var timeoutId = setTimeout(resolve, 60*1000);
 | 
					              // console.log('resuming', conn.tunnelCid, 'now that the web socket has caught up');
 | 
				
			||||||
            conn.once('drain', function () {
 | 
					              conn.resume();
 | 
				
			||||||
              clearTimeout(timeoutId);
 | 
					            }
 | 
				
			||||||
              setTimeout(resolve, 500);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
        }).then(function () {
 | 
					          token.pausedConns.length = 0;
 | 
				
			||||||
          if (remote.clients[cid]) {
 | 
					 | 
				
			||||||
            console.warn(cid, 'browser connection still present after calling `end`');
 | 
					 | 
				
			||||||
            remote.clients[cid].destroy();
 | 
					 | 
				
			||||||
            return timeoutPromise(500);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }).then(function () {
 | 
					 | 
				
			||||||
          if (remote.clients[cid]) {
 | 
					 | 
				
			||||||
            console.error(cid, 'browser connection still present after calling `destroy`');
 | 
					 | 
				
			||||||
            delete remote.clients[cid];
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }).catch(function (err) {
 | 
					 | 
				
			||||||
          console.warn('failed to close browser connection', cid, err);
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      function addToken(jwtoken) {
 | 
					        token.domains.forEach(function (domainname) {
 | 
				
			||||||
 | 
					          Devices.add(state.deviceLists, domainname, token);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        function onAuth(token) {
 | 
					        console.log('[DEBUG] got to firstToken check');
 | 
				
			||||||
          var err;
 | 
					 | 
				
			||||||
          if (!token) {
 | 
					 | 
				
			||||||
            err = new Error("invalid access token");
 | 
					 | 
				
			||||||
            err.code = "E_INVALID_TOKEN";
 | 
					 | 
				
			||||||
            return state.Promise.reject(err);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (!Array.isArray(token.domains)) {
 | 
					        if (!firstToken || firstToken === jwtoken) {
 | 
				
			||||||
            if ('string' === typeof token.name) {
 | 
					          firstToken = jwtoken;
 | 
				
			||||||
              token.domains = [ token.name ];
 | 
					          token.dynamicPorts = [];
 | 
				
			||||||
            }
 | 
					          token.dynamicNames = [];
 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (!Array.isArray(token.domains) || !token.domains.length) {
 | 
					          function onDynTcpReady() {
 | 
				
			||||||
            err = new Error("invalid domains array");
 | 
					            var serviceport = this.address().port;
 | 
				
			||||||
            err.code = "E_INVALID_NAME";
 | 
					            console.info('[DynTcpConn] Port', serviceport, 'now open for', token.deviceId);
 | 
				
			||||||
            return state.Promise.reject(err);
 | 
					            token.dynamicPorts.push(serviceport);
 | 
				
			||||||
          }
 | 
					            Devices.add(state.deviceLists, serviceport, token);
 | 
				
			||||||
          if (token.domains.some(function (name) { return typeof name !== 'string'; })) {
 | 
					            var hri = require('human-readable-ids').hri;
 | 
				
			||||||
            err = new Error("invalid domain name(s)");
 | 
					            var hrname = hri.random() + '.telebit.cloud';
 | 
				
			||||||
            err.code = "E_INVALID_NAME";
 | 
					            token.dynamicNames.push(hrname);
 | 
				
			||||||
            return state.Promise.reject(err);
 | 
					            // TODO restrict to authenticated device
 | 
				
			||||||
          }
 | 
					            // TODO pull servername from config
 | 
				
			||||||
 | 
					            // TODO remove hrname on disconnect
 | 
				
			||||||
          // Add the custom properties we need to manage this remote, then add it to all the relevant
 | 
					            Devices.add(state.deviceLists, hrname, token);
 | 
				
			||||||
          // domains and the list of all this websocket's remotes.
 | 
					            sendTunnelMsg(
 | 
				
			||||||
          token.deviceId = (token.device && (token.device.id || token.device.hostname)) || token.domains.join(',');
 | 
					              null
 | 
				
			||||||
          token.ws = ws;
 | 
					            , [ 2
 | 
				
			||||||
          token.upgradeReq = upgradeReq;
 | 
					              , 'grant'
 | 
				
			||||||
          token.clients = {};
 | 
					              , [ ['ssh+https', hrname, 443 ]
 | 
				
			||||||
 | 
					                , ['ssh', 'ssh.telebit.cloud', serviceport ]
 | 
				
			||||||
          token.pausedConns = [];
 | 
					                , ['tcp', 'tcp.telebit.cloud', serviceport]
 | 
				
			||||||
          ws._socket.on('drain', function () {
 | 
					                , ['https', hrname ]
 | 
				
			||||||
            // the websocket library has it's own buffer apart from node's socket buffer, but that one
 | 
					 | 
				
			||||||
            // is much more difficult to watch, so we watch for the lower level buffer to drain and
 | 
					 | 
				
			||||||
            // then check to see if the upper level buffer is still too full to write to. Note that
 | 
					 | 
				
			||||||
            // the websocket library buffer has something to do with compression, so I'm not requiring
 | 
					 | 
				
			||||||
            // that to be 0 before we start up again.
 | 
					 | 
				
			||||||
            if (ws.bufferedAmount > 128*1024) {
 | 
					 | 
				
			||||||
              return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            token.pausedConns.forEach(function (conn) {
 | 
					 | 
				
			||||||
              if (!conn.manualPause) {
 | 
					 | 
				
			||||||
                // console.log('resuming', conn.tunnelCid, 'now that the web socket has caught up');
 | 
					 | 
				
			||||||
                conn.resume();
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
            token.pausedConns.length = 0;
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          token.domains.forEach(function (domainname) {
 | 
					 | 
				
			||||||
            Devices.add(state.deviceLists, domainname, token);
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          console.log('[DEBUG] got to firstToken check');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if (!firstToken || firstToken === jwtoken) {
 | 
					 | 
				
			||||||
            firstToken = jwtoken;
 | 
					 | 
				
			||||||
            token.dynamicPorts = [];
 | 
					 | 
				
			||||||
            token.dynamicNames = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            function onDynTcpReady() {
 | 
					 | 
				
			||||||
              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);
 | 
					 | 
				
			||||||
              var hri = require('human-readable-ids').hri;
 | 
					 | 
				
			||||||
              var hrname = hri.random() + '.telebit.cloud';
 | 
					 | 
				
			||||||
              token.dynamicNames.push(hrname);
 | 
					 | 
				
			||||||
              // TODO restrict to authenticated device
 | 
					 | 
				
			||||||
              // TODO pull servername from config
 | 
					 | 
				
			||||||
              // TODO remove hrname on disconnect
 | 
					 | 
				
			||||||
              Devices.add(state.deviceLists, hrname, token);
 | 
					 | 
				
			||||||
              sendTunnelMsg(
 | 
					 | 
				
			||||||
                null
 | 
					 | 
				
			||||||
              , [ 2
 | 
					 | 
				
			||||||
                , 'grant'
 | 
					 | 
				
			||||||
                , [ ['ssh+https', hrname, 443 ]
 | 
					 | 
				
			||||||
                  , ['ssh', 'ssh.telebit.cloud', serviceport ]
 | 
					 | 
				
			||||||
                  , ['tcp', 'tcp.telebit.cloud', serviceport]
 | 
					 | 
				
			||||||
                  , ['https', hrname ]
 | 
					 | 
				
			||||||
                  ]
 | 
					 | 
				
			||||||
                ]
 | 
					                ]
 | 
				
			||||||
              , 'control'
 | 
					              ]
 | 
				
			||||||
              );
 | 
					            , 'control'
 | 
				
			||||||
            }
 | 
					            );
 | 
				
			||||||
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
              token.server = require('net').createServer(onDynTcpConn).listen(0, onDynTcpReady);
 | 
					 | 
				
			||||||
              token.server.on('error', function (e) {
 | 
					 | 
				
			||||||
                console.error("Server Error assigning a dynamic port to a new connection:", e);
 | 
					 | 
				
			||||||
              });
 | 
					 | 
				
			||||||
            } 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;
 | 
					          try {
 | 
				
			||||||
          console.info("[ws] authorized", socketId, "for", token.deviceId);
 | 
					            token.server = require('net').createServer(onDynTcpConn).listen(0, onDynTcpReady);
 | 
				
			||||||
          return null;
 | 
					            token.server.on('error', function (e) {
 | 
				
			||||||
 | 
					              console.error("Server Error assigning a dynamic port to a new connection:", e);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          } 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);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (remotes[jwtoken]) {
 | 
					        remotes[jwtoken] = token;
 | 
				
			||||||
          // return { message: "token sent multiple times", code: "E_TOKEN_REPEAT" };
 | 
					        console.info("[ws] authorized", socketId, "for", token.deviceId);
 | 
				
			||||||
          return state.Promise.resolve(null);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return state.authenticate({ auth: jwtoken }).then(onAuth);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      function removeToken(jwtoken) {
 | 
					 | 
				
			||||||
        var remote = remotes[jwtoken];
 | 
					 | 
				
			||||||
        if (!remote) {
 | 
					 | 
				
			||||||
          return { message: 'specified token not present', code: 'E_INVALID_TOKEN'};
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Prevent any more browser connections being sent to this remote, and any existing
 | 
					 | 
				
			||||||
        // connections from trying to send more data across the connection.
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
        if (remote.server) {
 | 
					 | 
				
			||||||
          remote.serverPort = remote.server.address().port;
 | 
					 | 
				
			||||||
          remote.server.close(function () {
 | 
					 | 
				
			||||||
            console.log("[DynTcpConn] closing server for ", remote.serverPort);
 | 
					 | 
				
			||||||
            remote.serverPort = null;
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
          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("[ws] removed token '" + remote.deviceId + "' from", socketId);
 | 
					 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (remotes[jwtoken]) {
 | 
				
			||||||
 | 
					        // return { message: "token sent multiple times", code: "E_TOKEN_REPEAT" };
 | 
				
			||||||
 | 
					        return state.Promise.resolve(null);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return state.authenticate({ auth: jwtoken }).then(onAuth);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function removeToken(jwtoken) {
 | 
				
			||||||
 | 
					      var remote = remotes[jwtoken];
 | 
				
			||||||
 | 
					      if (!remote) {
 | 
				
			||||||
 | 
					        return { message: 'specified token not present', code: 'E_INVALID_TOKEN'};
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Prevent any more browser connections being sent to this remote, and any existing
 | 
				
			||||||
 | 
					      // connections from trying to send more data across the connection.
 | 
				
			||||||
 | 
					      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;
 | 
				
			||||||
 | 
					      if (remote.server) {
 | 
				
			||||||
 | 
					        remote.serverPort = remote.server.address().port;
 | 
				
			||||||
 | 
					        remote.server.close(function () {
 | 
				
			||||||
 | 
					          console.log("[DynTcpConn] closing server for ", remote.serverPort);
 | 
				
			||||||
 | 
					          remote.serverPort = null;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        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("[ws] removed token '" + remote.deviceId + "' from", socketId);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function next() {
 | 
				
			||||||
      var commandHandlers = {
 | 
					      var commandHandlers = {
 | 
				
			||||||
        add_token: addToken
 | 
					        add_token: addToken
 | 
				
			||||||
      , auth: addToken
 | 
					      , auth: addToken
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user