| 
									
										
										
										
											2017-02-28 14:55:48 -07:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  | module.exports.dependencies = [ 'OAUTH3', 'storage.owners', 'options.device' ]; | 
					
						
							| 
									
										
										
										
											2017-04-26 20:16:47 -06:00
										 |  |  | module.exports.create = function (deps, conf) { | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |   var scmp = require('scmp'); | 
					
						
							|  |  |  |   var crypto = require('crypto'); | 
					
						
							|  |  |  |   var jwt = require('jsonwebtoken'); | 
					
						
							| 
									
										
										
										
											2017-02-28 14:55:48 -07:00
										 |  |  |   var bodyParser = require('body-parser'); | 
					
						
							|  |  |  |   var jsonParser = bodyParser.json({ | 
					
						
							|  |  |  |     inflate: true, limit: '100kb', reviver: null, strict: true /* type, verify */ | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 19:02:51 -06:00
										 |  |  |   var api = deps.api; | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |   /* | 
					
						
							|  |  |  |   var owners; | 
					
						
							|  |  |  |   deps.storage.owners.on('set', function (_owners) { | 
					
						
							|  |  |  |     owners = _owners; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2017-02-28 14:55:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |   function isAuthorized(req, res, fn) { | 
					
						
							|  |  |  |     var auth = jwt.decode((req.headers.authorization||'').replace(/^bearer\s+/i, '')); | 
					
						
							|  |  |  |     if (!auth) { | 
					
						
							| 
									
										
										
										
											2017-02-28 14:55:48 -07:00
										 |  |  |       res.setHeader('Content-Type', 'application/json;'); | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |       res.end(JSON.stringify({ error: { message: "no token", code: 'E_NO_TOKEN', uri: undefined } })); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var id = crypto.createHash('sha256').update(auth.sub).digest('hex'); | 
					
						
							|  |  |  |     return deps.storage.owners.exists(id).then(function (exists) { | 
					
						
							|  |  |  |       if (!exists) { | 
					
						
							|  |  |  |         res.setHeader('Content-Type', 'application/json;'); | 
					
						
							|  |  |  |         res.end(JSON.stringify({ error: { message: "not authorized", code: 'E_NO_AUTHZ', uri: undefined } })); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  |       req.userId = id; | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |       fn(); | 
					
						
							| 
									
										
										
										
											2017-02-28 14:55:48 -07:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     init: function (req, res) { | 
					
						
							|  |  |  |       jsonParser(req, res, function () { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-18 14:48:49 -06:00
										 |  |  |       return deps.PromiseA.resolve().then(function () { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         console.log('req.body', req.body); | 
					
						
							|  |  |  |         var auth = jwt.decode((req.headers.authorization||'').replace(/^bearer\s+/i, '')); | 
					
						
							|  |  |  |         var token = jwt.decode(req.body.access_token); | 
					
						
							|  |  |  |         var refresh = jwt.decode(req.body.refresh_token); | 
					
						
							|  |  |  |         auth.sub = auth.sub || auth.acx.id; | 
					
						
							|  |  |  |         token.sub = token.sub || token.acx.id; | 
					
						
							|  |  |  |         refresh.sub = refresh.sub || refresh.acx.id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // TODO validate token with issuer, but as-is the sub is already a secret
 | 
					
						
							|  |  |  |         var id = crypto.createHash('sha256').update(auth.sub).digest('hex'); | 
					
						
							|  |  |  |         var tid = crypto.createHash('sha256').update(token.sub).digest('hex'); | 
					
						
							|  |  |  |         var rid = crypto.createHash('sha256').update(refresh.sub).digest('hex'); | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  |         var session = { | 
					
						
							|  |  |  |           access_token: req.body.access_token | 
					
						
							|  |  |  |         , token: token | 
					
						
							|  |  |  |         , refresh_token: req.body.refresh_token | 
					
						
							|  |  |  |         , refresh: refresh | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2017-03-18 14:48:49 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         console.log('ids', id, tid, rid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (req.body.ip_url) { | 
					
						
							|  |  |  |           // TODO set options / GunDB
 | 
					
						
							| 
									
										
										
										
											2017-04-26 20:16:47 -06:00
										 |  |  |           conf.ip_url = req.body.ip_url; | 
					
						
							| 
									
										
										
										
											2017-03-18 14:48:49 -06:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return deps.storage.owners.all().then(function (results) { | 
					
						
							|  |  |  |           console.log('results', results); | 
					
						
							|  |  |  |           var err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // There is no owner yet. First come, first serve.
 | 
					
						
							|  |  |  |           if (!results || !results.length) { | 
					
						
							|  |  |  |             if (tid !== id || rid !== id) { | 
					
						
							|  |  |  |               err = new Error( | 
					
						
							|  |  |  |                 "When creating an owner the Authorization Bearer and Token and Refresh must all match" | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |               return deps.PromiseA.reject(err); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             console.log('no owner, creating'); | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  |             return deps.storage.owners.set(id, session); | 
					
						
							| 
									
										
										
										
											2017-03-18 14:48:49 -06:00
										 |  |  |           } | 
					
						
							|  |  |  |           console.log('has results'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // There are onwers. Is this one of them?
 | 
					
						
							|  |  |  |           if (!results.some(function (token) { | 
					
						
							|  |  |  |             return scmp(id, token.id); | 
					
						
							|  |  |  |           })) { | 
					
						
							|  |  |  |             err = new Error("Authorization token does not belong to an existing owner."); | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |             return deps.PromiseA.reject(err); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-03-18 14:48:49 -06:00
										 |  |  |           console.log('has correct owner'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           // We're adding an owner, unless it already exists
 | 
					
						
							|  |  |  |           if (!results.some(function (token) { | 
					
						
							|  |  |  |             return scmp(tid, token.id); | 
					
						
							|  |  |  |           })) { | 
					
						
							|  |  |  |             console.log('adds new owner with existing owner'); | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  |             return deps.storage.owners.set(id, session); | 
					
						
							| 
									
										
										
										
											2017-03-18 14:48:49 -06:00
										 |  |  |           } | 
					
						
							|  |  |  |         }).then(function () { | 
					
						
							|  |  |  |           res.setHeader('Content-Type', 'application/json;'); | 
					
						
							|  |  |  |           res.end(JSON.stringify({ success: true })); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |       }, function (err) { | 
					
						
							|  |  |  |         res.setHeader('Content-Type', 'application/json;'); | 
					
						
							|  |  |  |         res.end(JSON.stringify({ error: { message: err.message, code: err.code, uri: err.uri } })); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  |   , tunnel: function (req, res) { | 
					
						
							|  |  |  |       isAuthorized(req, res, function () { | 
					
						
							|  |  |  |         jsonParser(req, res, function () { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           console.log('req.body', req.body); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return deps.storage.owners.get(req.userId).then(function (session) { | 
					
						
							|  |  |  |             session.token.id = req.userId; | 
					
						
							| 
									
										
										
										
											2017-04-13 16:50:48 -06:00
										 |  |  |             return api.tunnel(deps, session).then(function () { | 
					
						
							|  |  |  |               res.setHeader('Content-Type', 'application/json;'); | 
					
						
							|  |  |  |               res.end(JSON.stringify({ success: true })); | 
					
						
							|  |  |  |             }, function (err) { | 
					
						
							|  |  |  |               res.setHeader('Content-Type', 'application/json;'); | 
					
						
							|  |  |  |               res.end(JSON.stringify({ error: { message: err.message, code: err.code, uri: err.uri } })); | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  |           }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |   , config: function (req, res) { | 
					
						
							|  |  |  |       isAuthorized(req, res, function () { | 
					
						
							|  |  |  |         if ('POST' !== req.method) { | 
					
						
							|  |  |  |           res.setHeader('Content-Type', 'application/json;'); | 
					
						
							| 
									
										
										
										
											2017-04-27 16:50:03 -06:00
										 |  |  |           res.end(JSON.stringify(deps.recase.snakeCopy(conf))); | 
					
						
							| 
									
										
										
										
											2017-03-02 00:58:45 -07:00
										 |  |  |           return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         jsonParser(req, res, function () { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           console.log('req.body', req.body); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           deps.storage.config.merge(req.body); | 
					
						
							|  |  |  |           deps.storage.config.save(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-18 14:48:49 -06:00
										 |  |  |   , request: function (req, res) { | 
					
						
							|  |  |  |       jsonParser(req, res, function () { | 
					
						
							|  |  |  |       isAuthorized(req, res, function () { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         deps.request({ | 
					
						
							|  |  |  |           method: req.body.method || 'GET' | 
					
						
							|  |  |  |         , url: req.body.url | 
					
						
							|  |  |  |         , headers: req.body.headers | 
					
						
							|  |  |  |         , body: req.body.data | 
					
						
							|  |  |  |         }).then(function (resp) { | 
					
						
							|  |  |  |           if (resp.body instanceof Buffer || 'string' === typeof resp.body) { | 
					
						
							|  |  |  |             resp.body = JSON.parse(resp.body); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return { | 
					
						
							|  |  |  |             statusCode: resp.statusCode | 
					
						
							|  |  |  |           , status: resp.status | 
					
						
							|  |  |  |           , headers: resp.headers | 
					
						
							|  |  |  |           , body: resp.body | 
					
						
							|  |  |  |           , data: resp.data | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |         }).then(function (result) { | 
					
						
							|  |  |  |           res.send(result); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-05 12:49:48 -06:00
										 |  |  |   , _api: api | 
					
						
							| 
									
										
										
										
											2017-02-28 14:55:48 -07:00
										 |  |  |   }; | 
					
						
							|  |  |  | }; |