406 lines
12 KiB
JavaScript
406 lines
12 KiB
JavaScript
'use strict';
|
|
|
|
module.exports = function (myDeps, conf, overrideHttp) {
|
|
var express = require('express');
|
|
//var finalhandler = require('finalhandler');
|
|
var serveStatic = require('serve-static');
|
|
var serveIndex = require('serve-index');
|
|
//var assetServer = serveStatic(opts.assetsPath);
|
|
var path = require('path');
|
|
//var wellKnownServer = serveStatic(path.join(opts.assetsPath, 'well-known'));
|
|
|
|
var serveStaticMap = {};
|
|
var serveIndexMap = {};
|
|
var content = conf.content;
|
|
//var server;
|
|
var goldilocksApis;
|
|
var app;
|
|
var request;
|
|
|
|
function createGoldilocksApis() {
|
|
var PromiseA = require('bluebird');
|
|
var OAUTH3 = require('../packages/assets/org.oauth3');
|
|
require('../packages/assets/org.oauth3/oauth3.domains.js');
|
|
require('../packages/assets/org.oauth3/oauth3.dns.js');
|
|
require('../packages/assets/org.oauth3/oauth3.tunnel.js');
|
|
OAUTH3._hooks = require('../packages/assets/org.oauth3/oauth3.node.storage.js');
|
|
var fs = PromiseA.promisifyAll(require('fs'));
|
|
var ownersPath = path.join(__dirname, '..', 'var', 'owners.json');
|
|
|
|
var scmp = require('scmp');
|
|
request = request || PromiseA.promisify(require('request'));
|
|
|
|
var owners = {
|
|
all: function () {
|
|
var owners;
|
|
try {
|
|
owners = require(ownersPath);
|
|
} catch(e) {
|
|
owners = {};
|
|
}
|
|
|
|
return PromiseA.resolve(Object.keys(owners).map(function (key) {
|
|
var owner = owners[key];
|
|
owner.id = key;
|
|
return owner;
|
|
}));
|
|
}
|
|
, get: function (id) {
|
|
var me = this;
|
|
|
|
return me.all().then(function (owners) {
|
|
return owners.filter(function (owner) {
|
|
return scmp(id, owner.id);
|
|
})[0];
|
|
});
|
|
}
|
|
, exists: function (id) {
|
|
var me = this;
|
|
|
|
return me.get(id).then(function (owner) {
|
|
return !!owner;
|
|
});
|
|
}
|
|
, set: function (id, obj) {
|
|
var owners;
|
|
try {
|
|
owners = require(ownersPath);
|
|
} catch(e) {
|
|
owners = {};
|
|
}
|
|
obj.id = id;
|
|
owners[id] = obj;
|
|
|
|
return fs.mkdirAsync(path.dirname(ownersPath)).catch(function (err) {
|
|
if (err.code !== 'EEXIST') {
|
|
console.error('failed to mkdir', path.dirname(ownersPath), err.toString());
|
|
}
|
|
}).then(function () {
|
|
return fs.writeFileAsync(ownersPath, JSON.stringify(owners), 'utf8');
|
|
});
|
|
}
|
|
};
|
|
|
|
myDeps.PromiseA = PromiseA;
|
|
myDeps.OAUTH3 = OAUTH3;
|
|
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);
|
|
}
|
|
|
|
app = express();
|
|
|
|
var Sites = {
|
|
add: function (sitesMap, site) {
|
|
if (!sitesMap[site.$id]) {
|
|
sitesMap[site.$id] = site;
|
|
}
|
|
|
|
if (!site.paths) {
|
|
site.paths = [];
|
|
}
|
|
if (!site.paths._map) {
|
|
site.paths._map = {};
|
|
}
|
|
site.paths.forEach(function (path) {
|
|
|
|
site.paths._map[path.$id] = path;
|
|
|
|
if (!path.modules) {
|
|
path.modules = [];
|
|
}
|
|
if (!path.modules._map) {
|
|
path.modules._map = {};
|
|
}
|
|
path.modules.forEach(function (module) {
|
|
|
|
path.modules._map[module.$id] = module;
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
var opts = overrideHttp || conf.http;
|
|
if (!opts.defaults) {
|
|
opts.defaults = {};
|
|
}
|
|
if (!opts.global) {
|
|
opts.global = {};
|
|
}
|
|
if (!opts.sites) {
|
|
opts.sites = [];
|
|
}
|
|
opts.sites._map = {};
|
|
opts.sites.forEach(function (site) {
|
|
|
|
Sites.add(opts.sites._map, site);
|
|
});
|
|
|
|
function mapMap(el, i, arr) {
|
|
arr._map[el.$id] = el;
|
|
}
|
|
opts.global.modules._map = {};
|
|
opts.global.modules.forEach(mapMap);
|
|
opts.global.paths._map = {};
|
|
opts.global.paths.forEach(function (path, i, arr) {
|
|
mapMap(path, i, arr);
|
|
//opts.global.paths._map[path.$id] = path;
|
|
path.modules._map = {};
|
|
path.modules.forEach(mapMap);
|
|
});
|
|
opts.sites.forEach(function (site) {
|
|
site.paths._map = {};
|
|
site.paths.forEach(function (path, i, arr) {
|
|
mapMap(path, i, arr);
|
|
//site.paths._map[path.$id] = path;
|
|
path.modules._map = {};
|
|
path.modules.forEach(mapMap);
|
|
});
|
|
});
|
|
opts.defaults.modules._map = {};
|
|
opts.defaults.modules.forEach(mapMap);
|
|
opts.defaults.paths._map = {};
|
|
opts.defaults.paths.forEach(function (path, i, arr) {
|
|
mapMap(path, i, arr);
|
|
//opts.global.paths._map[path.$id] = path;
|
|
path.modules._map = {};
|
|
path.modules.forEach(mapMap);
|
|
});
|
|
|
|
return app.use('/api/com.daplie.goldilocks/:name', function (req, res, next) {
|
|
if (!goldilocksApis) {
|
|
goldilocksApis = createGoldilocksApis();
|
|
}
|
|
|
|
if (typeof goldilocksApis[req.params.name] === 'function') {
|
|
goldilocksApis[req.params.name](req, res);
|
|
} else {
|
|
next();
|
|
}
|
|
}).use('/', function (req, res, next) {
|
|
if (!req.headers.host) {
|
|
next(new Error('missing HTTP Host header'));
|
|
return;
|
|
}
|
|
|
|
if (content && '/' === req.url) {
|
|
// res.setHeader('Content-Type', 'application/octet-stream');
|
|
res.end(content);
|
|
return;
|
|
}
|
|
|
|
//var done = finalhandler(req, res);
|
|
var host = req.headers.host;
|
|
var hostname = (host||'').split(':')[0].toLowerCase();
|
|
|
|
console.log('opts.global', opts.global);
|
|
var sites = [ opts.global || null, opts.sites._map[hostname] || null, opts.defaults || null ];
|
|
var loadables = {
|
|
serve: function (config, hostname, pathname, req, res, next) {
|
|
var originalUrl = req.url;
|
|
var dirpaths = config.paths.slice(0);
|
|
|
|
function nextServe() {
|
|
var dirname = dirpaths.pop();
|
|
if (!dirname) {
|
|
req.url = originalUrl;
|
|
next();
|
|
return;
|
|
}
|
|
|
|
console.log('[serve]', req.url, hostname, pathname, dirname);
|
|
dirname = path.resolve(conf.cwd, dirname.replace(/:hostname/, hostname));
|
|
if (!serveStaticMap[dirname]) {
|
|
serveStaticMap[dirname] = serveStatic(dirname);
|
|
}
|
|
|
|
serveStaticMap[dirname](req, res, nextServe);
|
|
}
|
|
|
|
req.url = req.url.substr(pathname.length - 1);
|
|
nextServe();
|
|
}
|
|
, indexes: function (config, hostname, pathname, req, res, next) {
|
|
var originalUrl = req.url;
|
|
var dirpaths = config.paths.slice(0);
|
|
|
|
function nextIndex() {
|
|
var dirname = dirpaths.pop();
|
|
if (!dirname) {
|
|
req.url = originalUrl;
|
|
next();
|
|
return;
|
|
}
|
|
|
|
console.log('[indexes]', req.url, hostname, pathname, dirname);
|
|
dirname = path.resolve(conf.cwd, dirname.replace(/:hostname/, hostname));
|
|
if (!serveStaticMap[dirname]) {
|
|
serveIndexMap[dirname] = serveIndex(dirname);
|
|
}
|
|
serveIndexMap[dirname](req, res, nextIndex);
|
|
}
|
|
|
|
req.url = req.url.substr(pathname.length - 1);
|
|
nextIndex();
|
|
}
|
|
, app: function (config, hostname, pathname, req, res, next) {
|
|
//var appfile = path.resolve(/*process.cwd(), */config.path.replace(/:hostname/, hostname));
|
|
var appfile = config.path.replace(/:hostname/, hostname);
|
|
try {
|
|
var app = require(appfile);
|
|
app(req, res, next);
|
|
} catch (err) {
|
|
next();
|
|
}
|
|
}
|
|
};
|
|
|
|
function runModule(module, hostname, pathname, modulename, req, res, next) {
|
|
if (!loadables[modulename]) {
|
|
next(new Error("no module '" + modulename + "' found"));
|
|
return;
|
|
}
|
|
loadables[modulename](module, hostname, pathname, req, res, next);
|
|
}
|
|
|
|
function iterModules(modules, hostname, pathname, req, res, next) {
|
|
console.log('modules');
|
|
console.log(modules);
|
|
var modulenames = Object.keys(modules._map);
|
|
|
|
function nextModule() {
|
|
var modulename = modulenames.pop();
|
|
if (!modulename) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
console.log('modules', modules);
|
|
runModule(modules._map[modulename], hostname, pathname, modulename, req, res, nextModule);
|
|
}
|
|
|
|
nextModule();
|
|
}
|
|
|
|
function iterPaths(site, hostname, req, res, next) {
|
|
console.log('site', hostname);
|
|
console.log(site);
|
|
var pathnames = Object.keys(site.paths._map);
|
|
console.log('pathnames', pathnames);
|
|
pathnames = pathnames.filter(function (pathname) {
|
|
// TODO ensure that pathname has trailing /
|
|
return (0 === req.url.indexOf(pathname));
|
|
//return req.url.match(pathname);
|
|
});
|
|
pathnames.sort(function (a, b) {
|
|
return b.length - a.length;
|
|
});
|
|
console.log('pathnames', pathnames);
|
|
|
|
function nextPath() {
|
|
var pathname = pathnames.shift();
|
|
if (!pathname) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
console.log('iterPaths', hostname, pathname, req.url);
|
|
iterModules(site.paths._map[pathname].modules, hostname, pathname, req, res, nextPath);
|
|
}
|
|
|
|
nextPath();
|
|
}
|
|
|
|
function nextSite() {
|
|
console.log('hostname', hostname, sites);
|
|
var site;
|
|
if (!sites.length) {
|
|
next(); // 404
|
|
return;
|
|
}
|
|
site = sites.shift();
|
|
if (!site) {
|
|
nextSite();
|
|
return;
|
|
}
|
|
iterPaths(site, hostname, req, res, nextSite);
|
|
}
|
|
|
|
nextSite();
|
|
|
|
/*
|
|
function serveStaticly(server) {
|
|
function serveTheStatic() {
|
|
server.serve(req, res, function (err) {
|
|
if (err) { return done(err); }
|
|
server.index(req, res, function (err) {
|
|
if (err) { return done(err); }
|
|
req.url = req.url.replace(/\/assets/, '');
|
|
assetServer(req, res, function () {
|
|
if (err) { return done(err); }
|
|
req.url = req.url.replace(/\/\.well-known/, '');
|
|
wellKnownServer(req, res, done);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
if (server.expressApp) {
|
|
server.expressApp(req, res, serveTheStatic);
|
|
return;
|
|
}
|
|
|
|
serveTheStatic();
|
|
}
|
|
|
|
if (opts.livereload) {
|
|
res.__my_livereload = '<script src="//'
|
|
+ (host || opts.sites[0].name).split(':')[0]
|
|
+ ':35729/livereload.js?snipver=1"></script>';
|
|
res.__my_addLen = res.__my_livereload.length;
|
|
|
|
// TODO modify prototype instead of each instance?
|
|
res.__write = res.write;
|
|
res.write = _reloadWrite;
|
|
}
|
|
|
|
console.log('hostname:', hostname, opts.sites[0].paths);
|
|
|
|
addServer(hostname);
|
|
server = hostsMap[hostname] || hostsMap[opts.sites[0].name];
|
|
serveStaticly(server);
|
|
*/
|
|
});
|
|
};
|