BaseController to encapsulate req2params method
All controllers now extending BaseController - Most of the acceptance ported tests will be broken
This commit is contained in:
parent
1c6571d1db
commit
352dc6b311
150
lib/cartodb/controllers/base.js
Normal file
150
lib/cartodb/controllers/base.js
Normal file
@ -0,0 +1,150 @@
|
||||
var assert = require('assert');
|
||||
|
||||
var _ = require('underscore');
|
||||
var step = require('step');
|
||||
|
||||
var LZMA = require('lzma').LZMA;
|
||||
var lzmaWorker = new LZMA();
|
||||
|
||||
// Whitelist query parameters and attach format
|
||||
var REQUEST_QUERY_PARAMS_WHITELIST = [
|
||||
'config',
|
||||
'map_key',
|
||||
'api_key',
|
||||
'auth_token',
|
||||
'callback'
|
||||
];
|
||||
|
||||
function BaseController(authApi, pgConnection) {
|
||||
this.authApi = authApi;
|
||||
this.pgConnection = pgConnection;
|
||||
}
|
||||
|
||||
module.exports = BaseController;
|
||||
|
||||
// jshint maxcomplexity:9
|
||||
/**
|
||||
* Whitelist input and get database name & default geometry type from
|
||||
* subdomain/user metadata held in CartoDB Redis
|
||||
* @param req - standard express request obj. Should have host & table
|
||||
* @param callback
|
||||
*/
|
||||
BaseController.prototype.req2params = function(req, callback){
|
||||
var self = this;
|
||||
|
||||
if ( req.query.lzma ) {
|
||||
|
||||
// Decode (from base64)
|
||||
var lzma = new Buffer(req.query.lzma, 'base64')
|
||||
.toString('binary')
|
||||
.split('')
|
||||
.map(function(c) {
|
||||
return c.charCodeAt(0) - 128;
|
||||
});
|
||||
|
||||
|
||||
// Decompress
|
||||
lzmaWorker.decompress(
|
||||
lzma,
|
||||
function(result) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('lzma');
|
||||
}
|
||||
try {
|
||||
delete req.query.lzma;
|
||||
_.extend(req.query, JSON.parse(result));
|
||||
self.req2params(req, callback);
|
||||
} catch (err) {
|
||||
req.profiler.done('req2params');
|
||||
callback(new Error('Error parsing lzma as JSON: ' + err));
|
||||
}
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
req.query = _.pick(req.query, REQUEST_QUERY_PARAMS_WHITELIST);
|
||||
req.params = _.extend({}, req.params); // shuffle things as request is a strange array/object
|
||||
|
||||
var user = req.context.user;
|
||||
|
||||
if ( req.params.token ) {
|
||||
// Token might match the following patterns:
|
||||
// - {user}@{tpl_id}@{token}:{cache_buster}
|
||||
//console.log("Request parameters include token " + req.params.token);
|
||||
var tksplit = req.params.token.split(':');
|
||||
req.params.token = tksplit[0];
|
||||
if ( tksplit.length > 1 ) {
|
||||
req.params.cache_buster= tksplit[1];
|
||||
}
|
||||
tksplit = req.params.token.split('@');
|
||||
if ( tksplit.length > 1 ) {
|
||||
req.params.signer = tksplit.shift();
|
||||
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 + '"'
|
||||
);
|
||||
err.http_status = 403;
|
||||
req.profiler.done('req2params');
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if ( tksplit.length > 1 ) {
|
||||
/*var template_hash = */tksplit.shift(); // unused
|
||||
}
|
||||
req.params.token = tksplit.shift();
|
||||
//console.log("Request for token " + req.params.token + " with signature from " + req.params.signer);
|
||||
}
|
||||
}
|
||||
|
||||
// bring all query values onto req.params object
|
||||
_.extend(req.params, req.query);
|
||||
|
||||
if (req.profiler) {
|
||||
req.profiler.done('req2params.setup');
|
||||
}
|
||||
|
||||
step(
|
||||
function getPrivacy(){
|
||||
self.authApi.authorize(req, this);
|
||||
},
|
||||
function validateAuthorization(err, authorized) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('authorize');
|
||||
}
|
||||
assert.ifError(err);
|
||||
if(!authorized) {
|
||||
err = new Error("Sorry, you are unauthorized (permission denied)");
|
||||
err.http_status = 403;
|
||||
throw err;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
function getDatabase(err){
|
||||
assert.ifError(err);
|
||||
self.pgConnection.setDBConn(user, req.params, this);
|
||||
},
|
||||
function finishSetup(err) {
|
||||
if ( err ) {
|
||||
req.profiler.done('req2params');
|
||||
return callback(err, req);
|
||||
}
|
||||
|
||||
// Add default database connection parameters
|
||||
// if none given
|
||||
_.defaults(req.params, {
|
||||
dbuser: global.environment.postgres.user,
|
||||
dbpassword: global.environment.postgres.password,
|
||||
dbhost: global.environment.postgres.host,
|
||||
dbport: global.environment.postgres.port
|
||||
});
|
||||
|
||||
req.profiler.done('req2params');
|
||||
callback(null, req);
|
||||
}
|
||||
);
|
||||
};
|
||||
// jshint maxcomplexity:6
|
@ -1,6 +1,9 @@
|
||||
var assert = require('assert');
|
||||
var step = require('step');
|
||||
|
||||
var util = require('util');
|
||||
var BaseController = require('./base');
|
||||
|
||||
var cors = require('../middleware/cors');
|
||||
|
||||
var MapStoreMapConfigProvider = require('../models/mapconfig/map_store_provider');
|
||||
@ -8,6 +11,8 @@ var TablesCacheEntry = require('../cache/model/database_tables_entry');
|
||||
|
||||
/**
|
||||
* @param app
|
||||
* @param {AuthApi} authApi
|
||||
* @param {PgConnection} pgConnection
|
||||
* @param {MapStore} mapStore
|
||||
* @param {TileBackend} tileBackend
|
||||
* @param {PreviewBackend} previewBackend
|
||||
@ -18,8 +23,10 @@ var TablesCacheEntry = require('../cache/model/database_tables_entry');
|
||||
* @param {LayergroupAffectedTables} layergroupAffectedTables
|
||||
* @constructor
|
||||
*/
|
||||
function LayergroupController(app, mapStore, tileBackend, previewBackend, attributesBackend, surrogateKeysCache,
|
||||
userLimitsApi, queryTablesApi, layergroupAffectedTables) {
|
||||
function LayergroupController(app, authApi, pgConnection, mapStore, tileBackend, previewBackend, attributesBackend,
|
||||
surrogateKeysCache, userLimitsApi, queryTablesApi, layergroupAffectedTables) {
|
||||
BaseController.call(this, authApi, pgConnection);
|
||||
|
||||
this.app = app;
|
||||
this.mapStore = mapStore;
|
||||
this.tileBackend = tileBackend;
|
||||
@ -31,6 +38,8 @@ function LayergroupController(app, mapStore, tileBackend, previewBackend, attrib
|
||||
this.layergroupAffectedTables = layergroupAffectedTables;
|
||||
}
|
||||
|
||||
util.inherits(LayergroupController, BaseController);
|
||||
|
||||
module.exports = LayergroupController;
|
||||
|
||||
|
||||
@ -52,7 +61,7 @@ LayergroupController.prototype.attributes = function(req, res) {
|
||||
|
||||
step(
|
||||
function setupParams() {
|
||||
self.app.req2params(req, this);
|
||||
self.req2params(req, this);
|
||||
},
|
||||
function retrieveFeatureAttributes(err) {
|
||||
assert.ifError(err);
|
||||
@ -95,7 +104,7 @@ LayergroupController.prototype.tileOrLayer = function (req, res) {
|
||||
|
||||
step(
|
||||
function mapController$prepareParams() {
|
||||
self.app.req2params(req, this);
|
||||
self.req2params(req, this);
|
||||
},
|
||||
function mapController$getTileOrGrid(err) {
|
||||
assert.ifError(err);
|
||||
@ -181,7 +190,7 @@ LayergroupController.prototype.staticMap = function(req, res, width, height, zoo
|
||||
|
||||
step(
|
||||
function() {
|
||||
self.app.req2params(req, this);
|
||||
self.req2params(req, this);
|
||||
},
|
||||
function(err) {
|
||||
assert.ifError(err);
|
||||
|
@ -3,6 +3,9 @@ var assert = require('assert');
|
||||
var step = require('step');
|
||||
var windshaft = require('windshaft');
|
||||
|
||||
var util = require('util');
|
||||
var BaseController = require('./base');
|
||||
|
||||
var cors = require('../middleware/cors');
|
||||
|
||||
var MapConfig = windshaft.model.MapConfig;
|
||||
@ -17,6 +20,7 @@ var CreateLayergroupMapConfigProvider = require('../models/mapconfig/create_laye
|
||||
|
||||
/**
|
||||
* @param app
|
||||
* @param {AuthApi} authApi
|
||||
* @param {PgConnection} pgConnection
|
||||
* @param {TemplateMaps} templateMaps
|
||||
* @param {MapBackend} mapBackend
|
||||
@ -27,8 +31,11 @@ var CreateLayergroupMapConfigProvider = require('../models/mapconfig/create_laye
|
||||
* @param {LayergroupAffectedTables} layergroupAffectedTables
|
||||
* @constructor
|
||||
*/
|
||||
function MapController(app, pgConnection, templateMaps, mapBackend, metadataBackend, queryTablesApi,
|
||||
function MapController(app, authApi, pgConnection, templateMaps, mapBackend, metadataBackend, queryTablesApi,
|
||||
surrogateKeysCache, userLimitsApi, layergroupAffectedTables) {
|
||||
|
||||
BaseController.call(this, authApi, pgConnection);
|
||||
|
||||
this.app = app;
|
||||
this.pgConnection = pgConnection;
|
||||
this.templateMaps = templateMaps;
|
||||
@ -42,6 +49,8 @@ function MapController(app, pgConnection, templateMaps, mapBackend, metadataBack
|
||||
this.namedLayersAdapter = new MapConfigNamedLayersAdapter(templateMaps);
|
||||
}
|
||||
|
||||
util.inherits(MapController, BaseController);
|
||||
|
||||
module.exports = MapController;
|
||||
|
||||
|
||||
@ -121,7 +130,7 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
|
||||
|
||||
step(
|
||||
function setupParams(){
|
||||
self.app.req2params(req, this);
|
||||
self.req2params(req, this);
|
||||
},
|
||||
prepareConfigFn,
|
||||
function beforeLayergroupCreate(err, requestMapConfig) {
|
||||
@ -174,7 +183,7 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
|
||||
|
||||
step(
|
||||
function setupParams(){
|
||||
self.app.req2params(req, this);
|
||||
self.req2params(req, this);
|
||||
},
|
||||
function getTemplateParams() {
|
||||
prepareParamsFn(this);
|
||||
|
@ -2,12 +2,18 @@ var step = require('step');
|
||||
var assert = require('assert');
|
||||
var _ = require('underscore');
|
||||
var NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
|
||||
|
||||
var util = require('util');
|
||||
var BaseController = require('./base');
|
||||
|
||||
var cors = require('../middleware/cors');
|
||||
|
||||
var TablesCacheEntry = require('../cache/model/database_tables_entry');
|
||||
|
||||
function NamedMapsController(app, namedMapProviderCache, tileBackend, previewBackend, surrogateKeysCache,
|
||||
function NamedMapsController(app, authApi, pgConnection, namedMapProviderCache, tileBackend, previewBackend, surrogateKeysCache,
|
||||
tablesExtentApi) {
|
||||
BaseController.call(this, authApi, pgConnection);
|
||||
|
||||
this.app = app;
|
||||
this.namedMapProviderCache = namedMapProviderCache;
|
||||
this.tileBackend = tileBackend;
|
||||
@ -16,6 +22,8 @@ function NamedMapsController(app, namedMapProviderCache, tileBackend, previewBac
|
||||
this.tablesExtentApi = tablesExtentApi;
|
||||
}
|
||||
|
||||
util.inherits(NamedMapsController, BaseController);
|
||||
|
||||
module.exports = NamedMapsController;
|
||||
|
||||
NamedMapsController.prototype.register = function(app) {
|
||||
@ -73,7 +81,7 @@ NamedMapsController.prototype.tile = function(req, res) {
|
||||
var namedMapProvider;
|
||||
step(
|
||||
function reqParams() {
|
||||
self.app.req2params(req, this);
|
||||
self.req2params(req, this);
|
||||
},
|
||||
function getTile() {
|
||||
namedMapProvider = self.namedMapProviderCache.get(
|
||||
@ -110,7 +118,7 @@ NamedMapsController.prototype.staticMap = function(req, res) {
|
||||
var namedMapProvider;
|
||||
step(
|
||||
function reqParams() {
|
||||
self.app.req2params(req, this);
|
||||
self.req2params(req, this);
|
||||
},
|
||||
function getTemplate(err) {
|
||||
assert.ifError(err);
|
||||
|
@ -1,15 +1,22 @@
|
||||
var step = require('step');
|
||||
var assert = require('assert');
|
||||
var templateName = require('../backends/template_maps').templateName;
|
||||
|
||||
var util = require('util');
|
||||
var BaseController = require('./base');
|
||||
|
||||
var cors = require('../middleware/cors');
|
||||
|
||||
|
||||
/**
|
||||
* @param {TemplateMaps} templateMaps
|
||||
* @param {AuthApi} authApi
|
||||
* @param {PgConnection} pgConnection
|
||||
* @constructor
|
||||
*/
|
||||
function NamedMapsAdminController(templateMaps, authApi) {
|
||||
function NamedMapsAdminController(templateMaps, authApi, pgConnection) {
|
||||
BaseController.call(this, authApi, pgConnection);
|
||||
|
||||
this.templateMaps = templateMaps;
|
||||
this.authApi = authApi;
|
||||
}
|
||||
|
@ -178,6 +178,8 @@ module.exports = function(serverOptions) {
|
||||
|
||||
new controller.Layergroup(
|
||||
app,
|
||||
authApi,
|
||||
pgConnection,
|
||||
mapStore,
|
||||
tileBackend,
|
||||
previewBackend,
|
||||
@ -190,6 +192,7 @@ module.exports = function(serverOptions) {
|
||||
|
||||
new controller.Map(
|
||||
app,
|
||||
authApi,
|
||||
pgConnection,
|
||||
templateMaps,
|
||||
mapBackend,
|
||||
@ -202,6 +205,8 @@ module.exports = function(serverOptions) {
|
||||
|
||||
new controller.NamedMaps(
|
||||
app,
|
||||
authApi,
|
||||
pgConnection,
|
||||
namedMapProviderCache,
|
||||
tileBackend,
|
||||
previewBackend,
|
||||
@ -209,7 +214,7 @@ module.exports = function(serverOptions) {
|
||||
tablesExtentApi
|
||||
).register(app);
|
||||
|
||||
new controller.NamedMapsAdmin(templateMaps, authApi).register(app);
|
||||
new controller.NamedMapsAdmin(templateMaps, authApi, pgConnection).register(app);
|
||||
|
||||
new controller.ServerInfo().register(app);
|
||||
|
||||
@ -217,131 +222,6 @@ module.exports = function(serverOptions) {
|
||||
* END Routing
|
||||
******************************************************************************************************************/
|
||||
|
||||
// jshint maxcomplexity:10
|
||||
/**
|
||||
* Whitelist input and get database name & default geometry type from
|
||||
* subdomain/user metadata held in CartoDB Redis
|
||||
* @param req - standard express request obj. Should have host & table
|
||||
* @param callback
|
||||
*/
|
||||
app.req2params = function(req, callback){
|
||||
|
||||
if ( req.query.lzma ) {
|
||||
|
||||
// Decode (from base64)
|
||||
var lzma = new Buffer(req.query.lzma, 'base64')
|
||||
.toString('binary')
|
||||
.split('')
|
||||
.map(function(c) {
|
||||
return c.charCodeAt(0) - 128;
|
||||
});
|
||||
|
||||
// Decompress
|
||||
lzmaWorker.decompress(
|
||||
lzma,
|
||||
function(result) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('lzma');
|
||||
}
|
||||
try {
|
||||
delete req.query.lzma;
|
||||
_.extend(req.query, JSON.parse(result));
|
||||
app.req2params(req, callback);
|
||||
} catch (err) {
|
||||
req.profiler.done('req2params');
|
||||
callback(new Error('Error parsing lzma as JSON: ' + err));
|
||||
}
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
req.query = _.pick(req.query, REQUEST_QUERY_PARAMS_WHITELIST);
|
||||
req.params = _.extend({}, req.params); // shuffle things as request is a strange array/object
|
||||
|
||||
var user = req.context.user;
|
||||
|
||||
if ( req.params.token ) {
|
||||
// Token might match the following patterns:
|
||||
// - {user}@{tpl_id}@{token}:{cache_buster}
|
||||
//console.log("Request parameters include token " + req.params.token);
|
||||
var tksplit = req.params.token.split(':');
|
||||
req.params.token = tksplit[0];
|
||||
if ( tksplit.length > 1 ) {
|
||||
req.params.cache_buster= tksplit[1];
|
||||
}
|
||||
tksplit = req.params.token.split('@');
|
||||
if ( tksplit.length > 1 ) {
|
||||
req.params.signer = tksplit.shift();
|
||||
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 + '"'
|
||||
);
|
||||
err.http_status = 403;
|
||||
req.profiler.done('req2params');
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if ( tksplit.length > 1 ) {
|
||||
/*var template_hash = */tksplit.shift(); // unused
|
||||
}
|
||||
req.params.token = tksplit.shift();
|
||||
//console.log("Request for token " + req.params.token + " with signature from " + req.params.signer);
|
||||
}
|
||||
}
|
||||
|
||||
// bring all query values onto req.params object
|
||||
_.extend(req.params, req.query);
|
||||
|
||||
if (req.profiler) {
|
||||
req.profiler.done('req2params.setup');
|
||||
}
|
||||
|
||||
step(
|
||||
function getPrivacy(){
|
||||
authApi.authorize(req, this);
|
||||
},
|
||||
function validateAuthorization(err, authorized) {
|
||||
if (req.profiler) {
|
||||
req.profiler.done('authorize');
|
||||
}
|
||||
assert.ifError(err);
|
||||
if(!authorized) {
|
||||
err = new Error("Sorry, you are unauthorized (permission denied)");
|
||||
err.http_status = 403;
|
||||
throw err;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
function getDatabase(err){
|
||||
assert.ifError(err);
|
||||
pgConnection.setDBConn(user, req.params, this);
|
||||
},
|
||||
function finishSetup(err) {
|
||||
if ( err ) {
|
||||
req.profiler.done('req2params');
|
||||
return callback(err, req);
|
||||
}
|
||||
|
||||
// Add default database connection parameters
|
||||
// if none given
|
||||
_.defaults(req.params, {
|
||||
dbuser: global.environment.postgres.user,
|
||||
dbpassword: global.environment.postgres.password,
|
||||
dbhost: global.environment.postgres.host,
|
||||
dbport: global.environment.postgres.port
|
||||
});
|
||||
|
||||
req.profiler.done('req2params');
|
||||
callback(null, req);
|
||||
}
|
||||
);
|
||||
};
|
||||
// jshint maxcomplexity:6
|
||||
|
||||
return app;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user