From f37730c97d97c3ff8aa045e3b87a9c5ffaaa4ea4 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Mon, 26 Jun 2017 18:12:00 -0600 Subject: [PATCH] changed loopback endpoint to check all ports --- lib/goldilocks.js | 4 +- lib/loopback.js | 79 ++++++++++++++++---- lib/servers.js | 44 +++++------ packages/apis/com.daplie.goldilocks/index.js | 12 ++- 4 files changed, 89 insertions(+), 50 deletions(-) diff --git a/lib/goldilocks.js b/lib/goldilocks.js index ef3dc85..fde77a3 100644 --- a/lib/goldilocks.js +++ b/lib/goldilocks.js @@ -186,11 +186,11 @@ module.exports.create = function (deps, config) { return; } if (Array.isArray(bindList)) { - bindList.forEach(function (port) { + bindList.filter(Number).forEach(function (port) { tcpPortMap[port] = true; }); } - else { + else if (Number(bindList)) { tcpPortMap[bindList] = true; } } diff --git a/lib/loopback.js b/lib/loopback.js index 71e3cff..d53492e 100644 --- a/lib/loopback.js +++ b/lib/loopback.js @@ -5,23 +5,37 @@ module.exports.create = function () { var request = PromiseA.promisify(require('request')); var pending = {}; - function loopback(session, opts) { + function checkPublicAddr(host) { + return request({ + method: 'GET' + , url: 'https://'+host+'/api/org.oauth3.tunnel/checkip' + , json: true + }).then(function (result) { + if (!result.body) { + return PromiseA.reject(new Error('No response body in request for public address')); + } + if (result.body.error) { + var err = new Error(result.body.error.message); + return PromiseA.reject(Object.assign(err, result.body.error)); + } + console.log(result.body, result.body.address); + return result.body.address; + }); + } + + function checkSinglePort(host, address, port) { var crypto = require('crypto'); var token = crypto.randomBytes(8).toString('hex'); var keyAuth = crypto.randomBytes(32).toString('hex'); pending[token] = keyAuth; - var host; - if (!opts) { - opts = session; - host = 'api.oauth3.org'; - } else { - host = 'api.' + ((session.token || {}).aud || 'oauth3.org'); - } - - opts.token = token; - opts.keyAuthorization = keyAuth; - opts.iat = Date.now(); + var opts = { + address: address + , port: port + , token: token + , keyAuthorization: keyAuth + , iat: Date.now() + }; return request({ method: 'POST' @@ -29,11 +43,44 @@ module.exports.create = function () { , json: opts }) .then(function (result) { - if (result.body.error) { - var err = new Error(result.body.error.message); - return PromiseA.reject(Object.assign(err, result.body.error)); + delete pending[token]; + if (!result.body) { + return PromiseA.reject(new Error('No response body in loopback request for port '+port)); } - return result.body.success; + // If the loopback requests don't go to us then there are all kinds of ways it could + // error, but none of them really provide much extra information so we don't do + // anything that will break the PromiseA.all out and mask the other results. + if (result.body.error) { + console.log('error on remote side of port '+port+' loopback', result.body.error); + } + return !!result.body.success; + }, function (err) { + delete pending[token]; + throw err; + }); + } + + function loopback(session) { + var host; + if (!session) { + host = 'api.oauth3.org'; + } else { + host = 'api.' + ((session.token || {}).aud || 'oauth3.org'); + } + + return checkPublicAddr(host).then(function (address) { + console.log('checking to see if', address, 'gets back to us'); + var ports = require('./servers').listeners.tcp.list(); + return PromiseA.all(ports.map(function (port) { + return checkSinglePort(host, address, port); + })) + .then(function (values) { + var result = {error: null, address: address}; + ports.forEach(function (port, ind) { + result[port] = values[ind]; + }); + return result; + }); }); } diff --git a/lib/servers.js b/lib/servers.js index 0338172..5d4aa05 100644 --- a/lib/servers.js +++ b/lib/servers.js @@ -46,20 +46,18 @@ module.exports.addTcpListener = function (port, handler) { conn.__proto = 'tcp'; stat.handler(conn); }); - server.on('error', function (e) { + server.on('close', function () { + console.log('TCP server on port %d closed', port); delete serversMap[port]; - + }); + server.on('error', function (e) { if (!resolved) { reject(e); - return; - } - - if (handler.onError) { + } else if (handler.onError) { handler.onError(e); - return; + } else { + throw e; } - - throw e; }); server.listen(port, function () { @@ -75,29 +73,20 @@ module.exports.closeTcpListener = function (port) { resolve(); return; } - stat.server.on('close', function () { - // once the clients close too - delete serversMap[port]; - if (stat._closing) { - stat._closing(); // resolve - stat._closing = null; - } - stat = null; - }); - stat._closing = resolve; + stat.server.once('close', resolve); stat.server.close(); }); }; module.exports.destroyTcpListener = function (port) { var stat = serversMap[port]; - delete serversMap[port]; - stat.server.destroy(); - if (stat._closing) { - stat._closing(); - stat._closing = null; + if (stat) { + stat.server.destroy(); } - stat = null; }; +module.exports.listTcpListeners = function () { + return Object.keys(serversMap).map(Number).filter(Boolean); +}; + module.exports.addUdpListener = function (port, handler) { return new PromiseA(function (resolve, reject) { @@ -162,6 +151,9 @@ module.exports.closeUdpListener = function (port) { stat.server.close(); }); }; +module.exports.listUdpListeners = function () { + return Object.keys(dgramMap).map(Number).filter(Boolean); +}; module.exports.listeners = { @@ -169,9 +161,11 @@ module.exports.listeners = { add: module.exports.addTcpListener , close: module.exports.closeTcpListener , destroy: module.exports.destroyTcpListener + , list: module.exports.listTcpListeners } , udp: { add: module.exports.addUdpListener , close: module.exports.closeUdpListener + , list: module.exports.listUdpListeners } }; diff --git a/packages/apis/com.daplie.goldilocks/index.js b/packages/apis/com.daplie.goldilocks/index.js index 9e10807..79732f3 100644 --- a/packages/apis/com.daplie.goldilocks/index.js +++ b/packages/apis/com.daplie.goldilocks/index.js @@ -309,20 +309,18 @@ module.exports.create = function (deps, conf) { }); } , loopback: function (req, res) { - if (handleCors(req, res, 'POST')) { + if (handleCors(req, res, 'GET')) { return; } isAuthorized(req, res, function () { - jsonParser(req, res, function () { res.setHeader('Content-Type', 'application/json'); - deps.loopback(req.body) - .then(function (success) { - res.end(JSON.stringify({error: null, success: success})); + deps.loopback() + .then(function (result) { + res.end(JSON.stringify(result)); }, function (err) { - res.end(JSON.stringify({error: {message: err.message, code: err.code}})) + res.end(JSON.stringify({error: {message: err.message, code: err.code}})); }); }); - }); } , paywall_check: function (req, res) { if (handleCors(req, res, 'GET')) {