From aea4725fb0b304cc877a7881ab5c0bb72b628762 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Tue, 20 Jun 2017 11:45:00 -0600 Subject: [PATCH 1/8] simplified adding new com.daplie.goldilocks apis --- lib/app.js | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/lib/app.js b/lib/app.js index 235ca02..c2df411 100644 --- a/lib/app.js +++ b/lib/app.js @@ -13,11 +13,11 @@ module.exports = function (myDeps, conf, overrideHttp) { var serveIndexMap = {}; var content = conf.content; //var server; - var serveInit; + var goldilocksApis; var app; var request; - function createServeInit() { + function createGoldilocksApis() { var PromiseA = require('bluebird'); var OAUTH3 = require('../packages/assets/org.oauth3'); require('../packages/assets/org.oauth3/oauth3.domains.js'); @@ -198,31 +198,19 @@ module.exports = function (myDeps, conf, overrideHttp) { path.modules.forEach(mapMap); }); - return app.use('/', function (req, res, next) { - if (!req.headers.host) { - next(new Error('missing HTTP Host header')); - return; + return app.use('/api/com.daplie.goldilocks/:name', function (req, res, next) { + if (!goldilocksApis) { + goldilocksApis = createGoldilocksApis(); } - if (0 === req.url.indexOf('/api/com.daplie.goldilocks/')) { - if (!serveInit) { - serveInit = createServeInit(); - } + if (typeof goldilocksApis[req.params.name] === 'function') { + goldilocksApis[req.params.name](req, res); + } else { + next(); } - if ('/api/com.daplie.goldilocks/init' === req.url) { - serveInit.init(req, res); - return; - } - if ('/api/com.daplie.goldilocks/tunnel' === req.url) { - serveInit.tunnel(req, res); - return; - } - if ('/api/com.daplie.goldilocks/config' === req.url) { - serveInit.config(req, res); - return; - } - if ('/api/com.daplie.goldilocks/request' === req.url) { - serveInit.request(req, res); + }).use('/', function (req, res, next) { + if (!req.headers.host) { + next(new Error('missing HTTP Host header')); return; } From e901f1679ba0286c34737518113f5dcca6a89a09 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Tue, 20 Jun 2017 15:33:45 -0600 Subject: [PATCH 2/8] implemented check for hotel/ISP paywall --- packages/apis/com.daplie.goldilocks/index.js | 91 ++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/packages/apis/com.daplie.goldilocks/index.js b/packages/apis/com.daplie.goldilocks/index.js index eb3d88b..6f97d2e 100644 --- a/packages/apis/com.daplie.goldilocks/index.js +++ b/packages/apis/com.daplie.goldilocks/index.js @@ -63,6 +63,81 @@ module.exports.create = function (deps, conf) { }); } + function checkPaywall() { + var PromiseA = require('bluebird'); + var testDomains = [ + 'daplie.com' + , 'duckduckgo.com' + , 'google.com' + , 'amazon.com' + , 'facebook.com' + , 'msn.com' + , 'yahoo.com' + ]; + + // While this is not being developed behind a paywall the current idea is that + // a paywall will either manipulate DNS queries to point to the paywall gate, + // or redirect HTTP requests to the paywall gate. So we check for both and + // hope we can detect most hotel/ISP paywalls out there in the world. + + return PromiseA.resolve() + .then(function () { + var dns = PromiseA.promisifyAll(require('dns')); + var proms = testDomains.map(function (dom) { + return dns.resolve6Async(dom) + .catch(function (err) { + if (err.code === 'ENODATA') { + return dns.resolve4Async(dom); + } else { + return PromiseA.reject(err); + } + }) + .then(function (result) { + return result[0]; + }); + }); + + return PromiseA.all(proms).then(function (addrs) { + var unique = addrs.filter(function (value, ind, self) { + return value && self.indexOf(value) === ind; + }); + // It is possible some walls might have exceptions that leave some of the domains + // we test alone, so we might have more than one unique address even behind an + // active paywall. + return unique.length < addrs.length; + }); + }) + .then(function (paywall) { + if (paywall) { + return paywall; + } + var request = deps.request.defaults({ + followRedirect: false + , headers: { + connection: 'close' + } + }); + + var proms = testDomains.map(function (dom) { + return request('https://'+dom).then(function (resp) { + if (resp.statusCode >= 300 && resp.statusCode < 400) { + return resp.headers.location; + } else { + return 'https://'+dom; + } + }); + }); + + return PromiseA.all(proms).then(function (urls) { + var unique = urls.filter(function (value, ind, self) { + return value && self.indexOf(value) === ind; + }); + return unique.length < urls.length; + }); + }) + ; + } + return { init: function (req, res) { if (handleCors(req, res, 'POST')) { @@ -233,6 +308,22 @@ module.exports.create = function (deps, conf) { }); }); } + , paywall_check: function (req, res) { + if (handleCors(req, res, 'GET')) { + return; + } + isAuthorized(req, res, function () { + res.setHeader('Content-Type', 'application/json;'); + + checkPaywall().then(function (paywall) { + res.end(JSON.stringify({paywall: paywall})); + }, function (err) { + err.message = err.message || err.toString(); + res.statusCode = 500; + res.end(JSON.stringify({error: {message: err.message, code: err.code}})); + }); + }); + } , _api: api }; }; From 4a6d21f0b560adc451bbaa9789a3b820eab2111c Mon Sep 17 00:00:00 2001 From: tigerbot Date: Tue, 20 Jun 2017 16:29:07 -0600 Subject: [PATCH 3/8] moved where invalid method request are rejected --- packages/apis/com.daplie.goldilocks/index.js | 24 +++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/apis/com.daplie.goldilocks/index.js b/packages/apis/com.daplie.goldilocks/index.js index 6f97d2e..293fdaa 100644 --- a/packages/apis/com.daplie.goldilocks/index.js +++ b/packages/apis/com.daplie.goldilocks/index.js @@ -31,13 +31,21 @@ module.exports.create = function (deps, conf) { res.setHeader('Access-Control-Allow-Methods', methods.join(', ')); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); - if (req.method.toUpperCase() !== 'OPTIONS') { - return false; + if (req.method.toUpperCase() === 'OPTIONS') { + res.setHeader('Allow', methods.join(', ')); + res.end(); + return true; } - res.setHeader('Allow', methods.join(', ')); - res.end(); - return true; + if (methods.indexOf('*') >= 0) { + return false; + } + if (methods.indexOf(req.method.toUpperCase()) < 0) { + res.statusCode = 405; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ error: { message: 'method '+req.method+' not allowed', code: 'EBADMETHOD'}})); + return true; + } } function isAuthorized(req, res, fn) { @@ -143,12 +151,6 @@ module.exports.create = function (deps, conf) { if (handleCors(req, res, 'POST')) { return; } - if (req.method !== 'POST') { - res.statusCode = 405; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ error: { message: 'method '+req.method+' not allowed'}})); - return; - } jsonParser(req, res, function () { From 2b7000130949c4b9e3b99ec3f11e2d6f73d9e4d2 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Tue, 20 Jun 2017 18:16:11 -0600 Subject: [PATCH 4/8] added API route to start/stop a socks5 proxy server --- lib/socks5-server.js | 73 ++++++++++++++++++++ lib/worker.js | 1 + packages/apis/com.daplie.goldilocks/index.js | 26 +++++++ 3 files changed, 100 insertions(+) create mode 100644 lib/socks5-server.js diff --git a/lib/socks5-server.js b/lib/socks5-server.js new file mode 100644 index 0000000..c088a91 --- /dev/null +++ b/lib/socks5-server.js @@ -0,0 +1,73 @@ +'use strict'; + +module.exports.create = function () { + var PromiseA = require('bluebird'); + var enableDestroy = require('server-destroy'); + var server; + + function curState() { + if (!server) { + return PromiseA.resolve({running: false}); + } + return PromiseA.resolve({ + running: true + , port: server.address().port + }); + } + + function start() { + if (server) { + return curState(); + } + + server = require('socksv5').createServer(function (info, accept) { + accept(); + }); + + enableDestroy(server); + server.on('close', function () { + server = null; + }); + + server.useAuth(require('socksv5').auth.None()); + + return new PromiseA(function (resolve, reject) { + server.on('error', function (err) { + if (err.code === 'EADDRINUSE') { + server.listen(0); + } else { + server = null; + reject(err); + } + }); + server.listen(1080, function () { + resolve(curState()); + }); + }); + } + + function stop() { + if (!server) { + return curState(); + } + return new PromiseA(function (resolve, reject) { + var timeoutId = setTimeout(function () { + server.destroy(); + }, 1000); + server.close(function (err) { + clearTimeout(timeoutId); + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + } + + return { + isRunning: curState + , start: start + , stop: stop + }; +}; diff --git a/lib/worker.js b/lib/worker.js index 5fb9764..6826d12 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -38,6 +38,7 @@ function create(conf) { } } }; + deps.socks5 = require('./socks5-server').create(deps, conf); require('./goldilocks.js').create(deps, conf); process.removeListener('message', create); diff --git a/packages/apis/com.daplie.goldilocks/index.js b/packages/apis/com.daplie.goldilocks/index.js index 293fdaa..2091c6e 100644 --- a/packages/apis/com.daplie.goldilocks/index.js +++ b/packages/apis/com.daplie.goldilocks/index.js @@ -326,6 +326,32 @@ module.exports.create = function (deps, conf) { }); }); } + , socks5: function (req, res) { + if (handleCors(req, res, ['GET', 'POST', 'DELETE'])) { + return; + } + isAuthorized(req, res, function () { + var method = req.method.toUpperCase(); + var prom; + + if (method === 'POST') { + prom = deps.socks5.start(); + } else if (method === 'DELETE') { + prom = deps.socks5.stop(); + } else { + prom = deps.socks5.curState(); + } + + res.setHeader('Content-Type', 'application/json;'); + prom.then(function (result) { + res.end(JSON.stringify(result)); + }, function (err) { + err.message = err.message || err.toString(); + res.statusCode = 500; + res.end(JSON.stringify({error: {message: err.message, code: err.code}})); + }); + }); + } , _api: api }; }; From caa7b343d428482269cbf25536f0b3feafd0e24b Mon Sep 17 00:00:00 2001 From: tigerbot Date: Wed, 21 Jun 2017 17:00:46 -0600 Subject: [PATCH 5/8] improved extraction of properties from TLS sockets --- lib/modules/tls.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/modules/tls.js b/lib/modules/tls.js index ece8cea..57f9042 100644 --- a/lib/modules/tls.js +++ b/lib/modules/tls.js @@ -9,14 +9,18 @@ module.exports.create = function (deps, config, netHandler) { function extractSocketProp(socket, propName) { // remoteAddress, remotePort... ugh... https://github.com/nodejs/node/issues/8854 - var value = socket[propName] || socket['_' + propName]; + var altName = '_' + propName; + var value = socket[propName] || socket[altName]; try { value = value || socket._handle._parent.owner.stream[propName]; + value = value || socket._handle._parent.owner.stream[altName]; } catch (e) {} try { value = value || socket._handle._parentWrap[propName]; + value = value || socket._handle._parentWrap[altName]; value = value || socket._handle._parentWrap._handle.owner.stream[propName]; + value = value || socket._handle._parentWrap._handle.owner.stream[altName]; } catch (e) {} return value || ''; From 000d36e76a2a487e3e3e4b54e696763d4293e2e1 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Mon, 26 Jun 2017 11:34:42 -0600 Subject: [PATCH 6/8] exposed a loopback test route in the api --- bin/goldilocks.js | 2 +- lib/app.js | 29 ----------- lib/loopback.js | 53 ++++++++++++++++++++ lib/modules/http.js | 10 +++- lib/modules/tls.js | 13 +++-- lib/worker.js | 3 +- packages/apis/com.daplie.goldilocks/index.js | 19 +++++-- 7 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 lib/loopback.js diff --git a/bin/goldilocks.js b/bin/goldilocks.js index 68dabe6..ab680d0 100755 --- a/bin/goldilocks.js +++ b/bin/goldilocks.js @@ -251,7 +251,7 @@ function run(args) { var cachedConfig; cluster.on('message', function (worker, message) { - if (message.type !== 'com.daplie.goldilocks.config-change') { + if (message.type !== 'com.daplie.goldilocks/config') { return; } configStorage.save(message.changes) diff --git a/lib/app.js b/lib/app.js index c2df411..a858a87 100644 --- a/lib/app.js +++ b/lib/app.js @@ -86,35 +86,6 @@ module.exports = function (myDeps, conf, overrideHttp) { myDeps.storage = Object.assign({ owners: owners }, myDeps.storage); myDeps.recase = require('recase').create({}); myDeps.request = request; - myDeps.api = { - // TODO move loopback to oauth3.api('tunnel:loopback') - loopback: function (deps, session, opts2) { - var crypto = require('crypto'); - var token = crypto.randomBytes(16).toString('hex'); - var keyAuthorization = crypto.randomBytes(16).toString('hex'); - var nonce = crypto.randomBytes(16).toString('hex'); - - // TODO set token and keyAuthorization to /.well-known/cloud-challenge/:token - return request({ - method: 'POST' - , url: 'https://oauth3.org/api/org.oauth3.tunnel/loopback' - , json: { - address: opts2.address - , port: opts2.port - , token: token - , keyAuthorization: keyAuthorization - , servername: opts2.servername - , nonce: nonce - , scheme: 'https' - , iat: Date.now() - } - }).then(function (result) { - // TODO this will always fail at the moment - console.log('loopback result:'); - return result; - }); - } - }; return require('../packages/apis/com.daplie.goldilocks').create(myDeps, conf); } diff --git a/lib/loopback.js b/lib/loopback.js new file mode 100644 index 0000000..71e3cff --- /dev/null +++ b/lib/loopback.js @@ -0,0 +1,53 @@ +'use strict'; + +module.exports.create = function () { + var PromiseA = require('bluebird'); + var request = PromiseA.promisify(require('request')); + var pending = {}; + + function loopback(session, opts) { + 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(); + + return request({ + method: 'POST' + , url: 'https://'+host+'/api/org.oauth3.tunnel/loopback' + , 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)); + } + return result.body.success; + }); + } + + loopback.server = require('http').createServer(function (req, res) { + var parsed = require('url').parse(req.url); + var token = parsed.pathname.replace('/.well-known/cloud-challenge/', ''); + if (pending[token]) { + res.setHeader('Content-Type', 'text/plain'); + res.end(pending[token]); + } else { + res.statusCode = 404; + res.end(); + } + }); + + return loopback; +}; diff --git a/lib/modules/http.js b/lib/modules/http.js index 351937e..8f95f18 100644 --- a/lib/modules/http.js +++ b/lib/modules/http.js @@ -64,7 +64,7 @@ module.exports.create = function (deps, conf, greenlockMiddleware) { } function hostMatchesDomains(req, domains) { - var host = separatePort((req.headers || req).host).host; + var host = separatePort((req.headers || req).host).host.toLowerCase(); return domains.some(function (pattern) { return domainMatches(pattern, host); @@ -170,6 +170,13 @@ module.exports.create = function (deps, conf, greenlockMiddleware) { return emitConnection(acmeServer, conn, opts); } + function checkLoopback(conn, opts, headers) { + if (headers.url.indexOf('/.well-known/cloud-challenge/') !== 0) { + return false; + } + return emitConnection(deps.loopback.server, conn, opts); + } + var httpsRedirectServer; function checkHttps(conn, opts, headers) { if (conf.http.allowInsecure || conn.encrypted) { @@ -398,6 +405,7 @@ module.exports.create = function (deps, conf, greenlockMiddleware) { parseHeaders(conn, opts) .then(function (headers) { if (checkAcme(conn, opts, headers)) { return; } + if (checkLoopback(conn, opts, headers)) { return; } if (checkHttps(conn, opts, headers)) { return; } if (checkAdmin(conn, opts, headers)) { return; } diff --git a/lib/modules/tls.js b/lib/modules/tls.js index 57f9042..9563a0d 100644 --- a/lib/modules/tls.js +++ b/lib/modules/tls.js @@ -164,18 +164,21 @@ module.exports.create = function (deps, config, netHandler) { var secureContexts = {}; var terminatorOpts = require('localhost.daplie.me-certificates').merge({}); terminatorOpts.SNICallback = function (sni, cb) { + sni = sni.toLowerCase(); console.log("[tlsOptions.SNICallback] SNI: '" + sni + "'"); var tlsOptions; // Static Certs - if (/.*localhost.*\.daplie\.me/.test(sni.toLowerCase())) { - // TODO implement + if (/\.invalid$/.test(sni)) { + sni = 'localhost.daplie.me'; + } + if (/.*localhost.*\.daplie\.me/.test(sni)) { if (!secureContexts[sni]) { tlsOptions = localhostCerts.mergeTlsOptions(sni, {}); - } - if (tlsOptions) { - secureContexts[sni] = tls.createSecureContext(tlsOptions); + if (tlsOptions) { + secureContexts[sni] = tls.createSecureContext(tlsOptions); + } } if (secureContexts[sni]) { console.log('Got static secure context:', sni, secureContexts[sni]); diff --git a/lib/worker.js b/lib/worker.js index 6826d12..e9fad05 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -32,13 +32,14 @@ function create(conf) { config: { save: function (changes) { process.send({ - type: 'com.daplie.goldilocks.config-change' + type: 'com.daplie.goldilocks/config' , changes: changes }); } } }; deps.socks5 = require('./socks5-server').create(deps, conf); + deps.loopback = require('./loopback').create(deps, conf); require('./goldilocks.js').create(deps, conf); process.removeListener('message', create); diff --git a/packages/apis/com.daplie.goldilocks/index.js b/packages/apis/com.daplie.goldilocks/index.js index 2091c6e..9e10807 100644 --- a/packages/apis/com.daplie.goldilocks/index.js +++ b/packages/apis/com.daplie.goldilocks/index.js @@ -10,8 +10,6 @@ module.exports.create = function (deps, conf) { inflate: true, limit: '100kb', reviver: null, strict: true /* type, verify */ }); - var api = deps.api; - /* var owners; deps.storage.owners.on('set', function (_owners) { @@ -310,6 +308,22 @@ module.exports.create = function (deps, conf) { }); }); } + , loopback: function (req, res) { + if (handleCors(req, res, 'POST')) { + 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})); + }, function (err) { + res.end(JSON.stringify({error: {message: err.message, code: err.code}})) + }); + }); + }); + } , paywall_check: function (req, res) { if (handleCors(req, res, 'GET')) { return; @@ -352,6 +366,5 @@ module.exports.create = function (deps, conf) { }); }); } - , _api: api }; }; From f37730c97d97c3ff8aa045e3b87a9c5ffaaa4ea4 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Mon, 26 Jun 2017 18:12:00 -0600 Subject: [PATCH 7/8] 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')) { From a4aad3184a5416e3eb4a08bf11e6e70a6dc46a8e Mon Sep 17 00:00:00 2001 From: tigerbot Date: Tue, 27 Jun 2017 10:39:59 -0600 Subject: [PATCH 8/8] allow loopback to use providers that are not oauth3.org --- lib/loopback.js | 41 +++++++++----------- packages/apis/com.daplie.goldilocks/index.js | 13 ++++++- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/lib/loopback.js b/lib/loopback.js index d53492e..fd827cf 100644 --- a/lib/loopback.js +++ b/lib/loopback.js @@ -1,6 +1,6 @@ 'use strict'; -module.exports.create = function () { +module.exports.create = function (deps) { var PromiseA = require('bluebird'); var request = PromiseA.promisify(require('request')); var pending = {}; @@ -8,7 +8,7 @@ module.exports.create = function () { function checkPublicAddr(host) { return request({ method: 'GET' - , url: 'https://'+host+'/api/org.oauth3.tunnel/checkip' + , url: host+'/api/org.oauth3.tunnel/checkip' , json: true }).then(function (result) { if (!result.body) { @@ -18,7 +18,6 @@ module.exports.create = function () { 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; }); } @@ -39,7 +38,7 @@ module.exports.create = function () { return request({ method: 'POST' - , url: 'https://'+host+'/api/org.oauth3.tunnel/loopback' + , url: host+'/api/org.oauth3.tunnel/loopback' , json: opts }) .then(function (result) { @@ -60,26 +59,22 @@ module.exports.create = function () { }); } - 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]; + function loopback(provider) { + return deps.OAUTH3.discover(provider).then(function (directives) { + return checkPublicAddr(directives.api).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(directives.api, address, port); + })) + .then(function (values) { + console.log(pending); + var result = {error: null, address: address}; + ports.forEach(function (port, ind) { + result[port] = values[ind]; + }); + return result; }); - return result; }); }); } diff --git a/packages/apis/com.daplie.goldilocks/index.js b/packages/apis/com.daplie.goldilocks/index.js index 79732f3..1c08fbc 100644 --- a/packages/apis/com.daplie.goldilocks/index.js +++ b/packages/apis/com.daplie.goldilocks/index.js @@ -313,9 +313,18 @@ module.exports.create = function (deps, conf) { return; } isAuthorized(req, res, function () { + var prom; + var query = require('querystring').parse(require('url').parse(req.url).query); + if (query.provider) { + prom = deps.loopback(query.provider); + } else { + prom = deps.storage.owners.get(req.userId).then(function (session) { + return deps.loopback(session.token.aud); + }); + } + res.setHeader('Content-Type', 'application/json'); - deps.loopback() - .then(function (result) { + prom.then(function (result) { res.end(JSON.stringify(result)); }, function (err) { res.end(JSON.stringify({error: {message: err.message, code: err.code}}));