lots and lots of failover
This commit is contained in:
		
							parent
							
								
									9bb093fd4f
								
							
						
					
					
						commit
						5b1191f1be
					
				
							
								
								
									
										141
									
								
								lib/index.js
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								lib/index.js
									
									
									
									
									
								
							@ -10,44 +10,131 @@ module.exports.create = function (args) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var servers = loopback.create(args);
 | 
			
		||||
  var promises = [];
 | 
			
		||||
  //var promises = [];
 | 
			
		||||
 | 
			
		||||
  if (args.debug) {
 | 
			
		||||
    console.log('[HP] create servers');
 | 
			
		||||
    console.log(servers);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (-1 !== args.protocols.indexOf('none')) {
 | 
			
		||||
    promises.push(PromiseA.any(args.ipifyUrls.map(function (ipifyUrl) {
 | 
			
		||||
  function getExternalIps() {
 | 
			
		||||
    return PromiseA.any(args.ipifyUrls.map(function (ipifyUrl) {
 | 
			
		||||
      var getIp = require('./external-ip');
 | 
			
		||||
 | 
			
		||||
      return getIp({ hostname: ipifyUrl, debug: args.debug });
 | 
			
		||||
    })).then(function (ips) {
 | 
			
		||||
      // TODO how (if at all) should ip.address === ip.localAddress be treated differently?
 | 
			
		||||
      // TODO check local firewall?
 | 
			
		||||
      // TODO would it ever make sense for a public ip to respond to upnp?
 | 
			
		||||
      var requestAsync = require('./request');
 | 
			
		||||
 | 
			
		||||
      return PromiseA.all(ips.map(function (ip) {
 | 
			
		||||
        return requestAsync({
 | 
			
		||||
          secure: false
 | 
			
		||||
        , hostname: ip.address
 | 
			
		||||
        , path: '/api/com.daplie.loopback'
 | 
			
		||||
        , servername: 'daplie.invalid'
 | 
			
		||||
        , localAddress: ip.localAddress
 | 
			
		||||
        , port: 65080
 | 
			
		||||
        , headers: {
 | 
			
		||||
            Host: 'daplie.invalid'
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }));
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return PromiseA.all(promises).then(function (results) {
 | 
			
		||||
    if (args.debug) {
 | 
			
		||||
      console.log('[HP] all done');
 | 
			
		||||
      console.log(results);
 | 
			
		||||
    }
 | 
			
		||||
  function testOpenPort(ip, portInfo) {
 | 
			
		||||
    var requestAsync = require('./request');
 | 
			
		||||
 | 
			
		||||
    return requestAsync({
 | 
			
		||||
      secure: portInfo.secure
 | 
			
		||||
    , rejectUnauthorized: false
 | 
			
		||||
    , hostname: ip.address
 | 
			
		||||
      // '/.well-known/com.daplie.loopback/'
 | 
			
		||||
    , path: args.loopbackPrefix + args.key
 | 
			
		||||
      // 'loopback.daplie.invalid'
 | 
			
		||||
    , servername: args.loopbackHostname
 | 
			
		||||
    , localAddress: ip.localAddress
 | 
			
		||||
    , port: portInfo.external || portInfo.internal
 | 
			
		||||
    , headers: {
 | 
			
		||||
        // 'loopback.daplie.invalid'
 | 
			
		||||
        Host: args.loopbackHostname
 | 
			
		||||
      }
 | 
			
		||||
    }).then(function (val) {
 | 
			
		||||
      if (val !== args.value) {
 | 
			
		||||
        return PromiseA.reject(new Error("invalid loopback token value"));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ip.validated = true;
 | 
			
		||||
 | 
			
		||||
      ip.ports.push(portInfo);
 | 
			
		||||
      portInfo.ips.push(ip);
 | 
			
		||||
 | 
			
		||||
      return portInfo;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function testPort(opts) {
 | 
			
		||||
    // TODO should ip.address === ip.localAddress be treated differently?
 | 
			
		||||
    // TODO check local firewall?
 | 
			
		||||
    // TODO would it ever make sense for a public ip to respond to upnp?
 | 
			
		||||
 | 
			
		||||
    // TODO should we pass any or require all?
 | 
			
		||||
    opts.portInfo.ips = [];
 | 
			
		||||
 | 
			
		||||
    return PromiseA.any(opts.ips.map(function (ip) {
 | 
			
		||||
      ip.ports = [];
 | 
			
		||||
 | 
			
		||||
      if (!opts.pretest) {
 | 
			
		||||
        //console.log('[HP pretest]', opts.pretest);
 | 
			
		||||
        return ip;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return testOpenPort(ip, opts.portInfo);
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return getExternalIps().then(function (ips) {
 | 
			
		||||
    var pretest = (-1 !== args.protocols.indexOf('none'));
 | 
			
		||||
    var portInfos = args.plainPorts.concat(args.tlsPorts.map(function (info) {
 | 
			
		||||
      info.secure = true;
 | 
			
		||||
      return info;
 | 
			
		||||
    }));
 | 
			
		||||
 | 
			
		||||
    return PromiseA.all(portInfos.map(function (info) {
 | 
			
		||||
      // TODO clone-merge args
 | 
			
		||||
      return testPort({
 | 
			
		||||
        portInfo: info
 | 
			
		||||
      , ips: ips
 | 
			
		||||
      , pretest: pretest
 | 
			
		||||
      });
 | 
			
		||||
    })).then(function (portInfos) {
 | 
			
		||||
      if (args.debug) {
 | 
			
		||||
        console.log('[HP] all done on the first try');
 | 
			
		||||
        console.log(portInfos);
 | 
			
		||||
      }
 | 
			
		||||
      return portInfos;
 | 
			
		||||
    }, function () {
 | 
			
		||||
      // at least one port could not be mapped
 | 
			
		||||
      var mappers = [];
 | 
			
		||||
 | 
			
		||||
      if (-1 !== args.protocols.indexOf('upnp')
 | 
			
		||||
        ||  -1 !== args.protocols.indexOf('ssdp')
 | 
			
		||||
      ) {
 | 
			
		||||
        mappers.push(require('./upnp'));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (-1 !== args.protocols.indexOf('pmp')
 | 
			
		||||
        || -1 !== args.protocols.indexOf('nat-pmp')
 | 
			
		||||
      ) {
 | 
			
		||||
        mappers.push(require('./pmp'));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return PromiseA.all(portInfos.map(function (portInfo) {
 | 
			
		||||
        return PromiseA.any(mappers.map(function (fn) {
 | 
			
		||||
          var p = fn(args, ips, portInfo);
 | 
			
		||||
 | 
			
		||||
          if (portInfos.ips.length) {
 | 
			
		||||
            return portInfos;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          return p;
 | 
			
		||||
        }));
 | 
			
		||||
      })).then(function () {
 | 
			
		||||
        if (args.debug) {
 | 
			
		||||
          console.log("[HP] all ports successfully mapped");
 | 
			
		||||
          console.log(portInfos);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return portInfos;
 | 
			
		||||
      });
 | 
			
		||||
    }).then(function () {
 | 
			
		||||
      return portInfos;
 | 
			
		||||
    }, function () {
 | 
			
		||||
      console.warn('[HP] RVPN not implemented');
 | 
			
		||||
      return portInfos;
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -56,5 +56,8 @@ module.exports.create = function (opts) {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  results.key = opts.key;
 | 
			
		||||
  results.value = opts.value;
 | 
			
		||||
 | 
			
		||||
  return results;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -6,14 +6,20 @@ function middleware(opts) {
 | 
			
		||||
  var key = opts.key;
 | 
			
		||||
  var val = opts.value;
 | 
			
		||||
  var vhost = opts.vhost;
 | 
			
		||||
  var pathnamePrefix = opts.prefix || '/.well-known/com.daplie.loopback/';
 | 
			
		||||
  var defaultHostname = 'loopback.daplie.invalid';
 | 
			
		||||
  var pathnamePrefix = opts.loopbackPrefix;
 | 
			
		||||
  var defaultHostname = opts.loopbackHostname;
 | 
			
		||||
 | 
			
		||||
  if (!defaultHostname) {
 | 
			
		||||
    defaultHostname = opts.loopbackHostname = 'loopback.daplie.invalid';
 | 
			
		||||
  }
 | 
			
		||||
  if (!pathnamePrefix) {
 | 
			
		||||
    pathnamePrefix = opts.loopbackPrefix = '/.well-known/com.daplie.loopback/';
 | 
			
		||||
  }
 | 
			
		||||
  if (!key) {
 | 
			
		||||
    opts.key = require('crypto').randomBytes(8).toString('hex');
 | 
			
		||||
    key = opts.key = require('crypto').randomBytes(8).toString('hex');
 | 
			
		||||
  }
 | 
			
		||||
  if (!val) {
 | 
			
		||||
    opts.value = require('crypto').randomBytes(16).toString('hex');
 | 
			
		||||
    val = opts.value = require('crypto').randomBytes(16).toString('hex');
 | 
			
		||||
  }
 | 
			
		||||
  if (!vhost && vhost !== false) {
 | 
			
		||||
    vhost = defaultHostname;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user