forked from coolaj86/walnut.js
		
	enable assets subdomain with cookies
This commit is contained in:
		
							parent
							
								
									babfb6b38b
								
							
						
					
					
						commit
						a429e48977
					
				
							
								
								
									
										1265
									
								
								lib/apis.js
									
									
									
									
									
								
							
							
						
						
									
										1265
									
								
								lib/apis.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										26
									
								
								lib/main.js
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								lib/main.js
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| module.exports.create = function (app, xconfx, apiFactories, apiDeps, errorIfApi) { | module.exports.create = function (app, xconfx, apiFactories, apiDeps, errorIfApi, errorIfAssets) { | ||||||
|   var PromiseA = require('bluebird'); |   var PromiseA = require('bluebird'); | ||||||
|   var path = require('path'); |   var path = require('path'); | ||||||
|   var fs = PromiseA.promisifyAll(require('fs')); |   var fs = PromiseA.promisifyAll(require('fs')); | ||||||
| @ -293,10 +293,27 @@ module.exports.create = function (app, xconfx, apiFactories, apiDeps, errorIfApi | |||||||
|   // TODO handle assets.example.com/sub/assets/com.example.xyz/
 |   // TODO handle assets.example.com/sub/assets/com.example.xyz/
 | ||||||
| 
 | 
 | ||||||
|   app.use('/api', require('connect-send-error').error()); |   app.use('/api', require('connect-send-error').error()); | ||||||
|  |   app.use('/assets', require('connect-send-error').error()); | ||||||
|   app.use('/', function (req, res, next) { |   app.use('/', function (req, res, next) { | ||||||
|     // If this doesn't look like an API we can move along
 |     // If this doesn't look like an API or assets we can move along
 | ||||||
|     if (!/\/api(\/|$)/.test(req.url)) { | 
 | ||||||
|       // /^api\./.test(req.hostname) &&
 |     /* | ||||||
|  |     console.log('.'); | ||||||
|  |     console.log('[main.js] req.url, req.hostname'); | ||||||
|  |     console.log(req.url); | ||||||
|  |     console.log(req.hostname); | ||||||
|  |     console.log('.'); | ||||||
|  |     */ | ||||||
|  | 
 | ||||||
|  |     if (!/\/(api|assets)(\/|$)/.test(req.url)) { | ||||||
|  |       //console.log('[main.js] api|assets');
 | ||||||
|  |       next(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // keep https://assets.example.com/assets but skip https://example.com/assets
 | ||||||
|  |     if (/\/assets(\/|$)/.test(req.url) && !/(^|\.)(api|assets)(\.)/.test(req.hostname) && !/^[0-9\.]+$/.test(req.hostname)) { | ||||||
|  |       //console.log('[main.js] skip');
 | ||||||
|       next(); |       next(); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| @ -325,6 +342,7 @@ module.exports.create = function (app, xconfx, apiFactories, apiDeps, errorIfApi | |||||||
|     return; |     return; | ||||||
|   }); |   }); | ||||||
|   app.use('/', errorIfApi); |   app.use('/', errorIfApi); | ||||||
|  |   app.use('/', errorIfAssets); | ||||||
|   app.use('/', serveStatic); |   app.use('/', serveStatic); | ||||||
|   app.use('/', serveApps); |   app.use('/', serveApps); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -181,6 +181,50 @@ function deepFreeze(obj) { | |||||||
|   Object.freeze(obj); |   Object.freeze(obj); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function cookieOauth3(req, res, next) { | ||||||
|  |   req.oauth3 = {}; | ||||||
|  | 
 | ||||||
|  |   var token = req.cookies.jwt; | ||||||
|  | 
 | ||||||
|  |   req.oauth3.encodedToken = token; | ||||||
|  |   req.oauth3.verifyAsync = function (jwt) { | ||||||
|  |     return verifyToken(jwt || token); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return verifyToken(token).then(function  (decoded) { | ||||||
|  |     req.oauth3.token = decoded; | ||||||
|  |     if (!decoded) { | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     var ppid = decoded.sub || decoded.ppid || decoded.appScopedId; | ||||||
|  |     req.oauth3.ppid = ppid; | ||||||
|  |     req.oauth3.accountIdx = ppid+'@'+decoded.iss; | ||||||
|  | 
 | ||||||
|  |     var hash = require('crypto').createHash('sha256').update(req.oauth3.accountIdx).digest('base64'); | ||||||
|  |     hash = hash.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+/g, ''); | ||||||
|  |     req.oauth3.accountHash = hash; | ||||||
|  | 
 | ||||||
|  |     req.oauth3.rescope = function (sub) { | ||||||
|  |       // TODO: this function is supposed to convert PPIDs of different parties to some account
 | ||||||
|  |       // ID that allows application to keep track of permisions and what-not.
 | ||||||
|  |       return PromiseA.resolve(sub || hash); | ||||||
|  |     }; | ||||||
|  |   }).then(function () { | ||||||
|  |     deepFreeze(req.oauth3); | ||||||
|  |     //Object.defineProperty(req, 'oauth3', {configurable: false, writable: false});
 | ||||||
|  |     next(); | ||||||
|  |   }, function (err) { | ||||||
|  |     if ('E_NO_TOKEN' === err.code) { | ||||||
|  |       next(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     console.error('[walnut] cookie lib/oauth3 error:'); | ||||||
|  |     console.error(err); | ||||||
|  |     res.send(err); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function attachOauth3(req, res, next) { | function attachOauth3(req, res, next) { | ||||||
|   req.oauth3 = {}; |   req.oauth3 = {}; | ||||||
| 
 | 
 | ||||||
| @ -215,14 +259,15 @@ function attachOauth3(req, res, next) { | |||||||
|     }; |     }; | ||||||
|   }).then(function () { |   }).then(function () { | ||||||
|     deepFreeze(req.oauth3); |     deepFreeze(req.oauth3); | ||||||
|     Object.defineProperty(req, 'oauth3', {configurable: false, writable: false}); |     //Object.defineProperty(req, 'oauth3', {configurable: false, writable: false});
 | ||||||
|     next(); |     next(); | ||||||
|   }, function (err) { |   }, function (err) { | ||||||
|     console.error('[walnut] lib/oauth3 error:'); |     console.error('[walnut] JWT lib/oauth3 error:'); | ||||||
|     console.error(err); |     console.error(err); | ||||||
|     res.send(err); |     res.send(err); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports.attachOauth3 = attachOauth3; | module.exports.attachOauth3 = attachOauth3; | ||||||
|  | module.exports.cookieOauth3 = cookieOauth3; | ||||||
| module.exports.verifyToken = verifyToken; | module.exports.verifyToken = verifyToken; | ||||||
|  | |||||||
| @ -150,6 +150,10 @@ module.exports.create = function (webserver, xconfx, state) { | |||||||
|             models: models |             models: models | ||||||
|             // TODO don't let packages use this directly
 |             // TODO don't let packages use this directly
 | ||||||
|           , Promise: PromiseA |           , Promise: PromiseA | ||||||
|  |           , dns: PromiseA.promisifyAll(require('dns')) | ||||||
|  |           , crypto: PromiseA.promisifyAll(require('crypto')) | ||||||
|  |           , fs: PromiseA.promisifyAll(require('fs')) | ||||||
|  |           , path: require('path') | ||||||
|           }; |           }; | ||||||
|           var apiFactories = { |           var apiFactories = { | ||||||
|             memstoreFactory: { create: scopeMemstore } |             memstoreFactory: { create: scopeMemstore } | ||||||
| @ -180,7 +184,7 @@ module.exports.create = function (webserver, xconfx, state) { | |||||||
|           function setupMain() { |           function setupMain() { | ||||||
|             if (xconfx.debug) { console.log('[main] setup'); } |             if (xconfx.debug) { console.log('[main] setup'); } | ||||||
|             mainApp = express(); |             mainApp = express(); | ||||||
|             require('./main').create(mainApp, xconfx, apiFactories, apiDeps, errorIfApi).then(function () { |             require('./main').create(mainApp, xconfx, apiFactories, apiDeps, errorIfApi, errorIfAssets).then(function () { | ||||||
|               if (xconfx.debug) { console.log('[main] ready'); } |               if (xconfx.debug) { console.log('[main] ready'); } | ||||||
|               // TODO process.send({});
 |               // TODO process.send({});
 | ||||||
|             }); |             }); | ||||||
| @ -225,6 +229,24 @@ module.exports.create = function (webserver, xconfx, state) { | |||||||
|             next(); |             next(); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|  |           function errorIfNotAssets(req, res, next) { | ||||||
|  |             var hostname = req.hostname || req.headers.host; | ||||||
|  | 
 | ||||||
|  |             if (!/^assets\.[a-z0-9\-]+/.test(hostname)) { | ||||||
|  |               res.send({ error: | ||||||
|  |                { message: "['" + hostname + req.url + "'] protected asset access is restricted to proper 'asset'-prefixed lowercase subdomains." | ||||||
|  |                    + " The HTTP 'Host' header must exist and must begin with 'assets.' as in 'assets.example.com'." | ||||||
|  |                    + " For development you may test with assets.localhost.daplie.me (or any domain by modifying your /etc/hosts)" | ||||||
|  |                , code: 'E_NOT_API' | ||||||
|  |                , _hostname: hostname | ||||||
|  |                } | ||||||
|  |               }); | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             next(); | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|           function errorIfApi(req, res, next) { |           function errorIfApi(req, res, next) { | ||||||
|             if (!/^api\./.test(req.headers.host)) { |             if (!/^api\./.test(req.headers.host)) { | ||||||
|               next(); |               next(); | ||||||
| @ -240,7 +262,25 @@ module.exports.create = function (webserver, xconfx, state) { | |||||||
|               return; |               return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             res.send({ error: { code: 'E_NO_IMPL', message: "not implemented" } }); |             res.send({ error: { code: 'E_NO_IMPL', message: "API not implemented" } }); | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           function errorIfAssets(req, res, next) { | ||||||
|  |             if (!/^assets\./.test(req.headers.host)) { | ||||||
|  |               next(); | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // has api. hostname prefix
 | ||||||
|  | 
 | ||||||
|  |             // doesn't have /api url prefix
 | ||||||
|  |             if (!/^\/assets\//.test(req.url)) { | ||||||
|  |               console.log('[walnut/worker assets] req.url', req.url); | ||||||
|  |               res.send({ error: { message: "missing /assets/ url prefix" } }); | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             res.send({ error: { code: 'E_NO_IMPL', message: "assets handler not implemented" } }); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           app.disable('x-powered-by'); |           app.disable('x-powered-by'); | ||||||
| @ -258,8 +298,11 @@ module.exports.create = function (webserver, xconfx, state) { | |||||||
|           })); |           })); | ||||||
|           app.use('/api', recase); |           app.use('/api', recase); | ||||||
| 
 | 
 | ||||||
|  |           var cookieParser = require('cookie-parser'); // signing is done in JWT
 | ||||||
|  | 
 | ||||||
|           app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); |           app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); | ||||||
|           app.use('/api', errorIfNotApi); |           app.use('/api', errorIfNotApi); | ||||||
|  |           app.use('/assets', /*errorIfNotAssets,*/ cookieParser()); // serializer { path: '/assets', httpOnly: true, sameSite: true/*, domain: assets.example.com*/ }
 | ||||||
|           app.use('/', function (req, res) { |           app.use('/', function (req, res) { | ||||||
|             if (!(req.encrypted || req.secure)) { |             if (!(req.encrypted || req.secure)) { | ||||||
|               // did not come from https
 |               // did not come from https
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user