diff --git a/lib/apis.js b/lib/apis.js index f576953..2737ce9 100644 --- a/lib/apis.js +++ b/lib/apis.js @@ -222,6 +222,53 @@ module.exports.create = function (xconfx, apiFactories, apiDeps) { rejectableRequest(req, res, promise, "[walnut@daplie.com] required account (not /public)"); } + function grantsRequired(grants) { + if (!Array.isArray(grants)) { + throw new Error("Usage: app.grantsRequired([ 'name|altname|altname2', 'othergrant' ])"); + } + + if (!grants.length) { + return function (req, res, next) { + next(); + }; + } + + return function (req, res, next) { + var tokenScopes; + + if (!(req.oauth3 || req.oauth3.token)) { + // TODO some error generator for standard messages + res.send({ error: { message: "You must be logged in", code: "E_NO_AUTHN" } }); + return; + } + var scope = req.oauth3.token.scope || req.oauth3.token.scp || req.oauth3.token.grants; + if ('string' !== typeof scope) { + res.send({ error: { message: "Token must contain a grants string in 'scope'", code: "E_NO_GRANTS" } }); + return; + } + + tokenScopes = scope.split(/[,\s]+/mg); + if (-1 !== tokenScopes.indexOf('*')) { + // has full account access + next(); + return; + } + + // every grant in the array must be present, though some grants can be satisfied + // by multiple scopes. + var missing = grants.filter(function (grant) { + return !grant.split('|').some(function (scp) { + return tokenScopes.indexOf(scp) !== -1; + }); + }); + if (missing.length) { + res.send({ error: { message: "Token missing required grants: '" + missing.join(',') + "'", code: "E_NO_GRANTS" } }); + return; + } + + next(); + }; + } function loadRestHelperApi(myConf, clientUrih, pkg, pkgId, pkgPath) { var pkgLinks = []; pkgLinks.push(pkgId); @@ -256,53 +303,7 @@ module.exports.create = function (xconfx, apiFactories, apiDeps) { myApp = express(); myApp.handlePromise = promisableRequest; myApp.handleRejection = rejectableRequest; - myApp.grantsRequired = function (grants) { - if (!Array.isArray(grants)) { - throw new Error("Usage: app.grantsRequired([ 'name|altname|altname2', 'othergrant' ])"); - } - - if (!grants.length) { - return function (req, res, next) { - next(); - }; - } - - return function (req, res, next) { - var tokenScopes; - - if (!(req.oauth3 || req.oauth3.token)) { - // TODO some error generator for standard messages - res.send({ error: { message: "You must be logged in", code: "E_NO_AUTHN" } }); - return; - } - var scope = req.oauth3.token.scope || req.oauth3.token.scp || req.oauth3.token.grants; - if ('string' !== typeof scope) { - res.send({ error: { message: "Token must contain a grants string in 'scope'", code: "E_NO_GRANTS" } }); - return; - } - - tokenScopes = scope.split(/[,\s]+/mg); - if (-1 !== tokenScopes.indexOf('*')) { - // has full account access - next(); - return; - } - - // every grant in the array must be present, though some grants can be satisfied - // by multiple scopes. - var missing = grants.filter(function (grant) { - return !grant.split('|').some(function (scp) { - return tokenScopes.indexOf(scp) !== -1; - }); - }); - if (missing.length) { - res.send({ error: { message: "Token missing required grants: '" + missing.join(',') + "'", code: "E_NO_GRANTS" } }); - return; - } - - next(); - }; - }; + myApp.grantsRequired = grantsRequired; myApp.use('/', require('./oauth3').attachOauth3); @@ -591,11 +592,64 @@ module.exports.create = function (xconfx, apiFactories, apiDeps) { }); } + var settingsPromise = PromiseA.resolve(); + function manageSiteSettings(section) { + + var submanager; + var manager = { + set: function (section, value) { + if ('email@daplie.com' === section) { + section = 'mailgun.org'; + } + + settingsPromise = settingsPromise.then(function () { + return manager.get().then(function () { + siteConfig[section] = value; + + var siteConfigPath = path.join(xconfx.appConfigPath, clientUrih); + return mkdirpAsync(siteConfigPath).then(function () { + return fs.writeFileAsync(path.join(siteConfigPath, 'config.json'), JSON.stringify(siteConfig), 'utf8'); + }); + }); + }); + return settingsPromise; + } + , get: function (section) { + if ('email@daplie.com' === section) { + section = 'mailgun.org'; + } + + settingsPromise = settingsPromise.then(function () { + return getSiteConfig(clientUrih).then(function (_siteConfig) { + siteConfig = _siteConfig; + return PromiseA.resolve((_siteConfig || {})[section]); + }); + }); + return settingsPromise; + } + }; + + submanager = manager; + if (section) { + submanager = { + set: function (value) { + return manager.set(section, value); + } + , get: function () { + return manager.get(section); + } + }; + } + + return apiDeps.Promise.resolve(submanager); + } + var caps = { // // Capabilities for APIs // - 'email@daplie.com': mailgunMail // whichever mailer + 'settings.site@daplie.com': manageSiteSettings + , 'email@daplie.com': mailgunMail // whichever mailer , 'mailer@daplie.com': mailgunMail // whichever mailer , 'mailgun@daplie.com': mailgunMail // specifically mailgun , 'tel@daplie.com': daplieTel // whichever telephony service @@ -736,7 +790,13 @@ module.exports.create = function (xconfx, apiFactories, apiDeps) { function loadRestHelperAssets(myConf, clientUrih, pkg, pkgId, pkgPath) { var myApp; var pkgDeps = {}; - var pkgRestAssets = require(path.join(pkgPath, 'assets.js')); + var pkgRestAssets; + + try { + pkgRestAssets = require(path.join(pkgPath, 'assets.js')); + } catch(e) { + return PromiseA.reject(e); + } Object.keys(apiDeps).forEach(function (key) { pkgDeps[key] = apiDeps[key]; @@ -758,53 +818,7 @@ module.exports.create = function (xconfx, apiFactories, apiDeps) { myApp = express(); myApp.handlePromise = promisableRequest; myApp.handleRejection = rejectableRequest; - myApp.grantsRequired = function (grants) { - if (!Array.isArray(grants)) { - throw new Error("Usage: app.grantsRequired([ 'name|altname|altname2', 'othergrant' ])"); - } - - if (!grants.length) { - return function (req, res, next) { - next(); - }; - } - - return function (req, res, next) { - var tokenScopes; - - if (!(req.oauth3 || req.oauth3.token)) { - // TODO some error generator for standard messages - res.send({ error: { message: "You must be logged in", code: "E_NO_AUTHN" } }); - return; - } - var scope = req.oauth3.token.scope || req.oauth3.token.scp || req.oauth3.token.grants; - if ('string' !== typeof scope) { - res.send({ error: { message: "Token must contain a grants string in 'scope'", code: "E_NO_GRANTS" } }); - return; - } - - tokenScopes = scope.split(/[,\s]+/mg); - if (-1 !== tokenScopes.indexOf('*')) { - // has full account access - next(); - return; - } - - // every grant in the array must be present, though some grants can be satisfied - // by multiple scopes. - var missing = grants.filter(function (grant) { - return !grant.split('|').some(function (scp) { - return tokenScopes.indexOf(scp) !== -1; - }); - }); - if (missing.length) { - res.send({ error: { message: "Token missing required grants: '" + missing.join(',') + "'", code: "E_NO_GRANTS" } }); - return; - } - - next(); - }; - }; + myApp.grantsRequired = grantsRequired; myApp.use('/', require('./oauth3').cookieOauth3); myApp.use('/', function (req, res, next) { @@ -937,6 +951,10 @@ module.exports.create = function (xconfx, apiFactories, apiDeps) { return loadRestHelperAssets(myConf, clientUrih, pkg, pkgId, pkgPath).then(function (assetsHandler) { stuff.assetsHandler = assetsHandler; return stuff; + }, function (err) { + console.error('[lib/api.js] no assets handler:'); + console.error(err); + return stuff; }); }); }); @@ -989,6 +1007,7 @@ module.exports.create = function (xconfx, apiFactories, apiDeps) { var clientUrih = req.hostname.replace(/^(api|assets)\./, '') + req.url.replace(/\/(api|assets)\/.*/, '/').replace(/\/+/g, '#').replace(/#$/, ''); var clientApiUri = req.hostname.replace(/^(api|assets)\./, 'api.') + req.url.replace(/\/(api|assets)\/.*/, '/').replace(/\/$/, ''); var clientAssetsUri = req.hostname.replace(/^(api|assets)\./, 'assets.') + req.url.replace(/\/(api|assets)\/.*/, '/').replace(/\/$/, ''); + //var clientAssetsUri = req.hostname.replace(/^(api|assets)\./, 'api.') + req.url.replace(/\/(api|assets)\/.*/, '/').replace(/\/$/, ''); // Canonical package names // '/api/com.daplie.hello/hello' should resolve to 'com.daplie.hello' // '/subapp/api/com.daplie.hello/hello' should also 'com.daplie.hello'