lots and lots of failover

This commit is contained in:
AJ ONeal 2015-12-30 06:35:21 +00:00
parent 9bb093fd4f
commit 5b1191f1be
3 changed files with 127 additions and 31 deletions

View File

@ -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;
});
});
};

View File

@ -56,5 +56,8 @@ module.exports.create = function (opts) {
});
});
results.key = opts.key;
results.value = opts.value;
return results;
};

View File

@ -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;