From 000d36e76a2a487e3e3e4b54e696763d4293e2e1 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Mon, 26 Jun 2017 11:34:42 -0600 Subject: [PATCH] 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 }; };