goldilocks.js/packages/apis/com.daplie.caddy/index.js

125 lines
4.2 KiB
JavaScript

'use strict';
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 jsonParser = bodyParser.json({
inflate: true, limit: '100kb', reviver: null, strict: true /* type, verify */
});
/*
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 () {
console.log('req.body', req.body);
deps.storage.config.merge(req.body);
deps.storage.config.save();
});
});
}
};
};