| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports.create = function (xconfx, apiFactories, apiDeps) { | 
					
						
							|  |  |  |   var PromiseA = apiDeps.Promise; | 
					
						
							| 
									
										
										
										
											2017-05-26 20:23:17 +00:00
										 |  |  |   var mkdirpAsync = PromiseA.promisify(require('mkdirp')); | 
					
						
							| 
									
										
										
										
											2017-08-04 11:45:33 -06:00
										 |  |  |   var request = PromiseA.promisify(require('request')); | 
					
						
							| 
									
										
										
										
											2017-05-24 04:27:52 +00:00
										 |  |  |   //var express = require('express');
 | 
					
						
							|  |  |  |   var express = require('express-lazy'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   var fs = PromiseA.promisifyAll(require('fs')); | 
					
						
							|  |  |  |   var path = require('path'); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |   var localCache = { rests: {}, pkgs: {}, assets: {} }; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |   var promisableRequest = require('./common').promisableRequest; | 
					
						
							|  |  |  |   var rejectableRequest = require('./common').rejectableRequest; | 
					
						
							|  |  |  |   var crypto = require('crypto'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // TODO xconfx.apispath
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |   xconfx.restPath = path.join(__dirname, '..', '..', 'packages', 'rest'); | 
					
						
							| 
									
										
										
										
											2017-05-27 01:17:50 +00:00
										 |  |  |   xconfx.apiPath = path.join(__dirname, '..', '..', 'packages', 'api'); | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |   xconfx.appApiGrantsPath = path.join(__dirname, '..', '..', 'packages', 'client-api-grants'); | 
					
						
							| 
									
										
										
										
											2017-05-24 07:34:34 +00:00
										 |  |  |   xconfx.appConfigPath = path.join(__dirname, '..', '..', 'var'); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   function notConfigured(req, res) { | 
					
						
							| 
									
										
										
										
											2017-05-20 04:51:44 +00:00
										 |  |  |     var msg = "api package '" + req.pkgId + "' not configured for client uri '" + req.experienceId + "'" | 
					
						
							|  |  |  |       + ". To configure it place a new line '" + req.pkgId + "' in the file '/srv/walnut/packages/client-api-grants/" + req.experienceId + "'" | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res.send({ error: { message: msg } }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |   /* | 
					
						
							|  |  |  |   function isThisPkgInstalled(myConf, pkgId) { | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |   function isThisClientAllowedToUseThisPkg(req, myConf, clientUrih, pkgId) { | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |     var appApiGrantsPath = path.join(myConf.appApiGrantsPath, clientUrih); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return fs.readFileAsync(appApiGrantsPath, 'utf8').then(function (text) { | 
					
						
							|  |  |  |       return text.trim().split(/\n/); | 
					
						
							| 
									
										
										
										
											2017-05-20 04:51:44 +00:00
										 |  |  |     }, function (err) { | 
					
						
							|  |  |  |       if ('ENOENT' !== err.code) { | 
					
						
							|  |  |  |         console.error(err); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       return []; | 
					
						
							|  |  |  |     }).then(function (apis) { | 
					
						
							| 
									
										
										
										
											2017-05-20 00:09:48 +00:00
										 |  |  |       if (apis.some(function (api) { | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |         if (api === pkgId) { | 
					
						
							|  |  |  |           return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       })) { | 
					
						
							| 
									
										
										
										
											2017-05-20 00:09:48 +00:00
										 |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-07-06 23:26:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       console.log('#################################################'); | 
					
						
							|  |  |  |       console.log('assets.' + xconfx.setupDomain); | 
					
						
							|  |  |  |       console.log('assets.' + clientUrih); | 
					
						
							|  |  |  |       console.log(req.clientAssetsUri); | 
					
						
							|  |  |  |       console.log(pkgId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (req.clientAssetsUri === ('assets.' + clientUrih) && -1 !== [ 'session', 'session@oauth3.org', 'azp@oauth3.org', 'issuer@oauth3.org' ].indexOf(pkgId)) { | 
					
						
							|  |  |  |         // fallthrough
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (clientUrih === ('api.' + xconfx.setupDomain) && -1 !== ['org.oauth3.consumer', 'azp@oauth3.org', 'oauth3.org'].indexOf(pkgId)) { | 
					
						
							| 
									
										
										
										
											2017-07-06 23:26:58 +00:00
										 |  |  |         // fallthrough
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return null; | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |   function getSitePackageConfig(clientUrih, pkgId) { | 
					
						
							|  |  |  |     var siteConfigPath = path.join(xconfx.appConfigPath, clientUrih); | 
					
						
							|  |  |  |     return mkdirpAsync(siteConfigPath).then(function () { | 
					
						
							|  |  |  |       return fs.readFileAsync(path.join(siteConfigPath, pkgId + '.json'), 'utf8').then(function (text) { | 
					
						
							|  |  |  |         return JSON.parse(text); | 
					
						
							|  |  |  |       }).then(function (data) { return data; }, function (/*err*/) { return {}; }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-24 07:34:34 +00:00
										 |  |  |   function getSiteConfig(clientUrih) { | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |     // TODO test if the requesting package has permission to the root-level site config
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:23:17 +00:00
										 |  |  |     var siteConfigPath = path.join(xconfx.appConfigPath, clientUrih); | 
					
						
							|  |  |  |     return mkdirpAsync(siteConfigPath).then(function () { | 
					
						
							|  |  |  |       return fs.readFileAsync(path.join(siteConfigPath, 'config.json'), 'utf8').then(function (text) { | 
					
						
							|  |  |  |         return JSON.parse(text); | 
					
						
							|  |  |  |       }).then(function (data) { return data; }, function (/*err*/) { return {}; }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-05-24 07:34:34 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 22:06:21 +00:00
										 |  |  |   var modelsCache = {}; | 
					
						
							|  |  |  |   function getSiteStore(clientUrih, pkgId, dir) { | 
					
						
							| 
									
										
										
										
											2017-05-30 01:39:21 +00:00
										 |  |  |     if (!modelsCache[clientUrih]) { | 
					
						
							|  |  |  |       modelsCache[clientUrih] = apiFactories.systemSqlFactory.create({ | 
					
						
							|  |  |  |         init: true | 
					
						
							|  |  |  |       , dbname: clientUrih // '#' is a valid file name character
 | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-05-26 22:06:21 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // DB scopes:
 | 
					
						
							|  |  |  |     // system (global)
 | 
					
						
							|  |  |  |     // experience (per domain)
 | 
					
						
							|  |  |  |     // api (per api)
 | 
					
						
							|  |  |  |     // account (per user account)
 | 
					
						
							|  |  |  |     // client (per 3rd party client)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // scope Experience to db
 | 
					
						
							|  |  |  |     // scope Api by table
 | 
					
						
							|  |  |  |     // scope Account and Client by column
 | 
					
						
							| 
									
										
										
										
											2017-05-30 01:39:21 +00:00
										 |  |  |     return modelsCache[clientUrih].then(function (db) { | 
					
						
							| 
									
										
										
										
											2017-05-26 22:06:21 +00:00
										 |  |  |       var wrap = require('masterquest-sqlite3'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return wrap.wrap(db, dir).then(function (models) { | 
					
						
							| 
									
										
										
										
											2017-05-30 01:39:21 +00:00
										 |  |  |         //modelsCache[clientUrih] = PromiseA.resolve(models);
 | 
					
						
							| 
									
										
										
										
											2017-05-26 22:06:21 +00:00
										 |  |  |         return models; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |   function accountRequiredById(req, res, next) { | 
					
						
							|  |  |  |     var promise = req.oauth3.verifyAsync().then(function (/*result*/) { | 
					
						
							|  |  |  |       var tok = req.oauth3.token; | 
					
						
							|  |  |  |       var accountId = req.params.accountId || '__NO_ID_GIVEN__'; | 
					
						
							|  |  |  |       var ppid; | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |       var iss = tok.iss; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (tok.sub && tok.sub.split(/,/g).filter(function (ppid) { | 
					
						
							|  |  |  |         return ppid === accountId; | 
					
						
							|  |  |  |       }).length) { | 
					
						
							|  |  |  |         ppid = accountId; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |       // Deprecated backwards compat. To be removed.
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |       if (tok.axs && tok.axs.filter(function (acc) { | 
					
						
							|  |  |  |         return acc.id === accountId || acc.appScopedId === accountId; | 
					
						
							|  |  |  |       }).length) { | 
					
						
							|  |  |  |         ppid = accountId; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (tok.acx && accountId === (tok.acx.appScopedId || tok.acx.id || tok.acx)) { | 
					
						
							|  |  |  |         ppid = accountId; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!ppid) { | 
					
						
							|  |  |  |         return PromiseA.reject(new Error("missing accountId '" + accountId + "' in access token")); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |       return req.oauth3.rescope().then(function (accountIdx) { | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |         req.oauth3.accountIdx = accountIdx; | 
					
						
							|  |  |  |         req.oauth3.ppid = ppid; | 
					
						
							| 
									
										
										
										
											2017-07-31 22:46:03 +00:00
										 |  |  |         //console.log('[walnut@daplie.com] accountIdx:', accountIdx);
 | 
					
						
							|  |  |  |         //console.log('[walnut@daplie.com] ppid:', ppid);
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 22:46:03 +00:00
										 |  |  |     rejectableRequest(req, res, promise, "[walnut@daplie.com] attach account by id"); | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function accountRequired(req, res, next) { | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |     console.log('[accountRequired] [enter]'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var myIss = req.experienceId; | 
					
						
							|  |  |  |     var isPpid; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |     // if this already has auth, great
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |     if (req.oauth3.ppid && req.oauth3.accountIdx) { | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |       // except that if it's a ppid, we have to internally exchange it for the real token
 | 
					
						
							|  |  |  |       isPpid = (myIss === req.oauth3.iss && myIss !== req.oauth3.azp); | 
					
						
							|  |  |  |       if (!isPpid) { | 
					
						
							|  |  |  |         console.log('[accountRequired] has token already'); | 
					
						
							|  |  |  |         console.log(req.oauth3); | 
					
						
							|  |  |  |         console.log(''); | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!req.oauth3.encodedToken) { | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |       // being public does not disallow authentication
 | 
					
						
							|  |  |  |       if (req.isPublic) { | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |       rejectableRequest( | 
					
						
							|  |  |  |         req | 
					
						
							|  |  |  |       , res | 
					
						
							|  |  |  |       , PromiseA.reject(new Error("this secure resource requires an access token")) | 
					
						
							| 
									
										
										
										
											2017-07-31 22:46:03 +00:00
										 |  |  |       , "[walnut@daplie.com] required account (not /public)" | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |       ); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // verify the auth if it's here
 | 
					
						
							|  |  |  |     var promise = req.oauth3.verifyAsync().then(function (/*result*/) { | 
					
						
							|  |  |  |       var tok = req.oauth3.token; | 
					
						
							|  |  |  |       var ppid; | 
					
						
							|  |  |  |       var err; | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |       var iss = tok.iss; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (tok.sub) { | 
					
						
							|  |  |  |         if (tok.sub.split(/,/g).length > 1) { | 
					
						
							|  |  |  |           err = new Error("more than one 'sub' specified in token"); | 
					
						
							|  |  |  |           return PromiseA.reject(err); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ppid = tok.sub; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!ppid) { | 
					
						
							|  |  |  |         return PromiseA.reject(new Error("could not determine accountId from access token")); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 08:20:46 +00:00
										 |  |  |       return req.oauth3.rescope().then(function (accountIdx) { | 
					
						
							|  |  |  |         console.log('[accountRequired] req.oauth3'); | 
					
						
							|  |  |  |         console.log(accountIdx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         var sub = accountIdx.split('@')[0]; | 
					
						
							|  |  |  |         var iss = accountIdx.split('@')[1]; | 
					
						
							|  |  |  |         var id = sub + '@' + iss; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         req.oauth3.profile = { | 
					
						
							|  |  |  |           id: id | 
					
						
							|  |  |  |         , sub: sub | 
					
						
							|  |  |  |         , iss: iss | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         req.oauth3.id = id; | 
					
						
							|  |  |  |         req.oauth3.sub = sub; | 
					
						
							|  |  |  |         req.oauth3.iss = iss; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |         req.oauth3.accountIdx = accountIdx; | 
					
						
							|  |  |  |         req.oauth3.ppid = ppid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 22:46:03 +00:00
										 |  |  |     rejectableRequest(req, res, promise, "[walnut@daplie.com] required account (not /public)"); | 
					
						
							| 
									
										
										
										
											2017-05-31 20:02:26 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |   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(); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |   function loadRestHelperApi(myConf, clientUrih, pkg, pkgId, pkgPath) { | 
					
						
							| 
									
										
										
										
											2017-05-26 23:09:49 +00:00
										 |  |  |     var pkgLinks = []; | 
					
						
							|  |  |  |     pkgLinks.push(pkgId); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     var pkgRestApi; | 
					
						
							|  |  |  |     var pkgDeps = {}; | 
					
						
							|  |  |  |     var myApp; | 
					
						
							|  |  |  |     var pkgPathApi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pkgPathApi = pkgPath; | 
					
						
							|  |  |  |     if (pkg.walnut) { | 
					
						
							|  |  |  |       pkgPathApi = path.join(pkgPath, pkg.walnut); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     pkgRestApi = require(pkgPathApi); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     Object.keys(apiDeps).forEach(function (key) { | 
					
						
							|  |  |  |       pkgDeps[key] = apiDeps[key]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     Object.keys(apiFactories).forEach(function (key) { | 
					
						
							|  |  |  |       pkgDeps[key] = apiFactories[key]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO pull db stuff from package.json somehow and pass allowed data models as deps
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // how can we tell which of these would be correct?
 | 
					
						
							|  |  |  |     // deps.memstore = apiFactories.memstoreFactory.create(pkgId);
 | 
					
						
							|  |  |  |     // deps.memstore = apiFactories.memstoreFactory.create(req.experienceId);
 | 
					
						
							|  |  |  |     // deps.memstore = apiFactories.memstoreFactory.create(req.experienceId + pkgId);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // let's go with this one for now and the api can choose to scope or not to scope
 | 
					
						
							|  |  |  |     pkgDeps.memstore = apiFactories.memstoreFactory.create(pkgId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     myApp = express(); | 
					
						
							|  |  |  |     myApp.handlePromise = promisableRequest; | 
					
						
							|  |  |  |     myApp.handleRejection = rejectableRequest; | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |     myApp.grantsRequired = grantsRequired; | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |     function getSitePackageStoreProp(otherPkgId) { | 
					
						
							|  |  |  |       var restPath = path.join(myConf.restPath, otherPkgId); | 
					
						
							|  |  |  |       var apiPath = path.join(myConf.apiPath, otherPkgId); | 
					
						
							|  |  |  |       var dir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // TODO usage package.json as a falback if the standard location is not used
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         dir = require(path.join(apiPath, 'models.js')); | 
					
						
							|  |  |  |       } catch(e) { | 
					
						
							|  |  |  |         dir = require(path.join(restPath, 'models.js')); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return getSiteStore(clientUrih, otherPkgId, dir); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function attachOauth3(req, res, next) { | 
					
						
							|  |  |  |       return getSitePackageStoreProp('issuer@oauth3.org').then(function (Models) { | 
					
						
							|  |  |  |         return require('./oauth3').attachOauth3(Models, req, res, next); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     myApp.use('/', attachOauth3); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // TODO delete these caches when config changes
 | 
					
						
							|  |  |  |     var _stripe; | 
					
						
							|  |  |  |     var _stripe_test; | 
					
						
							|  |  |  |     var _mandrill; | 
					
						
							|  |  |  |     var _mailchimp; | 
					
						
							|  |  |  |     var _twilio; | 
					
						
							|  |  |  |     var _get_response; | 
					
						
							|  |  |  |     myApp.use('/', function preHandler(req, res, next) { | 
					
						
							|  |  |  |       //if (xconfx.debug) { console.log('[api.js] loading handler prereqs'); }
 | 
					
						
							|  |  |  |       return getSiteConfig(clientUrih).then(function (siteConfig) { | 
					
						
							|  |  |  |         //if (xconfx.debug) { console.log('[api.js] loaded handler site config'); }
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Use getSiteCapability('email@daplie.com') instead
 | 
					
						
							|  |  |  |         Object.defineProperty(req, 'getSiteMailer' /*deprecated*/, { | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSiteMailerProp() { | 
					
						
							|  |  |  |             var nodemailer = require('nodemailer'); | 
					
						
							|  |  |  |             var transport = require('nodemailer-mailgun-transport'); | 
					
						
							|  |  |  |             //var mailconf = require('../../../com.daplie.mailer/config.mailgun');
 | 
					
						
							|  |  |  |             var mailconf = siteConfig['mailgun.org']; | 
					
						
							|  |  |  |             var mailer = PromiseA.promisifyAll(nodemailer.createTransport(transport(mailconf))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return mailer; | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-05-26 23:09:49 +00:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         Object.defineProperty(req, 'getSiteConfig', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSiteConfigProp(section) { | 
					
						
							|  |  |  |             // deprecated
 | 
					
						
							|  |  |  |             if ('com.daplie.tel' === section) { | 
					
						
							|  |  |  |               section = 'tel@daplie.com'; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return PromiseA.resolve((siteConfig || {})[section]); | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         Object.defineProperty(req, 'getSitePackageConfig', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSitePackageConfigProp() { | 
					
						
							|  |  |  |             return getSitePackageConfig(clientUrih, pkgId); | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |         Object.defineProperty(req, 'getSitePackageStore', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: getSitePackageStoreProp | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         Object.defineProperty(req, 'getSiteStore', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSiteStoreProp() { | 
					
						
							|  |  |  |             var restPath = path.join(myConf.restPath, pkgId); | 
					
						
							|  |  |  |             var apiPath = path.join(myConf.apiPath, pkgId); | 
					
						
							|  |  |  |             var dir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // TODO usage package.json as a falback if the standard location is not used
 | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |               dir = require(path.join(apiPath, 'models.js')); | 
					
						
							|  |  |  |             } catch(e) { | 
					
						
							|  |  |  |               dir = require(path.join(restPath, 'models.js')); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-06-01 00:25:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             return getSiteStore(clientUrih, pkgId, dir); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* | 
					
						
							|  |  |  |         Object.defineProperty(req, 'getSitePayments', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSitePaymentsProp() { | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         */ | 
					
						
							|  |  |  |         // TODO allow third-party clients stripe ids destination
 | 
					
						
							|  |  |  |         // https://stripe.com/docs/connect/payments-fees
 | 
					
						
							|  |  |  |         Object.defineProperty(req, 'Stripe', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , get: function () { | 
					
						
							|  |  |  |             _stripe = _stripe || require('stripe')(siteConfig['stripe.com'].live.secret); | 
					
						
							|  |  |  |             return _stripe; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Object.defineProperty(req, 'StripeTest', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , get: function () { | 
					
						
							|  |  |  |             _stripe_test = _stripe_test || require('stripe')(siteConfig['stripe.com'].test.secret); | 
					
						
							|  |  |  |             return _stripe_test; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Object.defineProperty(req, 'Mandrill', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , get: function () { | 
					
						
							|  |  |  |             if (!_mandrill) { | 
					
						
							|  |  |  |               var Mandrill = require('mandrill-api/mandrill'); | 
					
						
							|  |  |  |               _mandrill = new Mandrill.Mandrill(siteConfig['mandrill.com'].apiKey); | 
					
						
							|  |  |  |               _mandrill.messages.sendTemplateAsync = function (opts) { | 
					
						
							|  |  |  |                 return new PromiseA(function (resolve, reject) { | 
					
						
							|  |  |  |                   _mandrill.messages.sendTemplate(opts, resolve, reject); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }; | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             return _mandrill; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Object.defineProperty(req, 'Mailchimp', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , get: function () { | 
					
						
							|  |  |  |             var Mailchimp = require('mailchimp-api-v3'); | 
					
						
							|  |  |  |             _mailchimp = _mailchimp || new Mailchimp(siteConfig['mailchimp.com'].apiKey); | 
					
						
							|  |  |  |             return _mailchimp; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Object.defineProperty(req, 'GetResponse', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , get: function () { | 
					
						
							|  |  |  |             if (_get_response) { | 
					
						
							|  |  |  |               return _get_response; | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             _get_response = { | 
					
						
							|  |  |  |               saveSubscriber: function (email, opts) { | 
					
						
							|  |  |  |                 var config = siteConfig['getresponse@daplie.com']; | 
					
						
							|  |  |  |                 var customFields = []; | 
					
						
							|  |  |  |                 Object.keys(config.customFields).forEach(function (name) { | 
					
						
							|  |  |  |                   if (typeof opts[name] !== 'undefined') { | 
					
						
							|  |  |  |                     customFields.push({ | 
					
						
							|  |  |  |                       customFieldId: config.customFields[name] | 
					
						
							|  |  |  |                     , value: [ String(opts[name]) ] | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 }); | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |                 return request({ | 
					
						
							|  |  |  |                   method: 'POST' | 
					
						
							|  |  |  |                 , url: 'https://api.getresponse.com/v3/contacts' | 
					
						
							|  |  |  |                 , headers: { 'X-Auth-Token': 'api-key ' + config.apiKey } | 
					
						
							|  |  |  |                 , json: true | 
					
						
							|  |  |  |                 , body: { | 
					
						
							|  |  |  |                     name: opts.name | 
					
						
							|  |  |  |                   , email: email | 
					
						
							|  |  |  |                   , ipAddress: opts.ipAddress | 
					
						
							|  |  |  |                   , campaign: { campaignId: config.campaignId } | 
					
						
							|  |  |  |                   , customFieldValues: customFields | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 }).then(function (resp) { | 
					
						
							|  |  |  |                   if (resp.statusCode === 202) { | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                   return PromiseA.reject(resp.body.message); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return _get_response; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         var Twilio = require('twilio'); | 
					
						
							|  |  |  |         function twilioTel(/*opts*/) { | 
					
						
							|  |  |  |           if (_twilio) { | 
					
						
							|  |  |  |             return apiDeps.Promise.resolve(_twilio); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           _twilio = new Twilio.RestClient( | 
					
						
							|  |  |  |             siteConfig['twilio.com'].live.id | 
					
						
							|  |  |  |           , siteConfig['twilio.com'].live.auth | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |           return apiDeps.Promise.resolve(_twilio); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // TODO shared memory db
 | 
					
						
							|  |  |  |         var mailgunTokens = {}; | 
					
						
							|  |  |  |         function validateMailgun(apiKey, timestamp, token, signature) { | 
					
						
							|  |  |  |           // https://gist.github.com/coolaj86/81a3b61353d2f0a2552c
 | 
					
						
							|  |  |  |           // (realized later)
 | 
					
						
							|  |  |  |           // HAHA HAHA HAHAHAHAHA this is my own gist... so much more polite attribution
 | 
					
						
							|  |  |  |           var scmp = require('scmp') | 
					
						
							|  |  |  |             , mailgunExpirey = 15 * 60 * 1000 | 
					
						
							|  |  |  |             , mailgunHashType = 'sha256' | 
					
						
							|  |  |  |             , mailgunSignatureEncoding = 'hex' | 
					
						
							|  |  |  |             ; | 
					
						
							|  |  |  |           var actual | 
					
						
							|  |  |  |             , adjustedTimestamp = parseInt(timestamp, 10) * 1000 | 
					
						
							|  |  |  |             , fresh = (Math.abs(Date.now() - adjustedTimestamp) < mailgunExpirey) | 
					
						
							|  |  |  |             ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (!fresh) { | 
					
						
							|  |  |  |             console.error('[mailgun] Stale Timestamp: this may be an attack'); | 
					
						
							|  |  |  |             console.error('[mailgun] However, this is most likely your fault\n'); | 
					
						
							|  |  |  |             console.error('[mailgun] run `ntpdate ntp.ubuntu.com` and check your system clock\n'); | 
					
						
							|  |  |  |             console.error('[mailgun] System Time: ' + new Date().toString()); | 
					
						
							|  |  |  |             console.error('[mailgun] Mailgun Time: ' + new Date(adjustedTimestamp).toString(), timestamp); | 
					
						
							|  |  |  |             console.error('[mailgun] Delta: ' + (Date.now() - adjustedTimestamp)); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (mailgunTokens[token]) { | 
					
						
							|  |  |  |             console.error('[mailgun] Replay Attack'); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           mailgunTokens[token] = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           setTimeout(function () { | 
					
						
							|  |  |  |             delete mailgunTokens[token]; | 
					
						
							|  |  |  |           }, mailgunExpirey + (5 * 1000)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           actual = crypto.createHmac(mailgunHashType, apiKey) | 
					
						
							|  |  |  |             .update(new Buffer(timestamp + token, 'utf8')) | 
					
						
							|  |  |  |             .digest(mailgunSignatureEncoding) | 
					
						
							|  |  |  |             ; | 
					
						
							|  |  |  |           return scmp(signature, actual); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         function mailgunMail(/*opts*/) { | 
					
						
							|  |  |  |           return apiDeps.Promise.resolve(req.getSiteMailer()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         function getResponseList() { | 
					
						
							|  |  |  |           return apiDeps.Promise.resolve(req.GetResponse); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Twilio Parameters are often 26 long
 | 
					
						
							|  |  |  |         var bodyParserTwilio = require('body-parser').urlencoded({ limit: '4kb', parameterLimit: 100, extended: false }); | 
					
						
							|  |  |  |         // Mailgun has something like 50 parameters
 | 
					
						
							|  |  |  |         var bodyParserMailgun = require('body-parser').urlencoded({ limit: '1024kb', parameterLimit: 500, extended: false }); | 
					
						
							|  |  |  |         function bodyMultiParserMailgun (req, res, next) { | 
					
						
							|  |  |  |           var multiparty = require('multiparty'); | 
					
						
							|  |  |  |           var form = new multiparty.Form(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           form.parse(req, function (err, fields/*, files*/) { | 
					
						
							|  |  |  |             if (err) { | 
					
						
							|  |  |  |               console.error('Error'); | 
					
						
							|  |  |  |               console.error(err); | 
					
						
							|  |  |  |               res.end("Couldn't parse form"); | 
					
						
							| 
									
										
										
										
											2017-06-01 00:25:37 +00:00
										 |  |  |               return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             var body; | 
					
						
							|  |  |  |             req.body = req.body || {}; | 
					
						
							|  |  |  |             Object.keys(fields).forEach(function (key) { | 
					
						
							|  |  |  |               // TODO what if there were two of something?
 | 
					
						
							|  |  |  |               // (even though there won't be)
 | 
					
						
							|  |  |  |               req.body[key] = fields[key][0]; | 
					
						
							| 
									
										
										
										
											2017-07-13 18:23:42 -06:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             body = req.body; | 
					
						
							| 
									
										
										
										
											2017-05-29 21:39:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             next(); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-26 23:09:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         function daplieTel() { | 
					
						
							|  |  |  |           return twilioTel().then(function (twilio) { | 
					
						
							|  |  |  |             function sms(opts) { | 
					
						
							|  |  |  |               // opts = { to, from, body }
 | 
					
						
							|  |  |  |               return new apiDeps.Promise(function (resolve, reject) { | 
					
						
							|  |  |  |                 twilio.sendSms(opts, function (err, resp) { | 
					
						
							|  |  |  |                   if (err) { | 
					
						
							|  |  |  |                     reject(err); | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                   } | 
					
						
							| 
									
										
										
										
											2017-05-26 23:09:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |                   resolve(resp); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-05-26 23:09:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             return { | 
					
						
							|  |  |  |               sms: sms | 
					
						
							|  |  |  |             , mms: function () { throw new Error('MMS Not Implemented'); } | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-26 23:09:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |         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); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         var caps = { | 
					
						
							|  |  |  |           //
 | 
					
						
							|  |  |  |           // Capabilities for APIs
 | 
					
						
							|  |  |  |           //
 | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |           'settings.site@daplie.com': manageSiteSettings | 
					
						
							|  |  |  |         , 'email@daplie.com': mailgunMail     // whichever mailer
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         , 'mailer@daplie.com': mailgunMail    // whichever mailer
 | 
					
						
							|  |  |  |         , 'mailgun@daplie.com': mailgunMail   // specifically mailgun
 | 
					
						
							|  |  |  |         , 'tel@daplie.com': daplieTel         // whichever telephony service
 | 
					
						
							|  |  |  |         , 'twilio@daplie.com': twilioTel      // specifically twilio
 | 
					
						
							|  |  |  |         , 'com.daplie.tel.twilio': twilioTel  // deprecated alias
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         , 'getresponse@daplie.com': getResponseList | 
					
						
							|  |  |  |           //
 | 
					
						
							|  |  |  |           // Webhook Parsers
 | 
					
						
							|  |  |  |           //
 | 
					
						
							|  |  |  |         //, 'mailgun.urlencoded@daplie.com': function (req, res, next) { ... }
 | 
					
						
							|  |  |  |         , 'mailgun.parsers@daplie.com': function (req, res, next) { | 
					
						
							|  |  |  |             var chunks = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             req.on('data', function (chunk) { | 
					
						
							|  |  |  |               chunks.push(chunk); | 
					
						
							| 
									
										
										
										
											2017-05-29 17:35:52 +00:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             req.on('end', function () { | 
					
						
							| 
									
										
										
										
											2017-05-29 18:29:05 +00:00
										 |  |  |             }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             function verify() { | 
					
						
							|  |  |  |               var body = req.body; | 
					
						
							|  |  |  |               var mailconf = siteConfig['mailgun.org']; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               if (!body.timestamp) { | 
					
						
							|  |  |  |                 console.log('mailgun parser req.headers'); | 
					
						
							|  |  |  |                 console.log(req.headers); | 
					
						
							|  |  |  |                 chunks.forEach(function (datum) { | 
					
						
							|  |  |  |                   console.log('Length:', datum.length); | 
					
						
							|  |  |  |                   //console.log(datum.toString('utf8'));
 | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |                 console.log('weird body'); | 
					
						
							|  |  |  |                 console.log(body); | 
					
						
							| 
									
										
										
										
											2017-05-29 18:29:05 +00:00
										 |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |               if (!validateMailgun(mailconf.apiKey, body.timestamp, body.token, body.signature)) { | 
					
						
							|  |  |  |                 console.error('Request came, but not from Mailgun'); | 
					
						
							|  |  |  |                 console.error(req.url); | 
					
						
							|  |  |  |                 console.error(req.headers); | 
					
						
							|  |  |  |                 res.send({ error: { message: 'Invalid signature. Are you even Mailgun?' } }); | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2017-05-29 18:29:05 +00:00
										 |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |               next(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (/urlencoded/.test(req.headers['content-type'])) { | 
					
						
							|  |  |  |               console.log('urlencoded'); | 
					
						
							|  |  |  |               bodyParserMailgun(req, res, verify); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (/multipart/.test(req.headers['content-type'])) { | 
					
						
							|  |  |  |               console.log('multipart'); | 
					
						
							|  |  |  |               bodyMultiParserMailgun(req, res, verify); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |               console.log('no parser'); | 
					
						
							|  |  |  |               next(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         , 'twilio.urlencoded@daplie.com': function (req, res, next) { | 
					
						
							|  |  |  |             // TODO null for res and Promise instead of next?
 | 
					
						
							|  |  |  |             return bodyParserTwilio(req, res, function () { | 
					
						
							|  |  |  |               var signature = req.headers['x-twilio-signature']; | 
					
						
							|  |  |  |               var auth = siteConfig['twilio.com'].live.auth; | 
					
						
							|  |  |  |               var fullUrl = 'https://' + req.headers.host + req._walnutOriginalUrl; | 
					
						
							|  |  |  |               var validSig = Twilio.validateRequest(auth, signature, fullUrl, req.body); | 
					
						
							|  |  |  |               /* | 
					
						
							|  |  |  |               console.log('Twilio Signature Check'); | 
					
						
							|  |  |  |               console.log('auth', auth); | 
					
						
							|  |  |  |               console.log('sig', signature); | 
					
						
							|  |  |  |               console.log('fullUrl', fullUrl); | 
					
						
							|  |  |  |               console.log(req.body); | 
					
						
							|  |  |  |               console.log('valid', validSig); | 
					
						
							|  |  |  |               */ | 
					
						
							|  |  |  |               if (!validSig) { | 
					
						
							|  |  |  |                 res.statusCode = 401; | 
					
						
							|  |  |  |                 res.setHeader('Content-Type', 'text/xml'); | 
					
						
							|  |  |  |                 res.end('<Error>Invalid signature. Are you even Twilio?</Error>'); | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2017-05-29 18:29:05 +00:00
										 |  |  |               } | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |               // TODO session via db req.body.CallId req.body.smsId
 | 
					
						
							|  |  |  |               next(); | 
					
						
							| 
									
										
										
										
											2017-05-29 18:29:05 +00:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |           } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         req.getSiteCapability = function (capname, opts, b, c) { | 
					
						
							|  |  |  |           if (caps[capname]) { | 
					
						
							|  |  |  |             return caps[capname](opts, b, c); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (siteConfig[capname]) { | 
					
						
							|  |  |  |             var service = siteConfig[capname].service || siteConfig[capname]; | 
					
						
							|  |  |  |             if (caps[service]) { | 
					
						
							|  |  |  |               return caps[service](opts, b, c); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           return apiDeps.Promise.reject( | 
					
						
							|  |  |  |             new Error("['" + req.clientApiUri + '/' + pkgId + "'] " | 
					
						
							|  |  |  |               + "capability '" + capname + "' not implemented") | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2017-05-29 17:32:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         req._walnutOriginalUrl = req.url; | 
					
						
							|  |  |  |         // "/path/api/com.example/hello".replace(/.*\/api\//, '').replace(/([^\/]*\/+)/, '/') => '/hello'
 | 
					
						
							|  |  |  |         req.url = req.url.replace(/\/api\//, '').replace(/.*\/api\//, '').replace(/([^\/]*\/+)/, '/'); | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     myApp.use('/public', function preHandler(req, res, next) { | 
					
						
							|  |  |  |       // TODO authenticate or use guest user
 | 
					
						
							|  |  |  |       req.isPublic = true; | 
					
						
							|  |  |  |       next(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     myApp.use('/accounts/:accountId', accountRequiredById); | 
					
						
							|  |  |  |     myApp.use('/acl', accountRequired); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // TODO handle /accounts/:accountId
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     return PromiseA.resolve(pkgRestApi.create({ | 
					
						
							|  |  |  |       etcpath: xconfx.etcpath | 
					
						
							|  |  |  |     }/*pkgConf*/, pkgDeps/*pkgDeps*/, myApp/*myApp*/)).then(function (handler) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       //if (xconfx.debug) { console.log('[api.js] got handler'); }
 | 
					
						
							|  |  |  |       myApp.use('/', function postHandler(req, res, next) { | 
					
						
							|  |  |  |         req.url = req._walnutOriginalUrl; | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-08-04 11:45:33 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       localCache.pkgs[pkgId] = { pkgId: pkgId, pkg: pkg, handler: handler || myApp, createdAt: Date.now() }; | 
					
						
							| 
									
										
										
										
											2017-08-04 11:45:33 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       pkgLinks.forEach(function (pkgLink) { | 
					
						
							|  |  |  |         localCache.pkgs[pkgLink] = localCache.pkgs[pkgId]; | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-08-04 11:45:33 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       return localCache.pkgs[pkgId]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   function loadRestHelperAssets(myConf, clientUrih, pkg, pkgId, pkgPath) { | 
					
						
							|  |  |  |     var myApp; | 
					
						
							|  |  |  |     var pkgDeps = {}; | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |     var pkgRestAssets; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       pkgRestAssets = require(path.join(pkgPath, 'assets.js')); | 
					
						
							|  |  |  |     } catch(e) { | 
					
						
							|  |  |  |       return PromiseA.reject(e); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-06-14 02:26:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     Object.keys(apiDeps).forEach(function (key) { | 
					
						
							|  |  |  |       pkgDeps[key] = apiDeps[key]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     Object.keys(apiFactories).forEach(function (key) { | 
					
						
							|  |  |  |       pkgDeps[key] = apiFactories[key]; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-07-01 03:11:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     // TODO pull db stuff from package.json somehow and pass allowed data models as deps
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // how can we tell which of these would be correct?
 | 
					
						
							|  |  |  |     // deps.memstore = apiFactories.memstoreFactory.create(pkgId);
 | 
					
						
							|  |  |  |     // deps.memstore = apiFactories.memstoreFactory.create(req.experienceId);
 | 
					
						
							|  |  |  |     // deps.memstore = apiFactories.memstoreFactory.create(req.experienceId + pkgId);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // let's go with this one for now and the api can choose to scope or not to scope
 | 
					
						
							|  |  |  |     pkgDeps.memstore = apiFactories.memstoreFactory.create(pkgId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     myApp = express(); | 
					
						
							|  |  |  |     myApp.handlePromise = promisableRequest; | 
					
						
							|  |  |  |     myApp.handleRejection = rejectableRequest; | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |     myApp.grantsRequired = grantsRequired; | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |     function otherGetSitePackageStoreProp(otherPkgId) { | 
					
						
							|  |  |  |       var restPath = path.join(myConf.restPath, otherPkgId); | 
					
						
							|  |  |  |       var apiPath = path.join(myConf.apiPath, otherPkgId); | 
					
						
							|  |  |  |       var dir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // TODO usage package.json as a falback if the standard location is not used
 | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         dir = require(path.join(apiPath, 'models.js')); | 
					
						
							|  |  |  |       } catch(e) { | 
					
						
							|  |  |  |         dir = require(path.join(restPath, 'models.js')); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return getSiteStore(clientUrih, otherPkgId, dir); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     myApp.use('/', function cookieAttachOauth3(req, res, next) { | 
					
						
							|  |  |  |       return otherGetSitePackageStoreProp('issuer@oauth3.org').then(function (Models) { | 
					
						
							|  |  |  |         return require('./oauth3').cookieOauth3(Models, req, res, next); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     myApp.use('/', function (req, res, next) { | 
					
						
							|  |  |  |       console.log('########################################### session ###############################'); | 
					
						
							|  |  |  |       console.log('req.url', req.url); | 
					
						
							|  |  |  |       console.log('req.oauth3', req.oauth3); | 
					
						
							|  |  |  |       next(); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |     function otherAttachOauth3(req, res, next) { | 
					
						
							|  |  |  |       return otherGetSitePackageStoreProp('issuer@oauth3.org').then(function (Models) { | 
					
						
							|  |  |  |         return require('./oauth3').attachOauth3(Models, req, res, next); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     myApp.post('/assets/issuer@oauth3.org/session', otherAttachOauth3, function (req, res) { | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       console.log('get the session'); | 
					
						
							|  |  |  |       console.log(req.url); | 
					
						
							|  |  |  |       console.log("req.cookies:"); | 
					
						
							|  |  |  |       console.log(req.cookies); | 
					
						
							|  |  |  |       console.log("req.oauth3:"); | 
					
						
							|  |  |  |       console.log(req.oauth3); | 
					
						
							|  |  |  |       res.cookie('jwt', req.oauth3.encodedToken, { domain: req.clientAssetsUri, path: '/assets', httpOnly: true }); | 
					
						
							|  |  |  |       //req.url;
 | 
					
						
							|  |  |  |       res.send({ success: true }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-07-05 23:11:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     // TODO delete these caches when config changes
 | 
					
						
							|  |  |  |     myApp.use('/', function preHandler(req, res, next) { | 
					
						
							|  |  |  |       //if (xconfx.debug) { console.log('[api.js] loading handler prereqs'); }
 | 
					
						
							|  |  |  |       return getSiteConfig(clientUrih).then(function (siteConfig) { | 
					
						
							|  |  |  |         //if (xconfx.debug) { console.log('[api.js] loaded handler site config'); }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Object.defineProperty(req, 'getSiteConfig', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSiteConfigProp(section) { | 
					
						
							|  |  |  |             return PromiseA.resolve((siteConfig || {})[section]); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-07-05 23:11:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         Object.defineProperty(req, 'getSitePackageConfig', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSitePackageConfigProp() { | 
					
						
							|  |  |  |             return getSitePackageConfig(clientUrih, pkgId); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-07-10 12:04:45 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         Object.defineProperty(req, 'getSiteStore', { | 
					
						
							|  |  |  |           enumerable: true | 
					
						
							|  |  |  |         , configurable: false | 
					
						
							|  |  |  |         , writable: false | 
					
						
							|  |  |  |         , value: function getSiteStoreProp() { | 
					
						
							|  |  |  |             var restPath = path.join(myConf.restPath, pkgId); | 
					
						
							|  |  |  |             var apiPath = path.join(myConf.apiPath, pkgId); | 
					
						
							|  |  |  |             var dir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // TODO usage package.json as a falback if the standard location is not used
 | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |               dir = require(path.join(apiPath, 'models.js')); | 
					
						
							|  |  |  |             } catch(e) { | 
					
						
							|  |  |  |               dir = require(path.join(restPath, 'models.js')); | 
					
						
							| 
									
										
										
										
											2017-07-06 18:52:19 +00:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             return getSiteStore(clientUrih, pkgId, dir); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-07-05 23:11:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         req._walnutOriginalUrl = req.url; | 
					
						
							|  |  |  |         // "/path/api/com.example/hello".replace(/.*\/api\//, '').replace(/([^\/]*\/+)/, '/') => '/hello'
 | 
					
						
							|  |  |  |         req.url = req.url.replace(/\/(api|assets)\//, '').replace(/.*\/(api|assets)\//, '').replace(/([^\/]*\/+)/, '/'); | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-07-06 18:52:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     myApp.use('/public', function preHandler(req, res, next) { | 
					
						
							|  |  |  |       // TODO authenticate or use guest user
 | 
					
						
							|  |  |  |       req.isPublic = true; | 
					
						
							|  |  |  |       next(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     myApp.use('/accounts/:accountId', accountRequiredById); | 
					
						
							|  |  |  |     myApp.use('/acl', accountRequired); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // TODO handle /accounts/:accountId
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     function myAppWrapper(req, res, next) { | 
					
						
							|  |  |  |       return myApp(req, res, next); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Object.keys(myApp).forEach(function (key) { | 
					
						
							|  |  |  |       myAppWrapper[key] = myApp[key]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     myAppWrapper.use = function () { myApp.use.apply(myApp, arguments); }; | 
					
						
							|  |  |  |     myAppWrapper.get = function () { myApp.get.apply(myApp, arguments); }; | 
					
						
							|  |  |  |     myAppWrapper.post = function () { myApp.use(function (req, res, next) { next(); }); /*throw new Error("assets may not handle POST");*/ }; | 
					
						
							|  |  |  |     myAppWrapper.put = function () { throw new Error("assets may not handle PUT"); }; | 
					
						
							|  |  |  |     myAppWrapper.del = function () { throw new Error("assets may not handle DELETE"); }; | 
					
						
							|  |  |  |     myAppWrapper.delete = function () { throw new Error("assets may not handle DELETE"); }; | 
					
						
							|  |  |  |     return PromiseA.resolve(pkgRestAssets.create({ | 
					
						
							|  |  |  |       etcpath: xconfx.etcpath | 
					
						
							|  |  |  |     }/*pkgConf*/, pkgDeps/*pkgDeps*/, myAppWrapper)).then(function (assetsHandler) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       //if (xconfx.debug) { console.log('[api.js] got handler'); }
 | 
					
						
							|  |  |  |       myApp.use('/', function postHandler(req, res, next) { | 
					
						
							|  |  |  |         req.url = req._walnutOriginalUrl; | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-07-05 23:11:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       return assetsHandler || myApp; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   function loadRestHelper(myConf, clientUrih, pkgId) { | 
					
						
							|  |  |  |     var pkgPath = path.join(myConf.restPath, pkgId); | 
					
						
							| 
									
										
										
										
											2017-06-14 02:26:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |     // TODO allow recursion, but catch cycles
 | 
					
						
							|  |  |  |     return fs.lstatAsync(pkgPath).then(function (stat) { | 
					
						
							|  |  |  |       if (!stat.isFile()) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-05-24 05:25:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       return fs.readFileAsync(pkgPath, 'utf8').then(function (text) { | 
					
						
							|  |  |  |         pkgId = text.trim(); | 
					
						
							|  |  |  |         pkgPath = path.join(myConf.restPath, pkgId); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }, function () { | 
					
						
							|  |  |  |       // ignore error
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     }).then(function () { | 
					
						
							|  |  |  |       // TODO should not require package.json. Should work with files alone.
 | 
					
						
							|  |  |  |       return fs.readFileAsync(path.join(pkgPath, 'package.json'), 'utf8').then(function (text) { | 
					
						
							|  |  |  |         var pkg = JSON.parse(text); | 
					
						
							| 
									
										
										
										
											2017-08-16 19:47:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         return loadRestHelperApi(myConf, clientUrih, pkg, pkgId, pkgPath).then(function (stuff) { | 
					
						
							|  |  |  |           return loadRestHelperAssets(myConf, clientUrih, pkg, pkgId, pkgPath).then(function (assetsHandler) { | 
					
						
							|  |  |  |             stuff.assetsHandler = assetsHandler; | 
					
						
							|  |  |  |             return stuff; | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |           }, function (err) { | 
					
						
							|  |  |  |             console.error('[lib/api.js] no assets handler:'); | 
					
						
							|  |  |  |             console.error(err); | 
					
						
							|  |  |  |             return stuff; | 
					
						
							| 
									
										
										
										
											2017-05-26 23:09:49 +00:00
										 |  |  |           }); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Read packages/apis/sub.sld.tld (forward dns) to find list of apis as tld.sld.sub (reverse dns)
 | 
					
						
							|  |  |  |   // TODO packages/allowed_apis/sub.sld.tld (?)
 | 
					
						
							|  |  |  |   // TODO auto-register org.oauth3.consumer for primaryDomain (and all sites?)
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |   function loadRestHandler(myConf, clientUrih, pkgId) { | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |     return PromiseA.resolve().then(function () { | 
					
						
							|  |  |  |       if (!localCache.pkgs[pkgId]) { | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |         return loadRestHelper(myConf, clientUrih, pkgId); | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       return localCache.pkgs[pkgId]; | 
					
						
							|  |  |  |       // TODO expire require cache
 | 
					
						
							|  |  |  |       /* | 
					
						
							|  |  |  |       if (Date.now() - localCache.pkgs[pkgId].createdAt < (5 * 60 * 1000)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       */ | 
					
						
							|  |  |  |     }, function (/*err*/) { | 
					
						
							|  |  |  |       // TODO what kind of errors might we want to handle?
 | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     }).then(function (restPkg) { | 
					
						
							|  |  |  |       return restPkg; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |   var CORS = require('connect-cors'); | 
					
						
							|  |  |  |   var cors = CORS({ credentials: true, headers: [ | 
					
						
							|  |  |  |     'X-Requested-With' | 
					
						
							|  |  |  |   , 'X-HTTP-Method-Override' | 
					
						
							|  |  |  |   , 'Content-Type' | 
					
						
							|  |  |  |   , 'Accept' | 
					
						
							|  |  |  |   , 'Authorization' | 
					
						
							|  |  |  |   ], methods: [ "GET", "POST", "PATCH", "PUT", "DELETE" ] }); | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |   var staleAfter = (5 * 60 * 1000); | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   return function (req, res, next) { | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |     cors(req, res, function () { | 
					
						
							| 
									
										
										
										
											2017-08-16 19:47:51 +00:00
										 |  |  |       //if (xconfx.debug) { console.log('[api.js] after cors'); }
 | 
					
						
							| 
									
										
										
										
											2017-07-05 02:38:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 04:51:44 +00:00
										 |  |  |       // Canonical client names
 | 
					
						
							|  |  |  |       // example.com should use api.example.com/api for all requests
 | 
					
						
							|  |  |  |       // sub.example.com/api should resolve to sub.example.com
 | 
					
						
							| 
									
										
										
										
											2017-07-13 18:23:42 -06:00
										 |  |  |       // example.com/subapp/api should resolve to example.com#subapp
 | 
					
						
							|  |  |  |       // sub.example.com/subapp/api should resolve to sub.example.com#subapp
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |       var appUri = req.hostname.replace(/^(api|assets)\./, '') + req.url.replace(/\/(api|assets)\/.*/, '/').replace(/\/$/, ''); | 
					
						
							|  |  |  |       var clientUrih = appUri.replace(/\/+/g, '#').replace(/#$/, ''); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       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(/\/$/, ''); | 
					
						
							| 
									
										
										
										
											2017-09-01 00:49:08 +00:00
										 |  |  |       //var clientAssetsUri = req.hostname.replace(/^(api|assets)\./, 'api.') + req.url.replace(/\/(api|assets)\/.*/, '/').replace(/\/$/, '');
 | 
					
						
							| 
									
										
										
										
											2017-05-20 04:51:44 +00:00
										 |  |  |       // 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'
 | 
					
						
							|  |  |  |       // '/subapp/api/com.daplie.hello/' may exist... must be a small api
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       var pkgId = req.url.replace(/.*\/(api|assets)\//, '').replace(/^\//, '').replace(/\/.*/, ''); | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       var now = Date.now(); | 
					
						
							|  |  |  |       var hasBeenHandled = false; | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |       Object.defineProperty(req, 'clientUrl', { | 
					
						
							|  |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							|  |  |  |       , writable: false | 
					
						
							|  |  |  |       , value: (req.headers.referer || ('https://' +  appUri)).replace(/\/$/, '').replace(/\?.*/, '') | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-06-14 02:03:22 +00:00
										 |  |  |       Object.defineProperty(req, 'apiUrlPrefix', { | 
					
						
							|  |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							|  |  |  |       , writable: false | 
					
						
							| 
									
										
										
										
											2017-07-07 17:23:28 +00:00
										 |  |  |       , value: 'https://' + clientApiUri + '/api/' + pkgId | 
					
						
							| 
									
										
										
										
											2017-06-14 02:03:22 +00:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       Object.defineProperty(req, 'assetsUrlPrefix', { | 
					
						
							|  |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							|  |  |  |       , writable: false | 
					
						
							|  |  |  |       , value: 'https://' + clientAssetsUri + '/assets/' + pkgId | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-09-12 22:32:33 +00:00
										 |  |  |       Object.defineProperty(req, 'experienceId' /*deprecated*/, { | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       , writable: false | 
					
						
							|  |  |  |       , value: clientUrih | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-05-30 17:29:14 +00:00
										 |  |  |       Object.defineProperty(req, 'clientApiUri', { | 
					
						
							|  |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							|  |  |  |       , writable: false | 
					
						
							|  |  |  |       , value: clientApiUri | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       Object.defineProperty(req, 'clientAssetsUri', { | 
					
						
							|  |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							|  |  |  |       , writable: false | 
					
						
							|  |  |  |       , value: clientAssetsUri | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-05-20 00:09:48 +00:00
										 |  |  |       Object.defineProperty(req, 'apiId', { | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							|  |  |  |       , writable: false | 
					
						
							|  |  |  |       , value: pkgId | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       Object.defineProperty(req, 'clientUrih', { | 
					
						
							|  |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |       , writable: false | 
					
						
							|  |  |  |         // TODO this identifier may need to be non-deterministic as to transfer if a domain name changes but is still the "same" app
 | 
					
						
							|  |  |  |         // (i.e. a company name change. maybe auto vs manual register - just like oauth3?)
 | 
					
						
							|  |  |  |         // NOTE: probably best to alias the name logically
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       , value: clientUrih | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       Object.defineProperty(req, 'pkgId', { | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |         enumerable: true | 
					
						
							|  |  |  |       , configurable: false | 
					
						
							|  |  |  |       , writable: false | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       , value: pkgId | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       // TODO cache permission (although the FS is already cached, NBD)
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |       var promise = isThisClientAllowedToUseThisPkg(req, xconfx, clientUrih, pkgId).then(function (yes) { | 
					
						
							| 
									
										
										
										
											2017-08-16 19:47:51 +00:00
										 |  |  |         //if (xconfx.debug) { console.log('[api.js] azp is allowed?', yes); }
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |         if (!yes) { | 
					
						
							|  |  |  |           notConfigured(req, res); | 
					
						
							|  |  |  |           return null; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |         function handleWithHandler() { | 
					
						
							|  |  |  |           if (/\/assets\//.test(req.url) || /(^|\.)assets\./.test(req.hostname)) { | 
					
						
							|  |  |  |             if (localCache.assets[pkgId]) { | 
					
						
							|  |  |  |               if ('function' !== typeof localCache.assets[pkgId].handler) { console.log('localCache.assets[pkgId]'); console.log(localCache.assets[pkgId]); } | 
					
						
							|  |  |  |               localCache.assets[pkgId].handler(req, res, next); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |               next(); | 
					
						
							|  |  |  |               return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             localCache.rests[pkgId].handler(req, res, next); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |         if (localCache.rests[pkgId]) { | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |           if (handleWithHandler()) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |           hasBeenHandled = true; | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |           if (now - localCache.rests[pkgId].createdAt > staleAfter) { | 
					
						
							|  |  |  |             localCache.rests[pkgId] = null; | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             localCache.assets[pkgId] = null; | 
					
						
							| 
									
										
										
										
											2017-05-24 07:34:34 +00:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |         if (!localCache.rests[pkgId]) { | 
					
						
							|  |  |  |           //return doesThisPkgExist
 | 
					
						
							| 
									
										
										
										
											2017-05-24 07:34:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 19:47:51 +00:00
										 |  |  |           //if (xconfx.debug) { console.log('[api.js] before rest handler'); }
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |           return loadRestHandler(xconfx, clientUrih, pkgId).then(function (myHandler) { | 
					
						
							|  |  |  |             if (!myHandler) { | 
					
						
							| 
									
										
										
										
											2017-08-16 19:47:51 +00:00
										 |  |  |               //if (xconfx.debug) { console.log('[api.js] not configured'); }
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |               notConfigured(req, res); | 
					
						
							|  |  |  |               return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-05-24 07:34:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |             localCache.rests[pkgId] = { handler: myHandler.handler, createdAt: now }; | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |             localCache.assets[pkgId] = { handler: myHandler.assetsHandler, createdAt: now }; | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |             if (!hasBeenHandled) { | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  |               if (handleWithHandler()) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |               } | 
					
						
							| 
									
										
										
										
											2017-05-26 20:55:18 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:37:28 +00:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-08-30 17:47:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 22:46:03 +00:00
										 |  |  |       rejectableRequest(req, res, promise, "[walnut@daplie.com] load api package"); | 
					
						
							| 
									
										
										
										
											2016-06-08 14:05:10 -04:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-04-09 19:14:00 -04:00
										 |  |  |   }; | 
					
						
							|  |  |  | }; |