From 94eddd2fccc78b5bffb27484987d0a0065fb74c9 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Wed, 4 Nov 2015 11:02:23 +0000 Subject: [PATCH] separate frontend from apis --- .gitignore | 3 ++ backends/.gitkeep | 0 certs/live/.gitkeep | 0 lib/vhost-server.js | 50 ----------------- sites-available/.gitkeep | 0 sites-enabled/.gitkeep | 0 worker.js | 112 +++++++++++++++++++++++++++++++++++++-- 7 files changed, 112 insertions(+), 53 deletions(-) create mode 100644 backends/.gitkeep create mode 100644 certs/live/.gitkeep create mode 100644 sites-available/.gitkeep create mode 100644 sites-enabled/.gitkeep diff --git a/.gitignore b/.gitignore index 4399326..9586ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ redirects.json +sites-available +sites-enabled dyndns-token.js vhosts +certs .*.sw* # Logs diff --git a/backends/.gitkeep b/backends/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/certs/live/.gitkeep b/certs/live/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/vhost-server.js b/lib/vhost-server.js index 596fe7d..8f04179 100644 --- a/lib/vhost-server.js +++ b/lib/vhost-server.js @@ -359,56 +359,6 @@ module.exports.create = function (securePort, vhostsdir) { }); } - /* - function hotloadApp(req, res, next) { - var forEachAsync = require('foreachasync').forEachAsync.create(PromiseA); - var vhost = (req.headers.host || '').split(':')[0]; - - // the matching domain didn't catch it - console.log('[log] vhost:', vhost); - if (domainMergeMap[vhost]) { - next(); - return; - } - - return forEachAsync(readNewVhosts(), loadDomainMounts).then(loadDomainVhosts).then(function () { - // no matching domain was added - if (!domainMergeMap[vhost]) { - next(); - return; - } - - return forEachAsync(domainMergeMap[vhost].apps, function (fn) { - return new PromiseA(function (resolve, reject) { - function next(err) { - if (err) { - reject(err); - } - resolve(); - } - - try { - fn(req, res, next); - } catch(e) { - reject(e); - } - }); - }).catch(function (e) { - next(e); - }); - }); - - /* - // TODO loop through mounts and see if any fit - domainMergeMap[vhost].mountsMap['/' + domaininfo.dirpathname] - if (!domainMergeMap[domaininfo.hostname]) { - // TODO reread directories - } - */ // - /* - } - */ - // TODO pre-cache these once the server has started? // return forEachAsync(rootDomains, loadCerts); diff --git a/sites-available/.gitkeep b/sites-available/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/sites-enabled/.gitkeep b/sites-enabled/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/worker.js b/worker.js index 04dbffa..46c5d91 100644 --- a/worker.js +++ b/worker.js @@ -21,12 +21,118 @@ function init(info) { workerApp = promiseServer.then(function (secureServer) { //secureServer = _secureServer; console.log("#" + id + " Listening on https://localhost:" + secureServer.address().port, '\n'); + var app = require('express')(); + var apiHandler; + var staticHandlers = {}; - return require('./lib/vhost-server').create(info.securePort, vhostsdir).create(secureServer).then(function (app) { - workerApp = app; + app.use('/', function (req, res, next) { + if (!/^\/api/.test(req.url)) { + next(); + return; + } - return app; + if (apiHandler) { + if (apiHandler.then) { + apiHandler.then(function (app) { + app(req, res, next); + }); + return; + } + + apiHandler(req, res, next); + return; + } + + apiHandler = require('./lib/vhost-server').create(info.securePort, vhostsdir).create(secureServer, app).then(function (app) { + apiHandler = app; + app(req, res, next); + }); }); + + app.use('/', function (req, res, next) { + if (/^\/api/.test(req.url)) { + next(); + return; + } + + // TODO block absolute urls for mounted apps? + // i.e. referer daplie.com/connect requests daplie.com/scripts/blah -> daplie.com/connect/scripts ? + var host = req.headers.host; + var invalidHost = /(\.\.)|[\\:\/\s\|>\*<]/; + + if (!host || 'string' !== typeof host) { + next(); + return; + } + host = host.toLowerCase(); + + if (staticHandlers[host]) { + if (staticHandlers[host].then) { + staticHandlers[host].then(function () { + staticHandlers[host](req, res, next); + }, function (err) { + res.send({ + error: { + message: err.message + , code: err.code + } + }); + }); + return; + } + + staticHandlers[host](req, res, next); + return; + } + + staticHandlers[host] = PromiseA.resolve().then(function () { + var fs = PromiseA.promisifyAll(require('fs')); + + // host can be spoofed by the user, so lets be safe + // don't allow .. or / or whitespace + // RFC says domains must start with a-zA-Z0-9 and follow with normal characters + // HOWEVER, there are now Unicode character domains + // punycode? + // + if (invalidHost.test(host)) { + return PromiseA.reject({ + message: "invalid Host header" + , code: "E_INVALID_HOST" + }); + } + + return fs.readdirAsync(path.join(__dirname, 'sites-enabled')).then(function (nodes) { + nodes.forEach(function (node) { + if ('function' === typeof staticHandlers[host] && !staticHandlers[host].then) { + return; + } + + if (-1 === node.indexOf('.') || invalidHost.test(node)) { + return; + } + + console.log('vhost static'); + console.log(node); + staticHandlers[node] = require('serve-static')(path.join(__dirname, 'sites-enabled', node)); + }); + + console.log('vhost static final'); + console.log(host); + console.log(staticHandlers[host]); + + if (staticHandlers[host]) { + staticHandlers[host](req, res, next); + } else { + next(); + } + + return staticHandlers[host]; + }); + }); + }); + + workerApp = app; + return app; }); return workerApp;