diff --git a/lib/cartodb/api/auth_api.js b/lib/cartodb/api/auth_api.js index 484d66b1..562614c3 100644 --- a/lib/cartodb/api/auth_api.js +++ b/lib/cartodb/api/auth_api.js @@ -19,22 +19,22 @@ function AuthApi(pgConnection, metadataBackend, mapStore, templateMaps) { module.exports = AuthApi; -// Check if a request is authorized by a signer +// Check if the user is authorized by a signer // -// @param req express request object +// @param res express response object // @param callback function(err, signed_by) signed_by will be // null if the request is not signed by anyone // or will be a string cartodb username otherwise. // -AuthApi.prototype.authorizedBySigner = function(req, callback) { - if ( ! req.params.token || ! req.params.signer ) { +AuthApi.prototype.authorizedBySigner = function(res, callback) { + if ( ! res.locals.token || ! res.locals.signer ) { return callback(null, false); // no signer requested } var self = this; - var layergroup_id = req.params.token; - var auth_token = req.params.auth_token; + var layergroup_id = res.locals.token; + var auth_token = res.locals.auth_token; this.mapStore.load(layergroup_id, function(err, mapConfig) { if (err) { @@ -84,11 +84,12 @@ AuthApi.prototype.authorizedByAPIKey = function(user, req, callback) { * Check access authorization * * @param req - standard req object. Importantly contains table and host information + * @param res - standard res object. Contains the auth parameters in locals * @param callback function(err, allowed) is access allowed not? */ -AuthApi.prototype.authorize = function(req, callback) { +AuthApi.prototype.authorize = function(req, res, callback) { var self = this; - var user = req.context.user; + var user = res.locals.user; step( function () { @@ -101,11 +102,11 @@ AuthApi.prototype.authorize = function(req, callback) { // if not authorized by api_key, continue if (!authorized) { // not authorized by api_key, check if authorized by signer - return self.authorizedBySigner(req, this); + return self.authorizedBySigner(res, this); } // authorized by api key, login as the given username and stop - self.pgConnection.setDBAuth(user, req.params, function(err) { + self.pgConnection.setDBAuth(user, res.locals, function(err) { callback(err, true); // authorized (or error) }); }, @@ -120,7 +121,7 @@ AuthApi.prototype.authorize = function(req, callback) { // if no signer name was given, let dbparams and // PostgreSQL do the rest. // - if ( ! req.params.signer ) { + if ( ! res.locals.signer ) { return callback(null, true); // authorized so far } @@ -128,7 +129,7 @@ AuthApi.prototype.authorize = function(req, callback) { return callback(null, false); } - self.pgConnection.setDBAuth(user, req.params, function(err) { + self.pgConnection.setDBAuth(user, res.locals, function(err) { req.profiler.done('setDBAuth'); callback(err, true); // authorized (or error) }); diff --git a/lib/cartodb/backends/dataview.js b/lib/cartodb/backends/dataview.js index 29dcd903..b6037ae6 100644 --- a/lib/cartodb/backends/dataview.js +++ b/lib/cartodb/backends/dataview.js @@ -24,7 +24,7 @@ module.exports = DataviewBackend; DataviewBackend.prototype.getDataview = function (mapConfigProvider, user, params, callback) { - var dataviewName = params.dataviewName; + var dataviewName = params.dataviewName; step( function getMapConfig() { mapConfigProvider.getMapConfig(this); @@ -113,9 +113,7 @@ function getOverrideParams(params, ownFilter) { return overrideParams; } -DataviewBackend.prototype.search = function (mapConfigProvider, user, params, callback) { - var dataviewName = params.dataviewName; - +DataviewBackend.prototype.search = function (mapConfigProvider, user, dataviewName, params, callback) { step( function getMapConfig() { mapConfigProvider.getMapConfig(this); diff --git a/lib/cartodb/controllers/analyses.js b/lib/cartodb/controllers/analyses.js index eb5f5576..7aabc11b 100644 --- a/lib/cartodb/controllers/analyses.js +++ b/lib/cartodb/controllers/analyses.js @@ -37,11 +37,11 @@ AnalysesController.prototype.sendResponse = function(req, res, resource) { AnalysesController.prototype.catalog = function (req, res, next) { var self = this; - var username = req.context.user; + var username = res.locals.user; step( function catalogQuery() { - var pg = new PSQL(dbParamsFromReqParams(req.params)); + var pg = new PSQL(dbParamsFromReqParams(res.locals)); getMetadata(username, pg, this); }, function prepareResponse(err, results) { diff --git a/lib/cartodb/controllers/layergroup.js b/lib/cartodb/controllers/layergroup.js index cdeadc74..f83ffb82 100644 --- a/lib/cartodb/controllers/layergroup.js +++ b/lib/cartodb/controllers/layergroup.js @@ -169,7 +169,7 @@ LayergroupController.prototype.analysisNodeStatus = function(req, res, next) { step( function retrieveNodeStatus() { - self.analysisStatusBackend.getNodeStatus(req.params, this); + self.analysisStatusBackend.getNodeStatus(res.locals, this); }, function finish(err, nodeStatus, stats) { req.profiler.add(stats || {}); @@ -193,9 +193,14 @@ LayergroupController.prototype.dataview = function(req, res, next) { step( function retrieveDataview() { var mapConfigProvider = new MapStoreMapConfigProvider( - self.mapStore, req.context.user, self.userLimitsApi, req.params + self.mapStore, res.locals.user, self.userLimitsApi, res.locals + ); + self.dataviewBackend.getDataview( + mapConfigProvider, + res.locals.user, + res.locals, + this ); - self.dataviewBackend.getDataview(mapConfigProvider, req.context.user, req.params, this); }, function finish(err, dataview, stats) { req.profiler.add(stats || {}); @@ -216,9 +221,9 @@ LayergroupController.prototype.dataviewSearch = function(req, res, next) { step( function searchDataview() { var mapConfigProvider = new MapStoreMapConfigProvider( - self.mapStore, req.context.user, self.userLimitsApi, req.params + self.mapStore, res.locals.user, self.userLimitsApi, res.locals ); - self.dataviewBackend.search(mapConfigProvider, req.context.user, req.params, this); + self.dataviewBackend.search(mapConfigProvider, res.locals.user, req.params.dataviewName, res.locals, this); }, function finish(err, searchResult, stats) { req.profiler.add(stats || {}); @@ -242,9 +247,9 @@ LayergroupController.prototype.attributes = function(req, res, next) { step( function retrieveFeatureAttributes() { var mapConfigProvider = new MapStoreMapConfigProvider( - self.mapStore, req.context.user, self.userLimitsApi, req.params + self.mapStore, res.locals.user, self.userLimitsApi, res.locals ); - self.attributesBackend.getFeatureAttributes(mapConfigProvider, req.params, false, this); + self.attributesBackend.getFeatureAttributes(mapConfigProvider, res.locals, false, this); }, function finish(err, tile, stats) { req.profiler.add(stats || {}); @@ -278,7 +283,7 @@ LayergroupController.prototype.tileOrLayer = function (req, res, next) { step( function mapController$getTileOrGrid() { self.tileBackend.getTile( - new MapStoreMapConfigProvider(self.mapStore, req.context.user, self.userLimitsApi, req.params), + new MapStoreMapConfigProvider(self.mapStore, res.locals.user, self.userLimitsApi, res.locals), req.params, this ); }, @@ -350,8 +355,8 @@ LayergroupController.prototype.center = function(req, res, next) { LayergroupController.prototype.staticMap = function(req, res, width, height, zoom /* bounds */, center, next) { var format = req.params.format === 'jpg' ? 'jpeg' : 'png'; - req.params.layer = req.params.layer || 'all'; req.params.format = req.params.format || 'png'; + res.locals.layer = res.locals.layer || 'all'; var self = this; @@ -359,11 +364,11 @@ LayergroupController.prototype.staticMap = function(req, res, width, height, zoo function getImage() { if (center) { self.previewBackend.getImage( - new MapStoreMapConfigProvider(self.mapStore, req.context.user, self.userLimitsApi, req.params), + new MapStoreMapConfigProvider(self.mapStore, res.locals.user, self.userLimitsApi, res.locals), format, width, height, zoom, center, this); } else { self.previewBackend.getImage( - new MapStoreMapConfigProvider(self.mapStore, req.context.user, self.userLimitsApi, req.params), + new MapStoreMapConfigProvider(self.mapStore, res.locals.user, self.userLimitsApi, res.locals), format, width, height, zoom /* bounds */, this); } }, @@ -391,18 +396,18 @@ LayergroupController.prototype.sendResponse = function(req, res, body, status, h // Set Last-Modified header var lastUpdated; - if (req.params.cache_buster) { + if (res.locals.cache_buster) { // Assuming cache_buster is a timestamp - lastUpdated = new Date(parseInt(req.params.cache_buster)); + lastUpdated = new Date(parseInt(res.locals.cache_buster)); } else { lastUpdated = new Date(); } res.set('Last-Modified', lastUpdated.toUTCString()); - var dbName = req.params.dbname; + var dbName = res.locals.dbname; step( function getAffectedTables() { - self.getAffectedTables(req.context.user, dbName, req.params.token, this); + self.getAffectedTables(res.locals.user, dbName, res.locals.token, this); }, function sendResponse(err, affectedTables) { req.profiler.done('affectedTables'); diff --git a/lib/cartodb/controllers/map.js b/lib/cartodb/controllers/map.js index 661cdb39..f2e86d13 100644 --- a/lib/cartodb/controllers/map.js +++ b/lib/cartodb/controllers/map.js @@ -94,11 +94,11 @@ MapController.prototype.register = function(app) { MapController.prototype.createGet = function(req, res, next){ req.profiler.start('windshaft.createmap_get'); - this.create(req, res, function createGet$prepareConfig(req) { - if ( ! req.params.config ) { + this.create(req, res, function createGet$prepareConfig(req, config) { + if ( ! config ) { throw new Error('layergroup GET needs a "config" parameter'); } - return JSON.parse(req.params.config); + return JSON.parse(config); }, next); }; @@ -155,34 +155,35 @@ MapController.prototype.create = function(req, res, prepareConfigFn, next) { step( function prepareConfig () { - const requestMapConfig = prepareConfigFn(req); + const requestMapConfig = prepareConfigFn(req, res.locals.config); return requestMapConfig; }, function prepareAdapterMapConfig(err, requestMapConfig) { assert.ifError(err); context.analysisConfiguration = { - user: req.context.user, + user: res.locals.user, db: { - host: req.params.dbhost, - port: req.params.dbport, - dbname: req.params.dbname, - user: req.params.dbuser, - pass: req.params.dbpassword + host: res.locals.dbhost, + port: res.locals.dbport, + dbname: res.locals.dbname, + user: res.locals.dbuser, + pass: res.locals.dbpassword }, batch: { - username: req.context.user, - apiKey: req.params.api_key + username: res.locals.user, + apiKey: res.locals.api_key } }; - self.mapConfigAdapter.getMapConfig(req.context.user, requestMapConfig, req.params, context, this); + self.mapConfigAdapter.getMapConfig(res.locals.user, requestMapConfig, res.locals, context, this); }, function createLayergroup(err, requestMapConfig) { assert.ifError(err); var datasource = context.datasource || Datasource.EmptyDatasource(); mapConfig = new MapConfig(requestMapConfig, datasource); self.mapBackend.createLayergroup( - mapConfig, req.params, - new CreateLayergroupMapConfigProvider(mapConfig, req.context.user, self.userLimitsApi, req.params), + mapConfig, + res.locals, + new CreateLayergroupMapConfigProvider(mapConfig, res.locals.user, self.userLimitsApi, res.locals), this ); }, @@ -214,8 +215,8 @@ MapController.prototype.create = function(req, res, prepareConfigFn, next) { next(err); } else { var analysesResults = context.analysesResults || []; - self.addDataviewsAndWidgetsUrls(req.context.user, layergroup, mapConfig.obj()); - self.addAnalysesMetadata(req.context.user, layergroup, analysesResults, true); + self.addDataviewsAndWidgetsUrls(res.locals.user, layergroup, mapConfig.obj()); + self.addAnalysesMetadata(res.locals.user, layergroup, analysesResults, true); addContextMetadata(layergroup, mapConfig.obj(), context); res.set('X-Layergroup-Id', layergroup.layergroupid); self.send(req, res, layergroup, 200); @@ -238,7 +239,7 @@ function addContextMetadata(layergroup, mapConfig, context) { MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn, next) { var self = this; - var cdbuser = req.context.user; + var cdbuser = res.locals.user; var mapConfigProvider; var mapConfig; @@ -257,8 +258,8 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn cdbuser, req.params.template_id, templateParams, - req.query.auth_token, - req.params + res.locals.auth_token, + res.locals ); mapConfigProvider.getMapConfig(this); }, @@ -303,7 +304,7 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, layergroup, analysesResults, callback) { var self = this; - var username = req.context.user; + var username = res.locals.user; var tasksleft = 2; // redis key and affectedTables var errors = []; @@ -344,7 +345,7 @@ function(req, res, mapconfig, layergroup, analysesResults, callback) { } }); - var dbName = req.params.dbname; + var dbName = res.locals.dbname; var layergroupId = layergroup.layergroupid; var dbConnection; diff --git a/lib/cartodb/controllers/named_maps.js b/lib/cartodb/controllers/named_maps.js index 3898b0c7..759ae4b6 100644 --- a/lib/cartodb/controllers/named_maps.js +++ b/lib/cartodb/controllers/named_maps.js @@ -47,7 +47,7 @@ NamedMapsController.prototype.register = function(app) { }; NamedMapsController.prototype.sendResponse = function(req, res, resource, headers, namedMapProvider) { - this.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(req.context.user, namedMapProvider.getTemplateName())); + this.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(res.locals.user, namedMapProvider.getTemplateName())); res.set('Content-Type', headers['content-type'] || headers['Content-Type'] || 'image/png'); res.set('Cache-Control', 'public,max-age=7200,must-revalidate'); @@ -87,7 +87,7 @@ NamedMapsController.prototype.sendResponse = function(req, res, resource, header NamedMapsController.prototype.tile = function(req, res, next) { var self = this; - var cdbUser = req.context.user; + var cdbUser = res.locals.user; var namedMapProvider; step( @@ -97,7 +97,7 @@ NamedMapsController.prototype.tile = function(req, res, next) { req.params.template_id, req.query.config, req.query.auth_token, - req.params, + res.locals, this ); }, @@ -121,11 +121,11 @@ NamedMapsController.prototype.tile = function(req, res, next) { NamedMapsController.prototype.staticMap = function(req, res, next) { var self = this; - var cdbUser = req.context.user; + var cdbUser = res.locals.user; var format = req.params.format === 'jpg' ? 'jpeg' : 'png'; - req.params.format = req.params.format || 'png'; - req.params.layer = req.params.layer || 'all'; + res.locals.format = req.params.format || 'png'; + res.locals.layer = res.locals.layer || 'all'; var namedMapProvider; step( @@ -135,7 +135,7 @@ NamedMapsController.prototype.staticMap = function(req, res, next) { req.params.template_id, req.query.config, req.query.auth_token, - req.params, + res.locals, this ); }, @@ -143,12 +143,12 @@ NamedMapsController.prototype.staticMap = function(req, res, next) { assert.ifError(err); namedMapProvider = _namedMapProvider; - - self.prepareLayerFilterFromPreviewLayers(cdbUser, req, namedMapProvider, this); + + self.prepareLayerFilterFromPreviewLayers(cdbUser, req, res.locals, namedMapProvider, this); }, function prepareImageOptions(err) { assert.ifError(err); - self.getStaticImageOptions(cdbUser, req.params, namedMapProvider, this); + self.getStaticImageOptions(cdbUser, res.locals, namedMapProvider, this); }, function getImage(err, imageOpts) { assert.ifError(err); @@ -191,7 +191,13 @@ NamedMapsController.prototype.staticMap = function(req, res, next) { ); }; -NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function (user, req, namedMapProvider, callback) { +NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function ( + user, + req, + params, + namedMapProvider, + callback +) { var self = this; namedMapProvider.getTemplate(function (err, template) { if (err) { @@ -216,7 +222,7 @@ NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function (us } // overwrites 'all' default filter - req.params.layer = layerVisibilityFilter.join(','); + params.layer = layerVisibilityFilter.join(','); // recreates the provider self.namedMapProviderCache.get( @@ -224,7 +230,7 @@ NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function (us req.params.template_id, req.query.config, req.query.auth_token, - req.params, + params, callback ); }); diff --git a/lib/cartodb/controllers/named_maps_admin.js b/lib/cartodb/controllers/named_maps_admin.js index 411beb35..ae57ada3 100644 --- a/lib/cartodb/controllers/named_maps_admin.js +++ b/lib/cartodb/controllers/named_maps_admin.js @@ -71,7 +71,7 @@ NamedMapsAdminController.prototype.register = function (app) { NamedMapsAdminController.prototype.create = function(req, res, next) { var self = this; - var cdbuser = req.context.user; + var cdbuser = res.locals.user; step( function checkPerms(){ @@ -95,7 +95,7 @@ NamedMapsAdminController.prototype.create = function(req, res, next) { NamedMapsAdminController.prototype.update = function(req, res, next) { var self = this; - var cdbuser = req.context.user; + var cdbuser = res.locals.user; var template; var tpl_id; @@ -126,7 +126,7 @@ NamedMapsAdminController.prototype.retrieve = function(req, res, next) { req.profiler.start('windshaft-cartodb.get_template'); - var cdbuser = req.context.user; + var cdbuser = res.locals.user; var tpl_id; step( function checkPerms(){ @@ -160,7 +160,7 @@ NamedMapsAdminController.prototype.destroy = function(req, res, next) { req.profiler.start('windshaft-cartodb.delete_template'); - var cdbuser = req.context.user; + var cdbuser = res.locals.user; var tpl_id; step( function checkPerms(){ @@ -185,7 +185,7 @@ NamedMapsAdminController.prototype.list = function(req, res, next) { var self = this; req.profiler.start('windshaft-cartodb.get_template_list'); - var cdbuser = req.context.user; + var cdbuser = res.locals.user; step( function checkPerms(){ diff --git a/lib/cartodb/middleware/allow-query-params.js b/lib/cartodb/middleware/allow-query-params.js index 04a27033..7ec31d74 100644 --- a/lib/cartodb/middleware/allow-query-params.js +++ b/lib/cartodb/middleware/allow-query-params.js @@ -3,7 +3,7 @@ module.exports = function allowQueryParams(params) { throw new Error('allowQueryParams must receive an Array of params'); } return function allowQueryParamsMiddleware(req, res, next) { - req.context.allowedQueryParams = params; + res.locals.allowedQueryParams = params; next(); }; }; diff --git a/lib/cartodb/middleware/context/authorize.js b/lib/cartodb/middleware/context/authorize.js index bf95a78a..a42b5407 100644 --- a/lib/cartodb/middleware/context/authorize.js +++ b/lib/cartodb/middleware/context/authorize.js @@ -1,15 +1,8 @@ -const _ = require('underscore'); - module.exports = function authorizeMiddleware (authApi) { return function (req, res, next) { - // FIXME: Temporary hack to share data between middlewares. Express overrides req.params to - // parse url params to an object and it's performed after matching path and controller. - res.locals = {}; - _.extend(res.locals, req.params); - req.profiler.done('req2params.setup'); - authApi.authorize(req, (err, authorized) => { + authApi.authorize(req, res, (err, authorized) => { req.profiler.done('authorize'); if (err) { return next(err); diff --git a/lib/cartodb/middleware/context/clean-up-query-params.js b/lib/cartodb/middleware/context/clean-up-query-params.js index 7b0b56eb..280fe986 100644 --- a/lib/cartodb/middleware/context/clean-up-query-params.js +++ b/lib/cartodb/middleware/context/clean-up-query-params.js @@ -18,15 +18,15 @@ module.exports = function cleanUpQueryParamsMiddleware () { return function cleanUpQueryParams (req, res, next) { var allowedQueryParams = REQUEST_QUERY_PARAMS_WHITELIST; - if (Array.isArray(req.context.allowedQueryParams)) { - allowedQueryParams = allowedQueryParams.concat(req.context.allowedQueryParams); + if (Array.isArray(res.locals.allowedQueryParams)) { + allowedQueryParams = allowedQueryParams.concat(res.locals.allowedQueryParams); } req.query = _.pick(req.query, allowedQueryParams); - // bring all query values onto req.params object - _.extend(req.params, req.query); - + // bring all query values onto res.locals object + _.extend(res.locals, req.query); + next(); }; }; diff --git a/lib/cartodb/middleware/context/db-conn-setup.js b/lib/cartodb/middleware/context/db-conn-setup.js index f1974ce4..dec48f6d 100644 --- a/lib/cartodb/middleware/context/db-conn-setup.js +++ b/lib/cartodb/middleware/context/db-conn-setup.js @@ -2,11 +2,8 @@ const _ = require('underscore'); module.exports = function dbConnSetupMiddleware(pgConnection) { return function dbConnSetup(req, res, next) { - const user = req.context.user; - - // FIXME: this function shouldn't be able to change `req.params`. It should return an - // object with the user's conf and it should be merge with default here. - pgConnection.setDBConn(user, req.params, (err) => { + const user = res.locals.user; + pgConnection.setDBConn(user, res.locals, (err) => { if (err) { if (err.message && -1 !== err.message.indexOf('name not found')) { err.http_status = 404; @@ -17,24 +14,17 @@ module.exports = function dbConnSetupMiddleware(pgConnection) { // Add default database connection parameters // if none given - _.defaults(req.params, { + _.defaults(res.locals, { dbuser: global.environment.postgres.user, dbpassword: global.environment.postgres.password, dbhost: global.environment.postgres.host, dbport: global.environment.postgres.port }); - - res.set('X-Served-By-DB-Host', req.params.dbhost); - - // FIXME: Temporary hack to share data between middlewares. Express overrides req.params to - // parse url params to an object and it's performed after matching path and controller. - if (!res.locals) { - res.locals = {}; - } - _.defaults(res.locals, req.params); + + res.set('X-Served-By-DB-Host', res.locals.dbhost); req.profiler.done('req2params'); - + next(null); }); }; diff --git a/lib/cartodb/middleware/context/index.js b/lib/cartodb/middleware/context/index.js index 411b6f93..640aafd6 100644 --- a/lib/cartodb/middleware/context/index.js +++ b/lib/cartodb/middleware/context/index.js @@ -1,3 +1,4 @@ +const locals = require('./locals'); const cleanUpQueryParams = require('./clean-up-query-params'); const layergroupToken = require('./layergroup-token'); const authorize = require('./authorize'); @@ -5,6 +6,7 @@ const dbConnSetup = require('./db-conn-setup'); module.exports = function prepareContextMiddleware(authApi, pgConnection) { return [ + locals, cleanUpQueryParams(), layergroupToken, authorize(authApi), diff --git a/lib/cartodb/middleware/context/layergroup-token.js b/lib/cartodb/middleware/context/layergroup-token.js index d1ccb3be..026d0806 100644 --- a/lib/cartodb/middleware/context/layergroup-token.js +++ b/lib/cartodb/middleware/context/layergroup-token.js @@ -1,22 +1,22 @@ var LayergroupToken = require('../../models/layergroup-token'); module.exports = function layergroupTokenMiddleware(req, res, next) { - if (!req.params.hasOwnProperty('token')) { + if (!res.locals.token) { return next(); } - var user = req.context.user; + var user = res.locals.user; - var layergroupToken = LayergroupToken.parse(req.params.token); - req.params.token = layergroupToken.token; - req.params.cache_buster = layergroupToken.cacheBuster; + var layergroupToken = LayergroupToken.parse(res.locals.token); + res.locals.token = layergroupToken.token; + res.locals.cache_buster = layergroupToken.cacheBuster; if (layergroupToken.signer) { - req.params.signer = layergroupToken.signer; - if (!req.params.signer) { - req.params.signer = user; - } else if (req.params.signer !== user) { - var err = new Error(`Cannot use map signature of user "${req.params.signer}" on db of user "${user}"`); + res.locals.signer = layergroupToken.signer; + if (!res.locals.signer) { + res.locals.signer = user; + } else if (res.locals.signer !== user) { + var err = new Error(`Cannot use map signature of user "${res.locals.signer}" on db of user "${user}"`); err.type = 'auth'; err.http_status = 403; if (req.query && req.query.callback) { diff --git a/lib/cartodb/middleware/context/locals.js b/lib/cartodb/middleware/context/locals.js new file mode 100644 index 00000000..bb7d5ee2 --- /dev/null +++ b/lib/cartodb/middleware/context/locals.js @@ -0,0 +1,8 @@ +const _ = require('underscore'); + +module.exports = function localsMiddleware(req, res, next) { + _.extend(res.locals, req.params); + + next(); +}; + diff --git a/lib/cartodb/middleware/user.js b/lib/cartodb/middleware/user.js index 40934849..ce3fdd29 100644 --- a/lib/cartodb/middleware/user.js +++ b/lib/cartodb/middleware/user.js @@ -2,6 +2,13 @@ var CdbRequest = require('../models/cdb_request'); var cdbRequest = new CdbRequest(); module.exports = function userMiddleware(req, res, next) { - req.context.user = cdbRequest.userByReq(req); + res.locals.user = cdbRequest.userByReq(req); + + // avoid a req.params.user equals to undefined + // overwrites res.locals.user + if(!req.params.user) { + delete req.params.user; + } + next(); }; diff --git a/lib/cartodb/server.js b/lib/cartodb/server.js index 377fff69..5bb510fd 100644 --- a/lib/cartodb/server.js +++ b/lib/cartodb/server.js @@ -362,8 +362,6 @@ function bootstrap(opts) { app.use(bodyParser.json()); app.use(function bootstrap$prepareRequestResponse(req, res, next) { - req.context = req.context || {}; - if (global.environment && global.environment.api_hostname) { res.set('X-Served-By-Host', global.environment.api_hostname); } diff --git a/test/acceptance/ported/support/ported_server_options.js b/test/acceptance/ported/support/ported_server_options.js index 36684f77..8604e68c 100644 --- a/test/acceptance/ported/support/ported_server_options.js +++ b/test/acceptance/ported/support/ported_server_options.js @@ -63,7 +63,7 @@ module.exports = _.extend({}, serverOptions, { _.extend(req.params, req.query); req.params.user = 'localhost'; - req.context = {user: 'localhost'}; + res.locals.user = 'localhost'; req.params.dbhost = global.environment.postgres.host; req.params.dbport = req.params.dbport || global.environment.postgres.port; @@ -74,6 +74,9 @@ module.exports = _.extend({}, serverOptions, { } req.params.dbname = 'test_windshaft_cartodb_user_1_db'; + // add all params to res.locals + res.locals = _.extend({}, req.params); + // increment number of calls counter global.req2params_calls = global.req2params_calls ? global.req2params_calls + 1 : 1; diff --git a/test/unit/cartodb/prepare-context.test.js b/test/unit/cartodb/prepare-context.test.js index 1ae4ffe2..dbbfb8bf 100644 --- a/test/unit/cartodb/prepare-context.test.js +++ b/test/unit/cartodb/prepare-context.test.js @@ -10,6 +10,7 @@ var TemplateMaps = require('../../../lib/cartodb/backends/template_maps'); const cleanUpQueryParamsMiddleware = require('../../../lib/cartodb/middleware/context/clean-up-query-params'); const authorizeMiddleware = require('../../../lib/cartodb/middleware/context/authorize'); const dbConnSetupMiddleware = require('../../../lib/cartodb/middleware/context/db-conn-setup'); +const localsMiddleware = require('../../../lib/cartodb/middleware/context/locals'); var windshaft = require('windshaft'); @@ -47,56 +48,75 @@ describe('prepare-context', function() { req.profiler = { done: function() {} }; - req.context = { user: 'localhost' }; - req.params = {}; + return req; } + function prepareResponse(res) { + if(!res.locals) { + res.locals = {}; + } + res.locals.user = 'localhost'; + + return res; + } + + it('res.locals are created', function(done) { + let req = {}; + let res = {}; + + localsMiddleware(prepareRequest(req), prepareResponse(res), function(err) { + if ( err ) { done(err); return; } + assert.ok(res.hasOwnProperty('locals'), 'response has locals'); + done(); + }); + }); + it('cleans up request', function(done){ var req = {headers: { host:'localhost' }, query: {dbuser:'hacker',dbname:'secret'}}; var res = {}; - cleanUpQueryParams(prepareRequest(req), res, function(err) { + cleanUpQueryParams(prepareRequest(req), prepareResponse(res), function(err) { if ( err ) { done(err); return; } assert.ok(_.isObject(req.query), 'request has query'); assert.ok(!req.query.hasOwnProperty('dbuser'), 'dbuser was removed from query'); - assert.ok(req.hasOwnProperty('params'), 'request has params'); - assert.ok(!req.params.hasOwnProperty('interactivity'), 'request params do not have interactivity'); + assert.ok(res.hasOwnProperty('locals'), 'response has locals'); + assert.ok(!res.locals.hasOwnProperty('interactivity'), 'response locals do not have interactivity'); done(); }); }); it('sets dbname from redis metadata', function(done){ - var req = {headers: { host:'localhost' }, query: {}, locals: {} }; + var req = {headers: { host:'localhost' }, query: {} }; var res = { set: function () {} }; - dbConnSetup(prepareRequest(req), res, function(err) { - if ( err ) { done(err); return; } + dbConnSetup(prepareRequest(req), prepareResponse(res), function(err) { + if ( err ) { done(err); return; } assert.ok(_.isObject(req.query), 'request has query'); assert.ok(!req.query.hasOwnProperty('dbuser'), 'dbuser was removed from query'); - assert.ok(req.hasOwnProperty('params'), 'request has params'); - assert.ok(!req.params.hasOwnProperty('interactivity'), 'request params do not have interactivity'); - assert.equal(req.params.dbname, test_database); - assert.ok(req.params.dbuser === test_pubuser, 'could inject dbuser ('+req.params.dbuser+')'); + assert.ok(res.hasOwnProperty('locals'), 'response has locals'); + assert.ok(!res.locals.hasOwnProperty('interactivity'), 'response locals do not have interactivity'); + assert.equal(res.locals.dbname, test_database); + assert.ok(res.locals.dbuser === test_pubuser, 'could inject dbuser ('+res.locals.dbuser+')'); done(); }); }); it('sets also dbuser for authenticated requests', function(done){ - var req = { headers: { host: 'localhost' }, query: { map_key: '1234' }, locals: {} }; + var req = { headers: { host: 'localhost' }, query: { map_key: '1234' }}; var res = { set: function () {} }; // FIXME: review authorize-pgconnsetup workflow, It might we are doing authorization twice. - authorize(prepareRequest(req), res, function (err) { + authorize(prepareRequest(req), prepareResponse(res), function (err) { if (err) { done(err); return; } dbConnSetup(req, res, function(err) { if ( err ) { done(err); return; } assert.ok(_.isObject(req.query), 'request has query'); assert.ok(!req.query.hasOwnProperty('dbuser'), 'dbuser was removed from query'); - assert.ok(req.hasOwnProperty('params'), 'request has params'); - assert.ok(!req.params.hasOwnProperty('interactivity'), 'request params do not have interactivity'); - assert.equal(req.params.dbname, test_database); - assert.equal(req.params.dbuser, test_user); + assert.ok(res.hasOwnProperty('locals'), 'response has locals'); + assert.ok(!res.locals.hasOwnProperty('interactivity'), 'request params do not have interactivity'); + assert.equal(res.locals.dbname, test_database); + assert.equal(res.locals.dbuser, test_user); req = { headers: { @@ -104,13 +124,14 @@ describe('prepare-context', function() { }, query: { map_key: '1235' - }, - locals: {} + } }; - dbConnSetup(prepareRequest(req), res, function () { + res = { set: function () {} }; + + dbConnSetup(prepareRequest(req), prepareResponse(res), function() { // wrong key resets params to no user - assert.ok(req.params.dbuser === test_pubuser, 'could inject dbuser ('+req.params.dbuser+')'); + assert.ok(res.locals.dbuser === test_pubuser, 'could inject dbuser ('+res.locals.dbuser+')'); done(); }); }); @@ -130,17 +151,16 @@ describe('prepare-context', function() { api_key: 'test', style: 'override', config: config - }, - locals: {} + } }; var res = {}; - - cleanUpQueryParams(prepareRequest(req), res, function (err) { + + cleanUpQueryParams(prepareRequest(req), prepareResponse(res), function (err) { if ( err ) { return done(err); } - var query = req.params; + var query = res.locals; assert.deepEqual(config, query.config); assert.equal('test', query.api_key); assert.equal(undefined, query.non_included);