more comprehensive data model
This commit is contained in:
parent
1cae332c9c
commit
22b7a1b880
|
@ -1,3 +1,5 @@
|
||||||
|
var/*
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body class="fade" ng-class="[ 'in' ]">
|
<body class="fade" ng-class="[ 'in' ]">
|
||||||
|
|
||||||
<div ng-controller="LoginController as vm" ng-init="vm.setSimple()">
|
<div class="container" ng-controller="LoginController as vm" ng-init="vm.setSimple()">
|
||||||
<h1 ng-if="!vm.authnUpdated">Initializing... {{vm.hello}}</h1>
|
<h1 ng-if="!vm.authnUpdated">Initializing... {{vm.hello}}</h1>
|
||||||
<div ng-if="!vm.authnUpdated">
|
<div ng-if="!vm.authnUpdated">
|
||||||
<button
|
<button
|
||||||
|
@ -32,8 +32,25 @@
|
||||||
ng-click="vm.authenticate()"
|
ng-click="vm.authenticate()"
|
||||||
>Login</button>
|
>Login</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="vm.config">
|
||||||
|
<div class="input-group" ng-repeat="(sitename, siteconf) in vm.config.sites">
|
||||||
|
<label>Hostname:</label> <input class="form-control" ng-model="sitename" />
|
||||||
|
<br/>
|
||||||
|
<div ng-repeat="(pathname, modules) in siteconf.paths">Pathname:
|
||||||
|
<input class="form-control" ng-model="pathname" />
|
||||||
|
<div ng-repeat="(modulename, module) in modules">Modulename: {{modulename}}
|
||||||
|
<div ng-repeat="target in modules">Target:
|
||||||
|
<input class="form-control" ng-model="target" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<pre><code ng-bind="vm.config | json">{{vm.config}}</code></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Show Device Name</li>
|
<li>Show Device Name</li>
|
||||||
<li>Login to Daplie</li>
|
<li>Login to Daplie</li>
|
||||||
|
|
|
@ -67,10 +67,20 @@ angular.module('com.daplie.cloud', [ 'org.oauth3' ])
|
||||||
, tld: d.tld
|
, tld: d.tld
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
, jwk: null // TODO publish public key
|
||||||
}
|
}
|
||||||
}).then(function (resp) {
|
}).then(function (resp) {
|
||||||
|
// TODO resp should contain a token
|
||||||
console.info('Initialized Goldilocks', resp);
|
console.info('Initialized Goldilocks', resp);
|
||||||
|
return OAUTH3.request({
|
||||||
|
method: 'GET'
|
||||||
|
, url: 'https://' + vm.clientUri + '/api/com.daplie.caddy/config'
|
||||||
|
, session: session
|
||||||
|
}).then(function (configResp) {
|
||||||
|
console.log('config', configResp.data);
|
||||||
|
vm.config = configResp.data;
|
||||||
return resp;
|
return resp;
|
||||||
|
});
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
window.alert("Initialization failed:" + err.message);
|
window.alert("Initialization failed:" + err.message);
|
||||||
|
@ -82,6 +92,9 @@ angular.module('com.daplie.cloud', [ 'org.oauth3' ])
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
oauth3.checkSession().then(function (session) {
|
||||||
|
console.log('hasSession?', session);
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
console.log('OAUTH3.PromiseA', OAUTH3.PromiseA);
|
console.log('OAUTH3.PromiseA', OAUTH3.PromiseA);
|
||||||
|
|
|
@ -93,10 +93,23 @@ function createServer(port, _delete_me_, content, opts) {
|
||||||
return new PromiseA(function (realResolve) {
|
return new PromiseA(function (realResolve) {
|
||||||
var app = require('../lib/app.js');
|
var app = require('../lib/app.js');
|
||||||
|
|
||||||
var directive = { content: content, livereload: opts.livereload
|
var directive = {
|
||||||
|
content: content
|
||||||
|
, livereload: opts.livereload
|
||||||
|
, global: {
|
||||||
|
greenlock: { email: opts.email, tos: opts.tos }
|
||||||
|
, rvpn: { email: opts.email, tos: opts.tos }
|
||||||
|
, paths: {
|
||||||
|
'/assets/': { serve: [ opts.assetsPath ] }
|
||||||
|
// TODO figure this b out
|
||||||
|
, '/.well-known/': { serve: [ path.resolve(opts.assetsPath, 'well-known') ] }
|
||||||
|
, '/': { serve: [ opts.webRoot ], indexes: [ opts.webRoot ] }
|
||||||
|
}
|
||||||
|
}
|
||||||
, sites: opts.sites
|
, sites: opts.sites
|
||||||
, assetsPath: opts.assetsPath
|
, expressApp: opts.expressApp
|
||||||
, expressApp: opts.expressApp };
|
};
|
||||||
|
var server;
|
||||||
var insecureServer;
|
var insecureServer;
|
||||||
|
|
||||||
function resolve() {
|
function resolve() {
|
||||||
|
@ -160,7 +173,7 @@ function createServer(port, _delete_me_, content, opts) {
|
||||||
// Dynamic Certs
|
// Dynamic Certs
|
||||||
lex.httpsOptions.SNICallback(sni, cb);
|
lex.httpsOptions.SNICallback(sni, cb);
|
||||||
};
|
};
|
||||||
var server = https.createServer(opts.httpsOptions);
|
server = https.createServer(opts.httpsOptions);
|
||||||
|
|
||||||
server.on('error', function (err) {
|
server.on('error', function (err) {
|
||||||
if (opts.errorPort || opts.manualPort) {
|
if (opts.errorPort || opts.manualPort) {
|
||||||
|
@ -369,39 +382,57 @@ function run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
opts.sites = [ { name: defaultServername , path: '.' } ];
|
opts.cwd = process.cwd();
|
||||||
|
opts.sites = {};
|
||||||
|
|
||||||
if (argv.sites) {
|
if (argv.sites) {
|
||||||
opts._externalHost = false;
|
opts._externalHost = false;
|
||||||
opts.sites = argv.sites.split(',').map(function (name) {
|
argv.sites.split(',').map(function (name) {
|
||||||
var nameparts = name.split('|');
|
var nameparts = name.split('|');
|
||||||
var servername = nameparts.shift();
|
var servername = nameparts.shift();
|
||||||
|
var modules;
|
||||||
|
|
||||||
opts._externalHost = opts._externalHost || !/(^|\.)localhost\./.test(servername);
|
opts._externalHost = opts._externalHost || !/(^|\.)localhost\./.test(servername);
|
||||||
// TODO allow reverse proxy
|
// TODO allow reverse proxy
|
||||||
return {
|
if (!opts.sites[servername]) {
|
||||||
name: servername
|
opts.sites[servername] = { paths: {} };
|
||||||
// there should always be a path
|
}
|
||||||
, paths: nameparts.length && nameparts || [
|
|
||||||
defaultWebRoot.replace(/(:hostname|:servername)/g, servername)
|
if (!nameparts.length) {
|
||||||
]
|
return;
|
||||||
// TODO check for existing custom path before issuing with greenlock
|
}
|
||||||
, _hasCustomPath: !!nameparts.length
|
|
||||||
};
|
if (!opts.sites[servername].paths['/']) {
|
||||||
|
opts.sites[servername].paths['/'] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
modules = opts.sites[servername].paths['/'];
|
||||||
|
modules.serve = nameparts;
|
||||||
|
modules.indexes = nameparts;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
opts.sites.push({
|
|
||||||
name: 'localhost.alpha.daplie.me'
|
opts.groups = {};
|
||||||
, paths: [ path.resolve(__dirname, '..', 'admin', 'public') ]
|
|
||||||
, app: path.join(__dirname, 'admin')
|
// 'packages', 'assets', 'com.daplie.caddy'
|
||||||
});
|
opts.sites['localhost.alpha.daplie.me'] = {
|
||||||
opts.sites.push({
|
// greenlock: {}
|
||||||
name: 'localhost.daplie.invalid'
|
paths: {
|
||||||
, paths: [ path.join(__dirname, '..', 'admin', 'public') ]
|
'/': { serve: [ path.resolve(__dirname, '..', 'admin', 'public') ] }
|
||||||
, app: path.join(__dirname, 'admin')
|
, '/api/': { app: path.join(__dirname, 'admin') }
|
||||||
});
|
}
|
||||||
|
};
|
||||||
|
opts.sites['localhost.daplie.invalid'] = {
|
||||||
|
paths: {
|
||||||
|
'/': { serve: [ path.resolve(__dirname, '..', 'admin', 'public') ] }
|
||||||
|
, '/api/': { app: path.join(__dirname, 'admin') }
|
||||||
|
}
|
||||||
|
};
|
||||||
opts.assetsPath = path.join(__dirname, '..', 'packages', 'assets');
|
opts.assetsPath = path.join(__dirname, '..', 'packages', 'assets');
|
||||||
|
opts.webRoot = defaultWebRoot;
|
||||||
|
|
||||||
// TODO use arrays in all things
|
// TODO use arrays in all things
|
||||||
opts._old_server_name = opts.sites[0].name;
|
opts._old_server_name = Object.keys(opts.sites)[0];
|
||||||
opts.pubdir = defaultWebRoot.replace(/(:hostname|:servername).*/, '');
|
opts.pubdir = defaultWebRoot.replace(/(:hostname|:servername).*/, '');
|
||||||
|
|
||||||
if (argv.p || argv.port || argv._[0]) {
|
if (argv.p || argv.port || argv._[0]) {
|
||||||
|
|
236
lib/app.js
236
lib/app.js
|
@ -1,52 +1,20 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = function (opts) {
|
module.exports = function (opts) {
|
||||||
var finalhandler = require('finalhandler');
|
var express = require('express');
|
||||||
|
//var finalhandler = require('finalhandler');
|
||||||
var serveStatic = require('serve-static');
|
var serveStatic = require('serve-static');
|
||||||
var serveIndex = require('serve-index');
|
var serveIndex = require('serve-index');
|
||||||
var assetServer = serveStatic(opts.assetsPath);
|
//var assetServer = serveStatic(opts.assetsPath);
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var wellKnownServer = serveStatic(path.join(opts.assetsPath, 'well-known'));
|
//var wellKnownServer = serveStatic(path.join(opts.assetsPath, 'well-known'));
|
||||||
|
|
||||||
var hostsMap = {};
|
var serveStaticMap = {};
|
||||||
var pathsMap = {};
|
var serveIndexMap = {};
|
||||||
var content = opts.content;
|
var content = opts.content;
|
||||||
var server;
|
//var server;
|
||||||
var serveInit;
|
var serveInit;
|
||||||
|
var app;
|
||||||
function addServer(hostname) {
|
|
||||||
|
|
||||||
if (hostsMap[hostname]) {
|
|
||||||
return hostsMap[hostname];
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.sites.forEach(function (site) {
|
|
||||||
|
|
||||||
if (hostname !== site.name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// path should exist before it gets to this point
|
|
||||||
site.path = site.path || site.paths[0];
|
|
||||||
|
|
||||||
if (!pathsMap[site.path]) {
|
|
||||||
console.log('site:', site);
|
|
||||||
pathsMap[site.path] = {
|
|
||||||
serve: serveStatic(site.path)
|
|
||||||
// TODO option for dotfiles
|
|
||||||
, index: serveIndex(site.path)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
hostsMap[hostname] = {
|
|
||||||
serve: pathsMap[site.path].serve
|
|
||||||
, index: pathsMap[site.path].index
|
|
||||||
, app: site.app
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function _reloadWrite(data, enc, cb) {
|
function _reloadWrite(data, enc, cb) {
|
||||||
/*jshint validthis: true */
|
/*jshint validthis: true */
|
||||||
|
@ -69,14 +37,67 @@ module.exports = function (opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
addServer(opts.sites[0].name);
|
function createServeInit() {
|
||||||
|
var PromiseA = require('bluebird');
|
||||||
|
var fs = PromiseA.promisifyAll(require('fs'));
|
||||||
|
var ownersPath = path.join(__dirname, '..', 'var', 'owners.json');
|
||||||
|
|
||||||
return function (req, res) {
|
return require('../packages/apis/com.daplie.caddy').create({
|
||||||
if ('/api/com.daplie.caddy/init' === req.url) {
|
PromiseA: PromiseA
|
||||||
if (!serveInit) {
|
, storage: {
|
||||||
serveInit = require('../packages/apis/com.daplie.caddy').create(opts);
|
owners: {
|
||||||
|
all: function () {
|
||||||
|
var owners;
|
||||||
|
try {
|
||||||
|
owners = require(ownersPath);
|
||||||
|
} catch(e) {
|
||||||
|
owners = {};
|
||||||
}
|
}
|
||||||
serveInit(req, res);
|
|
||||||
|
return PromiseA.resolve(Object.keys(owners).map(function (key) {
|
||||||
|
var owner = owners[key];
|
||||||
|
owner.id = key;
|
||||||
|
return owner;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
, set: function (id, obj) {
|
||||||
|
var owners;
|
||||||
|
try {
|
||||||
|
owners = require(ownersPath);
|
||||||
|
} catch(e) {
|
||||||
|
owners = {};
|
||||||
|
}
|
||||||
|
obj.id = id;
|
||||||
|
owners[id] = obj;
|
||||||
|
|
||||||
|
return fs.writeFileAsync(ownersPath, JSON.stringify(owners), 'utf8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, recase: require('recase').create({})
|
||||||
|
, options: opts
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app = express();
|
||||||
|
|
||||||
|
return app.use('/', function (req, res, next) {
|
||||||
|
if (!req.headers.host) {
|
||||||
|
next(new Error('missing HTTP Host header'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 === req.url.indexOf('/api/com.daplie.caddy/')) {
|
||||||
|
if (!serveInit) {
|
||||||
|
serveInit = createServeInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ('/api/com.daplie.caddy/init' === req.url) {
|
||||||
|
serveInit.init(req, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ('/api/com.daplie.caddy/config' === req.url) {
|
||||||
|
serveInit.config(req, res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,10 +106,123 @@ module.exports = function (opts) {
|
||||||
res.end(content);
|
res.end(content);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var done = finalhandler(req, res);
|
|
||||||
var host = req.headers.host;
|
|
||||||
var hostname = (host||'').split(':')[0] || opts.sites[0].name;
|
|
||||||
|
|
||||||
|
//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 || {}, opts.sites[hostname] || {}, opts.defer || {} ];
|
||||||
|
var loadables = {
|
||||||
|
serve: function (config, hostname, pathname, req, res, next) {
|
||||||
|
config = config.slice(0);
|
||||||
|
var originalUrl = req.url;
|
||||||
|
|
||||||
|
function nextServe() {
|
||||||
|
var dirname = config.pop();
|
||||||
|
console.log('[serve]', req.url, hostname, pathname, dirname);
|
||||||
|
if (!dirname) {
|
||||||
|
req.url = originalUrl;
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
config = config.slice(0);
|
||||||
|
var originalUrl = req.url;
|
||||||
|
|
||||||
|
function nextIndex() {
|
||||||
|
var dirname = config.pop();
|
||||||
|
console.log('[indexes]', req.url, hostname, pathname, dirname);
|
||||||
|
if (!dirname) {
|
||||||
|
req.url = originalUrl;
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serveStaticMap[dirname]) {
|
||||||
|
serveIndexMap[dirname] = serveIndex(dirname);
|
||||||
|
}
|
||||||
|
serveIndexMap[dirname](req, res, nextIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
req.url = req.url.substr(pathname.length - 1);
|
||||||
|
nextIndex();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function runModule(config, hostname, pathname, modulename, req, res, next) {
|
||||||
|
if (!loadables[modulename]) {
|
||||||
|
next(new Error("no module '" + modulename + "' found"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadables[modulename](config, hostname, pathname, req, res, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
function iterModules(modules, hostname, pathname, req, res, next) {
|
||||||
|
var modulenames = Object.keys(modules);
|
||||||
|
|
||||||
|
function nextModule() {
|
||||||
|
var modulename = modulenames.pop();
|
||||||
|
if (!modulename) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('modules', modules);
|
||||||
|
runModule(modules[modulename], hostname, pathname, modulename, req, res, nextModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
function iterPaths(site, hostname, req, res, next) {
|
||||||
|
var pathnames = Object.keys(site.paths || {});
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
function nextPath() {
|
||||||
|
var pathname = pathnames.pop();
|
||||||
|
if (!pathname) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('iterPaths', hostname, pathname, req.url);
|
||||||
|
iterModules(site.paths[pathname], hostname, pathname, req, res, nextPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
function nextSite() {
|
||||||
|
var site = sites.pop();
|
||||||
|
if (!site) {
|
||||||
|
next(); // 404
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iterPaths(site, hostname, req, res, nextSite);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextSite();
|
||||||
|
|
||||||
|
/*
|
||||||
function serveStaticly(server) {
|
function serveStaticly(server) {
|
||||||
function serveTheStatic() {
|
function serveTheStatic() {
|
||||||
server.serve(req, res, function (err) {
|
server.serve(req, res, function (err) {
|
||||||
|
@ -129,6 +263,6 @@ module.exports = function (opts) {
|
||||||
addServer(hostname);
|
addServer(hostname);
|
||||||
server = hostsMap[hostname] || hostsMap[opts.sites[0].name];
|
server = hostsMap[hostname] || hostsMap[opts.sites[0].name];
|
||||||
serveStaticly(server);
|
serveStaticly(server);
|
||||||
|
*/
|
||||||
};
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
"body-parser": "git+https://github.com/expressjs/body-parser.git#1.16.1",
|
"body-parser": "git+https://github.com/expressjs/body-parser.git#1.16.1",
|
||||||
"daplie-tunnel": "git+https://git.daplie.com/Daplie/daplie-cli-tunnel.git#master",
|
"daplie-tunnel": "git+https://git.daplie.com/Daplie/daplie-cli-tunnel.git#master",
|
||||||
"ddns-cli": "git+https://git.daplie.com/Daplie/node-ddns-client.git#master",
|
"ddns-cli": "git+https://git.daplie.com/Daplie/node-ddns-client.git#master",
|
||||||
|
"express": "git+https://github.com/expressjs/express.git#4.x",
|
||||||
"finalhandler": "^0.4.0",
|
"finalhandler": "^0.4.0",
|
||||||
"greenlock": "git+https://git.daplie.com/Daplie/node-greenlock.git#master",
|
"greenlock": "git+https://git.daplie.com/Daplie/node-greenlock.git#master",
|
||||||
"greenlock-express": "git+https://git.daplie.com/Daplie/greenlock-express.git#master",
|
"greenlock-express": "git+https://git.daplie.com/Daplie/greenlock-express.git#master",
|
||||||
|
@ -55,7 +56,9 @@
|
||||||
"localhost.daplie.me-certificates": "^1.3.0",
|
"localhost.daplie.me-certificates": "^1.3.0",
|
||||||
"minimist": "^1.1.1",
|
"minimist": "^1.1.1",
|
||||||
"oauth3-cli": "git+https://git.daplie.com/OAuth3/oauth3-cli.git#master",
|
"oauth3-cli": "git+https://git.daplie.com/OAuth3/oauth3-cli.git#master",
|
||||||
|
"recase": "git+https://git.daplie.com/coolaj86/recase-js.git#v1.0.4",
|
||||||
"redirect-https": "^1.1.0",
|
"redirect-https": "^1.1.0",
|
||||||
|
"scmp": "git+https://github.com/freewil/scmp.git#1.x",
|
||||||
"serve-index": "^1.7.0",
|
"serve-index": "^1.7.0",
|
||||||
"serve-static": "^1.10.0",
|
"serve-static": "^1.10.0",
|
||||||
"stunnel": "git+https://git.daplie.com/Daplie/node-tunnel-client.git#master"
|
"stunnel": "git+https://git.daplie.com/Daplie/node-tunnel-client.git#master"
|
||||||
|
|
|
@ -1,18 +1,124 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports.create = function (opts) {
|
module.exports.dependencies = [ 'storage.owners' ];
|
||||||
|
module.exports.create = function (deps) {
|
||||||
|
var scmp = require('scmp');
|
||||||
|
var crypto = require('crypto');
|
||||||
|
var jwt = require('jsonwebtoken');
|
||||||
var bodyParser = require('body-parser');
|
var bodyParser = require('body-parser');
|
||||||
var jsonParser = bodyParser.json({
|
var jsonParser = bodyParser.json({
|
||||||
inflate: true, limit: '100kb', reviver: null, strict: true /* type, verify */
|
inflate: true, limit: '100kb', reviver: null, strict: true /* type, verify */
|
||||||
});
|
});
|
||||||
|
|
||||||
return function (req, res) {
|
/*
|
||||||
|
var owners;
|
||||||
|
deps.storage.owners.on('set', function (_owners) {
|
||||||
|
owners = _owners;
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
deps.storage.owners.exists = function (id) {
|
||||||
|
return deps.storage.owners.all().then(function (owners) {
|
||||||
|
return owners.some(function (owner) {
|
||||||
|
return scmp(id, owner.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function isAuthorized(req, res, fn) {
|
||||||
|
var auth = jwt.decode((req.headers.authorization||'').replace(/^bearer\s+/i, ''));
|
||||||
|
if (!auth) {
|
||||||
|
res.setHeader('Content-Type', 'application/json;');
|
||||||
|
res.end(JSON.stringify({ error: { message: "no token", code: 'E_NO_TOKEN', uri: undefined } }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = crypto.createHash('sha256').update(auth.sub).digest('hex');
|
||||||
|
return deps.storage.owners.exists(id).then(function (exists) {
|
||||||
|
if (!exists) {
|
||||||
|
res.setHeader('Content-Type', 'application/json;');
|
||||||
|
res.end(JSON.stringify({ error: { message: "not authorized", code: 'E_NO_AUTHZ', uri: undefined } }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init: function (req, res) {
|
||||||
|
jsonParser(req, res, function () {
|
||||||
|
|
||||||
|
console.log('req.body', req.body);
|
||||||
|
var auth = jwt.decode((req.headers.authorization||'').replace(/^bearer\s+/i, ''));
|
||||||
|
var token = jwt.decode(req.body.access_token);
|
||||||
|
var refresh = jwt.decode(req.body.refresh_token);
|
||||||
|
auth.sub = auth.sub || auth.acx.id;
|
||||||
|
token.sub = token.sub || token.acx.id;
|
||||||
|
refresh.sub = refresh.sub || refresh.acx.id;
|
||||||
|
|
||||||
|
// TODO validate token with issuer, but as-is the sub is already a secret
|
||||||
|
var id = crypto.createHash('sha256').update(auth.sub).digest('hex');
|
||||||
|
var tid = crypto.createHash('sha256').update(token.sub).digest('hex');
|
||||||
|
var rid = crypto.createHash('sha256').update(refresh.sub).digest('hex');
|
||||||
|
|
||||||
|
console.log('ids', id, tid, rid);
|
||||||
|
return deps.storage.owners.all().then(function (results) {
|
||||||
|
console.log('results', results);
|
||||||
|
var err;
|
||||||
|
|
||||||
|
// There is no owner yet. First come, first serve.
|
||||||
|
if (!results || !results.length) {
|
||||||
|
if (tid !== id || rid !== id) {
|
||||||
|
err = new Error("When creating an owner the Authorization Bearer and Token and Refresh must all match");
|
||||||
|
return deps.PromiseA.reject(err);
|
||||||
|
}
|
||||||
|
console.log('no owner, creating');
|
||||||
|
return deps.storage.owners.set(id, { token: token, refresh: refresh });
|
||||||
|
}
|
||||||
|
console.log('has results');
|
||||||
|
|
||||||
|
// There are onwers. Is this one of them?
|
||||||
|
if (!results.some(function (token) {
|
||||||
|
return scmp(id, token.id);
|
||||||
|
})) {
|
||||||
|
err = new Error("Authorization token does not belong to an existing owner.");
|
||||||
|
return deps.PromiseA.reject(err);
|
||||||
|
}
|
||||||
|
console.log('has correct owner');
|
||||||
|
|
||||||
|
// We're adding an owner, unless it already exists
|
||||||
|
if (!results.some(function (token) {
|
||||||
|
return scmp(tid, token.id);
|
||||||
|
})) {
|
||||||
|
console.log('adds new owner with existing owner');
|
||||||
|
return deps.storage.owners.set(id, { token: token, refresh: refresh });
|
||||||
|
}
|
||||||
|
}).then(function () {
|
||||||
|
res.setHeader('Content-Type', 'application/json;');
|
||||||
|
res.end(JSON.stringify({ success: true }));
|
||||||
|
}, function (err) {
|
||||||
|
res.setHeader('Content-Type', 'application/json;');
|
||||||
|
res.end(JSON.stringify({ error: { message: err.message, code: err.code, uri: err.uri } }));
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
, config: function (req, res) {
|
||||||
|
isAuthorized(req, res, function () {
|
||||||
|
if ('POST' !== req.method) {
|
||||||
|
res.setHeader('Content-Type', 'application/json;');
|
||||||
|
res.end(JSON.stringify(deps.recase.snakeCopy(deps.options)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
jsonParser(req, res, function () {
|
jsonParser(req, res, function () {
|
||||||
|
|
||||||
console.log('req.body', req.body);
|
console.log('req.body', req.body);
|
||||||
|
|
||||||
res.setHeader('Content-Type', 'application/json;');
|
deps.storage.config.merge(req.body);
|
||||||
res.end(JSON.stringify({ error: { message: "Not Implemented", code: "E_NO_IMPL" } }));
|
deps.storage.config.save();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit eff1fd11272472e8f6d03ac8b897a9853810672e
|
Subproject commit f179cfe3c9553718676db24f1203f67ea0427662
|
Loading…
Reference in New Issue