Browse Source

Merge pull request #251 from pelias/sanitizers

refactor sanitizers: first pass
pull/252/head
Peter Johnson a.k.a. insertcoffee 9 years ago
parent
commit
6567047fe8
  1. 2
      package.json
  2. 35
      sanitiser/_categories.js
  3. 35
      sanitiser/_details.js
  4. 11
      sanitiser/_geo_common.js
  5. 37
      sanitiser/_geo_reverse.js
  6. 37
      sanitiser/_geo_search.js
  7. 129
      sanitiser/_id.js
  8. 62
      sanitiser/_layers.js
  9. 17
      sanitiser/_sanitize.js
  10. 53
      sanitiser/_size.js
  11. 59
      sanitiser/_source.js
  12. 41
      sanitiser/_text.js
  13. 5
      sanitiser/place.js
  14. 18
      sanitiser/reverse.js
  15. 26
      sanitiser/sanitizeAll.js
  16. 8
      sanitiser/search.js
  17. 51
      test/unit/sanitiser/_source.js
  18. 8
      test/unit/sanitiser/search.js

2
package.json

@ -35,6 +35,7 @@
"dependencies": { "dependencies": {
"addressit": "1.3.0", "addressit": "1.3.0",
"async": "^0.9.0", "async": "^0.9.0",
"check-types": "^3.3.1",
"cluster2": "git://github.com/missinglink/cluster2.git#node_zero_twelve", "cluster2": "git://github.com/missinglink/cluster2.git#node_zero_twelve",
"express": "^4.8.8", "express": "^4.8.8",
"express-http-proxy": "^0.6.0", "express-http-proxy": "^0.6.0",
@ -43,7 +44,6 @@
"geojson-extent": "^0.3.1", "geojson-extent": "^0.3.1",
"geolib": "^2.0.18", "geolib": "^2.0.18",
"geopipes-elasticsearch-backend": "^0.2.0", "geopipes-elasticsearch-backend": "^0.2.0",
"is-object": "^1.0.1",
"markdown": "0.5.0", "markdown": "0.5.0",
"microtime": "1.4.0", "microtime": "1.4.0",
"morgan": "1.5.2", "morgan": "1.5.2",

35
sanitiser/_categories.js

@ -1,36 +1,33 @@
var isObject = require('is-object'); var check = require('check-types');
// validate inputs, convert types and apply defaults // validate inputs, convert types and apply defaults
function sanitize( req ){ function sanitize( raw, clean ){
var clean = req.clean || {}; // error & warning messages
var params= req.query; var messages = { errors: [], warnings: [] };
// ensure the input params are a valid object
if( !isObject( params ) ){
params = {};
}
// default case (no categories specified in GET params) // default case (no categories specified in GET params)
if('string' !== typeof params.categories || !params.categories.length){ clean.categories = [];
clean.categories = [];
} // if categories string has been set
else { if( check.unemptyString( raw.categories ) ){
// parse GET params
clean.categories = params.categories.split(',') // map input categories to valid format
clean.categories = raw.categories.split(',')
.map(function (cat) { .map(function (cat) {
return cat.toLowerCase().trim(); // lowercase inputs return cat.toLowerCase().trim(); // lowercase inputs
}) })
.filter( function( cat ) { .filter( function( cat ) {
return ( cat.length > 0 ); return ( cat.length > 0 );
}); });
}
// pass validated params to next middleware if( !clean.categories.length ){
req.clean = clean; messages.warnings.push( 'invalid \'categories\': no valid category strings found');
}
}
return { 'error': false }; return messages;
} }

35
sanitiser/_details.js

@ -1,36 +1,25 @@
var isObject = require('is-object');
// validate inputs, convert types and apply defaults var check = require('check-types');
function sanitize( req, default_value ){ var DEFAULT_DETAILS_BOOL = true;
var clean = req.clean || {};
var params= req.query;
if (default_value === undefined) {
default_value = true;
}
default_value = !!default_value; // validate inputs, convert types and apply defaults
function sanitize( raw, clean ){
// ensure the input params are a valid object // error & warning messages
if( !isObject( params ) ){ var messages = { errors: [], warnings: [] };
params = {};
}
if (params.details !== undefined) { if( !check.undefined( raw.details ) ){
clean.details = isTruthy(params.details); clean.details = isTruthy( raw.details );
} else { } else {
clean.details = default_value; clean.details = DEFAULT_DETAILS_BOOL;
} }
req.clean = clean; return messages;
return {'error':false};
} }
// be lenient with 'truthy' values
function isTruthy(val) { function isTruthy(val) {
if (typeof val === 'string') { if( check.string( val ) ){
return ['true', '1', 'yes', 'y'].indexOf(val) !== -1; return ['true', '1', 'yes', 'y'].indexOf(val) !== -1;
} }

11
sanitiser/_geo_common.js

@ -1,7 +1,8 @@
/** /**
* helper sanitiser methods for geo parameters * helper sanitiser methods for geo parameters
*/ */
var util = require( 'util' ); var util = require('util'),
check = require('check-types');
/** /**
* Parse and validate bbox parameter * Parse and validate bbox parameter
@ -9,15 +10,15 @@ var util = require( 'util' );
* bbox = left, bottom, right, top * bbox = left, bottom, right, top
* bbox = min Longitude, min Latitude, max Longitude, max Latitude * bbox = min Longitude, min Latitude, max Longitude, max Latitude
* *
* @param {object} raw
* @param {object} clean * @param {object} clean
* @param {string} param
*/ */
function sanitize_bbox( clean, param ) { function sanitize_bbox( raw, clean ) {
if( !param ) { if( !check.unemptyString( raw.bbox ) ) {
return; return;
} }
var bboxArr = param.split( ',' ); var bboxArr = raw.bbox.split( ',' );
if( Array.isArray( bboxArr ) && bboxArr.length === 4 ) { if( Array.isArray( bboxArr ) && bboxArr.length === 4 ) {
var bbox = bboxArr.map(parseFloat); var bbox = bboxArr.map(parseFloat);

37
sanitiser/_geo_reverse.js

@ -1,39 +1,26 @@
var isObject = require('is-object');
var geo_common = require ('./_geo_common'); var geo_common = require ('./_geo_common');
var LAT_LON_IS_REQUIRED = true,
CIRCLE_IS_REQUIRED = false,
CIRCLE_MUST_BE_COMPLETE = false;
// validate inputs, convert types and apply defaults // validate inputs, convert types and apply defaults
module.exports = function sanitize( req ){ module.exports = function sanitize( raw, clean ){
var clean = req.clean || {};
var params = req.query;
var latlon_is_required = true;
var circle_is_required = false;
var circle_must_be_complete = false;
// ensure the input params are a valid object // error & warning messages
if( !isObject( params ) ){ var messages = { errors: [], warnings: [] };
params = {};
}
if( !isObject( params.point ) ){
params.point = {};
}
try { try {
geo_common.sanitize_coord( 'lat', clean, params['point.lat'], latlon_is_required ); geo_common.sanitize_coord( 'lat', clean, raw['point.lat'], LAT_LON_IS_REQUIRED );
geo_common.sanitize_coord( 'lon', clean, params['point.lon'], latlon_is_required ); geo_common.sanitize_coord( 'lon', clean, raw['point.lon'], LAT_LON_IS_REQUIRED );
// boundary.circle.* is not mandatory, and only specifying radius is fine, // boundary.circle.* is not mandatory, and only specifying radius is fine,
// as point.lat/lon will be used to fill those values by default // as point.lat/lon will be used to fill those values by default
geo_common.sanitize_boundary_circle( clean, params, circle_is_required, circle_must_be_complete); geo_common.sanitize_boundary_circle( clean, raw, CIRCLE_IS_REQUIRED, CIRCLE_MUST_BE_COMPLETE);
} }
catch (err) { catch (err) {
return { messages.errors.push( err.message );
'error': true,
'message': err.message
};
} }
req.clean = clean; return messages;
return { 'error': false };
}; };

37
sanitiser/_geo_search.js

@ -1,38 +1,21 @@
var isObject = require('is-object');
var geo_common = require ('./_geo_common'); var geo_common = require ('./_geo_common');
var LAT_LON_IS_REQUIRED = false;
// validate inputs, convert types and apply defaults // validate inputs, convert types and apply defaults
module.exports = function sanitize( req ){ module.exports = function sanitize( raw, clean ){
var clean = req.clean || {};
var params = req.query;
var latlon_is_required = false;
// ensure the input params are a valid object
if( !isObject( params ) ){
params = {};
}
if( !isObject( params.focus ) ){ // error & warning messages
params.focus = {}; var messages = { errors: [], warnings: [] };
}
if( !isObject( params.focus.point ) ){
params.focus.point = {};
}
try { try {
geo_common.sanitize_coord( 'lat', clean, params['focus.point.lat'], latlon_is_required ); geo_common.sanitize_coord( 'lat', clean, raw['focus.point.lat'], LAT_LON_IS_REQUIRED );
geo_common.sanitize_coord( 'lon', clean, params['focus.point.lon'], latlon_is_required ); geo_common.sanitize_coord( 'lon', clean, raw['focus.point.lon'], LAT_LON_IS_REQUIRED );
geo_common.sanitize_bbox(clean, params.bbox); geo_common.sanitize_bbox(raw, clean);
} }
catch (err) { catch (err) {
return { messages.errors.push( err.message );
'error': true,
'message': err.message
};
} }
req.clean = clean; return messages;
return { 'error': false };
}; };

129
sanitiser/_id.js

@ -1,72 +1,79 @@
var isObject = require('is-object');
var check = require('check-types'),
types = require('../query/types');
var ID_DELIM = ':';
// validate inputs, convert types and apply defaults // validate inputs, convert types and apply defaults
// id generally looks like 'geoname:4163334' (type:id) // id generally looks like 'geoname:4163334' (type:id)
// so, both type and id are required fields. // so, both type and id are required fields.
function sanitize( req ){ function errorMessage(fieldname, message) {
req.clean = req.clean || {}; return message || 'invalid param \''+ fieldname + '\': text length, must be >0';
var params = req.query; }
var types = require('../query/types');
var delim = ':'; function sanitize( raw, clean ){
// ensure params is a valid object
if( !isObject( params ) ){
params = {};
}
var errormessage = function(fieldname, message) {
return {
'error': true,
'message': message || ('invalid param \''+ fieldname + '\': text length, must be >0')
};
};
if(('string' === typeof params.id && !params.id.length) || params.id === undefined){
return errormessage('id');
}
if( params && params.id && params.id.length ){
req.clean.ids = [];
params.ids = Array.isArray(params.id) ? params.id : [params.id];
// de-dupe
params.ids = params.ids.filter(function(item, pos) {
return params.ids.indexOf(item) === pos;
});
for (var i=0; i<params.ids.length; i++) { // error & warning messages
var thisparam = params.ids[i]; var messages = { errors: [], warnings: [] };
// basic format/ presence of ':' // 'raw.id' can be an array!?
if(thisparam.indexOf(delim) === -1) { var rawIds = check.array( raw.id ) ? raw.id : [ raw.id ];
return errormessage(null, 'invalid: must be of the format type:id for ex: \'geoname:4163334\'');
} // de-dupe ids
rawIds = rawIds.filter(function(item, pos) {
var param_index = thisparam.indexOf(delim); return rawIds.indexOf( item ) === pos;
var type = thisparam.substring(0, param_index ); });
var id = thisparam.substring(param_index + 1);
// ensure all elements are valid non-empty strings
// id text rawIds = rawIds.filter( function( uc ){
if('string' !== typeof id || !id.length){ if( !check.unemptyString( uc ) ){
return errormessage(thisparam); messages.errors.push( errorMessage('id') );
} return false;
// type text
if('string' !== typeof type || !type.length){
return errormessage(thisparam);
}
// type text must be one of the types
if(types.indexOf(type) === -1){
return errormessage('type', type + ' is invalid. It must be one of these values - [' + types.join(', ') + ']');
}
req.clean.ids.push({
id: id,
type: type
});
} }
} return true;
});
// init 'clean.ids'
clean.ids = [];
// cycle through raw ids and set those which are valid
rawIds.forEach( function( rawId ){
var param_index = rawId.indexOf(ID_DELIM);
var type = rawId.substring(0, param_index );
var id = rawId.substring(param_index + 1);
// basic format/ presence of ':'
if(param_index === -1) {
messages.errors.push(
errorMessage(null, 'invalid: must be of the format type:id for ex: \'geoname:4163334\'')
);
}
// id text
if( !check.unemptyString( id ) ){
messages.errors.push( errorMessage( rawId ) );
}
// type text
if( !check.unemptyString( type ) ){
messages.errors.push( errorMessage( rawId ) );
}
// type text must be one of the types
if( types.indexOf( type ) === -1 ){
messages.errors.push(
errorMessage('type', type + ' is invalid. It must be one of these values - [' + types.join(', ') + ']')
);
}
// add valid id to 'clean.ids' array
clean.ids.push({
id: id,
type: type
});
});
return { 'error': false }; return messages;
} }
// export function // export function

62
sanitiser/_layers.js

@ -1,51 +1,45 @@
var isObject = require('is-object'), var check = require('check-types'),
types = require('../query/types'), types = require('../query/types'),
get_layers = require('../helper/layers'); get_layers = require('../helper/layers');
// decide which layers can be queried
var ALIAS_LAYERS = ['poi', 'admin', 'address'],
ALIAS_TYPES = types.concat(ALIAS_LAYERS),
ALIAS_TYPES_JOINED = ALIAS_TYPES.join(',');
// validate inputs, convert types and apply defaults // validate inputs, convert types and apply defaults
function sanitize( req ){ function sanitize( raw, clean ){
var clean = req.clean || {};
var params= req.query;
clean.types = clean.types || {}; // error & warning messages
var messages = { errors: [], warnings: [] };
// ensure the input params are a valid object // init clean.types
if( !isObject( params ) ){ clean.types = clean.types || {};
params = {};
}
// default case (no layers specified in GET params) // default case (no layers specified in GET params)
// don't even set the from_layers key in this case // don't even set the from_layers key in this case
if('string' !== typeof params.layers || !params.layers.length){ if( check.unemptyString( raw.layers ) ){
return { 'error': false };
} // parse GET params
var layers = raw.layers.split(',').map( function( layer ){
return layer.toLowerCase(); // lowercase inputs
});
// validate layer names
for( var x=0; x<layers.length; x++ ){
if( -1 === ALIAS_TYPES.indexOf( layers[x] ) ){
messages.errors.push('invalid param \'layers\': must be one or more of ' + ALIAS_TYPES_JOINED);
}
}
// decide which layers can be queried // set 'from_layers' param
var alias_layers = ['poi', 'admin', 'address']; if( !messages.errors.length ){
var alias_types = types.concat(alias_layers); clean.types.from_layers = get_layers(layers);
// parse GET params
var layers = params.layers.split(',').map( function( layer ){
return layer.toLowerCase(); // lowercase inputs
});
// validate layer names
for( var x=0; x<layers.length; x++ ){
if( -1 === alias_types.indexOf( layers[x] ) ){
return {
'error': true,
'message': 'invalid param \'layers\': must be one or more of ' + alias_types.join(',')
};
} }
} }
// pass validated params to next middleware return messages;
clean.types.from_layers = get_layers(layers);
req.clean = clean;
return { 'error': false };
} }
// export function // export function

17
sanitiser/_sanitize.js

@ -1,17 +0,0 @@
function sanitize( req, sanitiser, cb ){
req.clean = req.clean || {};
for (var s in sanitiser) {
var sanity = sanitiser[s](req);
if (sanity.error) {
return cb(sanity.message);
}
}
return cb( undefined, req.clean );
}
// export function
module.exports = sanitize;

53
sanitiser/_size.js

@ -1,30 +1,47 @@
var isObject = require('is-object');
var MIN_SIZE = 1,
MAX_SIZE = 40,
DEFAULT_SIZE = 10;
// validate inputs, convert types and apply defaults // validate inputs, convert types and apply defaults
function sanitize( req, default_size){ function sanitize( raw, clean ){
var clean = req.clean || {}; // error & warning messages
var params= req.query; var messages = { errors: [], warnings: [] };
default_size = default_size || 10; // coercions
var _size = parseInt( raw.size, 10 );
// ensure the input params are a valid object // invalid numeric input
if( !isObject( params ) ){ // @todo: this can be removed now as queries have default sizes?
params = {}; if( isNaN( _size ) ){
}
// total results // set the default size
var size = parseInt( params.size, 10 ); messages.warnings.push('invalid integer \'size\', using DEFAULT_SIZE');
if( !isNaN( size ) ){ clean.size = DEFAULT_SIZE;
clean.size = Math.min( Math.max( size, 1 ), 40 ); // max
} else {
clean.size = default_size; // default
} }
// valid numeric input
else {
// ensure size falls within defined range
if( _size > MAX_SIZE ){
// set the max size
messages.warnings.push('out-of-range integer \'size\', using MAX_SIZE');
clean.size = MAX_SIZE;
}
else if( _size < MIN_SIZE ){
// set the min size
messages.warnings.push('out-of-range integer \'size\', using MIN_SIZE');
clean.size = MIN_SIZE;
}
else {
// set the input size
clean.size = _size;
}
req.clean = clean; }
return {'error':false};
return messages;
} }
// export function // export function

59
sanitiser/_source.js

@ -1,44 +1,45 @@
var isObject = require('is-object');
var sources_map = require( '../query/sources' );
var all_sources = Object.keys(sources_map);
function sanitize( req ) { var check = require('check-types'),
req.clean = req.clean || {}; sources_map = require( '../query/sources' );
var params = req.query;
req.clean.types = req.clean.types || {}; var ALL_SOURCES = Object.keys(sources_map),
ALL_SOURCES_JOINED = ALL_SOURCES.join(',');
// ensure the input params are a valid object function sanitize( raw, clean ) {
if( !isObject( params ) ){
params = {}; // error & warning messages
} var messages = { errors: [], warnings: [] };
// init clean.types (if not already init)
clean.types = clean.types || {};
// default case (no layers specified in GET params) // default case (no layers specified in GET params)
// don't even set the from_layers key in this case // don't even set the from_layers key in this case
if('string' !== typeof params.source || !params.source.length){ if( check.unemptyString( raw.source ) ){
return { error: false };
}
var sources = params.source.split(','); var sources = raw.source.split(',');
var invalid_sources = sources.filter(function(source) { var invalid_sources = sources.filter(function(source) {
return all_sources.indexOf(source) === -1; return ALL_SOURCES.indexOf(source) === -1;
}); });
if (invalid_sources.length > 0) { if( invalid_sources.length > 0 ){
return { invalid_sources.forEach( function( invalid ){
error: true, messages.errors.push('\'' + invalid + '\' is an invalid source parameter. Valid options: ' + ALL_SOURCES_JOINED);
msg: '`' + invalid_sources[0] + '` is an invalid source parameter. Valid options: ' + all_sources.join(', ') });
}; }
}
else {
var types = sources.reduce(function(acc, source) {
return acc.concat(sources_map[source]);
}, []);
var types = sources.reduce(function(acc, source) { clean.types.from_source = types;
return acc.concat(sources_map[source]); }
}, []);
req.clean.types.from_source = types; }
return { error: false }; return messages;
} }
module.exports = sanitize; module.exports = sanitize;

41
sanitiser/_text.js

@ -1,32 +1,33 @@
var isObject = require('is-object');
var query_parser = require('../helper/query_parser'); var check = require('check-types'),
query_parser = require('../helper/query_parser');
// validate texts, convert types and apply defaults // validate texts, convert types and apply defaults
function sanitize( req ){ function sanitize( raw, clean ){
req.clean = req.clean || {};
var params= req.query;
// ensure the text params are a valid object // error & warning messages
if( !isObject( params ) ){ var messages = { errors: [], warnings: [] };
params = {};
}
// text text // invalid input 'text'
if('string' !== typeof params.text || !params.text.length){ if( !check.unemptyString( raw.text ) ){
return { messages.errors.push('invalid param \'text\': text length, must be >0');
'error': true,
'message': 'invalid param \'text\': text length, must be >0'
};
} }
req.clean.text = params.text; // valid input 'text'
else {
req.clean.parsed_text = query_parser.get_parsed_address(params.text); // valid text
clean.text = raw.text;
req.clean.types = req.clean.layers || {}; // parse text with query parser
req.clean.types.from_address_parsing = query_parser.get_layers(params.text); clean.parsed_text = query_parser.get_parsed_address(clean.text);
// try to set layers from query parser results
clean.types = clean.layers || {};
clean.types.from_address_parsing = query_parser.get_layers(clean.text);
}
return { 'error': false }; return messages;
} }
// export function // export function

5
sanitiser/place.js

@ -1,10 +1,11 @@
var _sanitize = require('../sanitiser/_sanitize'),
var sanitizeAll = require('../sanitiser/sanitizeAll'),
sanitizers = { sanitizers = {
id: require('../sanitiser/_id'), id: require('../sanitiser/_id'),
details: require('../sanitiser/_details') details: require('../sanitiser/_details')
}; };
var sanitize = function(req, cb) { _sanitize(req, sanitizers, cb); }; var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); };
// export sanitize for testing // export sanitize for testing
module.exports.sanitize = sanitize; module.exports.sanitize = sanitize;

18
sanitiser/reverse.js

@ -1,17 +1,15 @@
var _sanitize = require('../sanitiser/_sanitize'),
sanitiser = { var sanitizeAll = require('../sanitiser/sanitizeAll'),
latlonzoom: require('../sanitiser/_geo_reverse'), sanitizers = {
layers: require('../sanitiser/_layers'), layers: require('../sanitiser/_layers'),
suorce: require('../sanitiser/_source'),
details: require('../sanitiser/_details'),
size: require('../sanitiser/_size'), size: require('../sanitiser/_size'),
categories: function ( req ) { source: require('../sanitiser/_source'),
var categories = require('../sanitiser/_categories'); details: require('../sanitiser/_details'),
return categories(req); geo_reverse: require('../sanitiser/_geo_reverse'),
} categories: require('../sanitiser/_categories')
}; };
var sanitize = function(req, cb) { _sanitize(req, sanitiser, cb); }; var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); };
// export sanitize for testing // export sanitize for testing
module.exports.sanitize = sanitize; module.exports.sanitize = sanitize;

26
sanitiser/sanitizeAll.js

@ -0,0 +1,26 @@
function sanitize( req, sanitizers, cb ){
// init an object to store clean
// (sanitized) input parameters
req.clean = {};
// source of input parameters
// (in this case from the GET querystring params)
var params = req.query || {};
for (var s in sanitizers) {
var sanity = sanitizers[s]( params, req.clean );
// errors
if( sanity.errors.length ){
return cb( sanity.errors[0] );
}
}
return cb( undefined, req.clean );
}
// export function
module.exports = sanitize;

8
sanitiser/search.js

@ -1,15 +1,15 @@
var _sanitize = require('../sanitiser/_sanitize'), var sanitizeAll = require('../sanitiser/sanitizeAll'),
sanitizers = { sanitizers = {
text: require('../sanitiser/_text'), text: require('../sanitiser/_text'),
size: require('../sanitiser/_size'),
layers: require('../sanitiser/_layers'), layers: require('../sanitiser/_layers'),
size: require('../sanitiser/_size'),
source: require('../sanitiser/_source'), source: require('../sanitiser/_source'),
details: require('../sanitiser/_details'), details: require('../sanitiser/_details'),
latlonzoom: require('../sanitiser/_geo_search') geo_search: require('../sanitiser/_geo_search')
}; };
var sanitize = function(req, cb) { _sanitize(req, sanitizers, cb); }; var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); };
// export sanitize for testing // export sanitize for testing
module.exports.sanitize = sanitize; module.exports.sanitize = sanitize;

51
test/unit/sanitiser/_source.js

@ -7,13 +7,15 @@ module.exports.tests = {};
module.exports.tests.no_sources = function(test, common) { module.exports.tests.no_sources = function(test, common) {
test('source is not set', function(t) { test('source is not set', function(t) {
var req = { var req = {
query: { } query: { },
clean: { }
}; };
var response = sanitize(req); var response = sanitize(req.query, req.clean);
t.deepEqual(req.clean.types, {}, 'clean.types should be empty object'); t.deepEqual(req.clean.types, {}, 'clean.types should be empty object');
t.deepEqual(response, success_response, 'no error returned'); t.deepEqual(response.errors, [], 'no error returned');
t.deepEqual(response.warnings, [], 'no warnings returned');
t.end(); t.end();
}); });
@ -21,13 +23,15 @@ module.exports.tests.no_sources = function(test, common) {
var req = { var req = {
query: { query: {
source: '' source: ''
} },
clean: { }
}; };
var response = sanitize(req); var response = sanitize(req.query, req.clean);
t.deepEqual(req.clean.types, {}, 'clean.types should be empty object'); t.deepEqual(req.clean.types, {}, 'clean.types should be empty object');
t.deepEqual(response, success_response, 'no error returned'); t.deepEqual(response.errors, [], 'no error returned');
t.deepEqual(response.warnings, [], 'no warnings returned');
t.end(); t.end();
}); });
}; };
@ -37,13 +41,15 @@ module.exports.tests.valid_sources = function(test, common) {
var req = { var req = {
query: { query: {
source: 'geonames' source: 'geonames'
} },
clean: { }
}; };
var response = sanitize(req); var response = sanitize(req.query, req.clean);
t.deepEqual(req.clean.types, { from_source: ['geoname'] }, 'clean.types should contain from_source entry with geonames'); t.deepEqual(req.clean.types, { from_source: ['geoname'] }, 'clean.types should contain from_source entry with geonames');
t.deepEqual(response, success_response, 'no error returned'); t.deepEqual(response.errors, [], 'no error returned');
t.deepEqual(response.warnings, [], 'no warnings returned');
t.end(); t.end();
}); });
@ -51,16 +57,18 @@ module.exports.tests.valid_sources = function(test, common) {
var req = { var req = {
query: { query: {
source: 'openstreetmap' source: 'openstreetmap'
} },
clean: { }
}; };
var expected_types = { var expected_types = {
from_source: ['osmaddress', 'osmnode', 'osmway'] from_source: ['osmaddress', 'osmnode', 'osmway']
}; };
var response = sanitize(req); var response = sanitize(req.query, req.clean);
t.deepEqual(req.clean.types, expected_types, 'clean.types should contain from_source entry with multiple entries for openstreetmap'); t.deepEqual(req.clean.types, expected_types, 'clean.types should contain from_source entry with multiple entries for openstreetmap');
t.deepEqual(response, success_response, 'no error returned'); t.deepEqual(response.errors, [], 'no error returned');
t.deepEqual(response.warnings, [], 'no warnings returned');
t.end(); t.end();
}); });
@ -68,17 +76,19 @@ module.exports.tests.valid_sources = function(test, common) {
var req = { var req = {
query: { query: {
source: 'openstreetmap,openaddresses' source: 'openstreetmap,openaddresses'
} },
clean: { }
}; };
var expected_types = { var expected_types = {
from_source: ['osmaddress', 'osmnode', 'osmway', 'openaddresses'] from_source: ['osmaddress', 'osmnode', 'osmway', 'openaddresses']
}; };
var response = sanitize(req); var response = sanitize(req.query, req.clean);
t.deepEqual(req.clean.types, expected_types, t.deepEqual(req.clean.types, expected_types,
'clean.types should contain from_source entry with multiple entries for openstreetmap and openadresses'); 'clean.types should contain from_source entry with multiple entries for openstreetmap and openadresses');
t.deepEqual(response, success_response, 'no error returned'); t.deepEqual(response.errors, [], 'no error returned');
t.deepEqual(response.warnings, [], 'no warnings returned');
t.end(); t.end();
}); });
}; };
@ -88,14 +98,17 @@ module.exports.tests.invalid_sources = function(test, common) {
var req = { var req = {
query: { query: {
source: 'notasource' source: 'notasource'
} },
clean: { }
}; };
var expected_response = { var expected_response = {
error: true, errors: [
msg: '`notasource` is an invalid source parameter. Valid options: geonames, openaddresses, quattroshapes, openstreetmap' '\'notasource\' is an invalid source parameter. Valid options: geonames,openaddresses,quattroshapes,openstreetmap'
],
warnings: []
}; };
var response = sanitize(req); var response = sanitize(req.query, req.clean);
t.deepEqual(response, expected_response, 'error with message returned'); t.deepEqual(response, expected_response, 'error with message returned');
t.deepEqual(req.clean.types, { }, 'clean.types should remain empty'); t.deepEqual(req.clean.types, { }, 'clean.types should remain empty');

8
test/unit/sanitiser/search.js

@ -291,6 +291,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
test('poi (alias) layer', function(t) { test('poi (alias) layer', function(t) {
var poi_layers = ['geoname','osmnode','osmway']; var poi_layers = ['geoname','osmnode','osmway'];
sanitize({ layers: 'poi', text: 'test' }, function( err, clean ){ sanitize({ layers: 'poi', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers set'); t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers set');
t.end(); t.end();
}); });
@ -298,6 +299,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
test('admin (alias) layer', function(t) { test('admin (alias) layer', function(t) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin']; var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
sanitize({ layers: 'admin', text: 'test' }, function( err, clean ){ sanitize({ layers: 'admin', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, admin_layers, 'admin layers set'); t.deepEqual(clean.types.from_layers, admin_layers, 'admin layers set');
t.end(); t.end();
}); });
@ -305,6 +307,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
test('address (alias) layer', function(t) { test('address (alias) layer', function(t) {
var address_layers = ['osmaddress','openaddresses']; var address_layers = ['osmaddress','openaddresses'];
sanitize({ layers: 'address', text: 'test' }, function( err, clean ){ sanitize({ layers: 'address', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, address_layers, 'types from layers set'); t.deepEqual(clean.types.from_layers, address_layers, 'types from layers set');
t.deepEqual(clean.types.from_address_parser, _text.allLayers, 'address parser uses default layers'); t.deepEqual(clean.types.from_address_parser, _text.allLayers, 'address parser uses default layers');
t.end(); t.end();
@ -314,6 +317,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
var poi_layers = ['geoname','osmnode','osmway']; var poi_layers = ['geoname','osmnode','osmway'];
var reg_layers = ['admin0', 'admin1']; var reg_layers = ['admin0', 'admin1'];
sanitize({ layers: 'poi,admin0,admin1', text: 'test' }, function( err, clean ){ sanitize({ layers: 'poi,admin0,admin1', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, reg_layers.concat(poi_layers), 'poi + regular layers'); t.deepEqual(clean.types.from_layers, reg_layers.concat(poi_layers), 'poi + regular layers');
t.end(); t.end();
}); });
@ -322,6 +326,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin']; var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
var reg_layers = ['geoname', 'osmway']; var reg_layers = ['geoname', 'osmway'];
sanitize({ layers: 'admin,geoname,osmway', text: 'test' }, function( err, clean ){ sanitize({ layers: 'admin,geoname,osmway', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, reg_layers.concat(admin_layers), 'admin + regular layers set'); t.deepEqual(clean.types.from_layers, reg_layers.concat(admin_layers), 'admin + regular layers set');
t.end(); t.end();
}); });
@ -330,6 +335,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
var address_layers = ['osmaddress','openaddresses']; var address_layers = ['osmaddress','openaddresses'];
var reg_layers = ['geoname', 'osmway']; var reg_layers = ['geoname', 'osmway'];
sanitize({ layers: 'address,geoname,osmway', text: 'test' }, function( err, clean ){ sanitize({ layers: 'address,geoname,osmway', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, reg_layers.concat(address_layers), 'address + regular layers set'); t.deepEqual(clean.types.from_layers, reg_layers.concat(address_layers), 'address + regular layers set');
t.end(); t.end();
}); });
@ -337,6 +343,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
test('alias layer plus regular layers (no duplicates)', function(t) { test('alias layer plus regular layers (no duplicates)', function(t) {
var poi_layers = ['geoname','osmnode','osmway']; var poi_layers = ['geoname','osmnode','osmway'];
sanitize({ layers: 'poi,geoname,osmnode', text: 'test' }, function( err, clean ){ sanitize({ layers: 'poi,geoname,osmnode', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers found (no duplicates)'); t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers found (no duplicates)');
t.end(); t.end();
}); });
@ -344,6 +351,7 @@ module.exports.tests.sanitize_layers = function(test, common) {
test('multiple alias layers (no duplicates)', function(t) { test('multiple alias layers (no duplicates)', function(t) {
var alias_layers = ['geoname','osmnode','osmway','admin0','admin1','admin2','neighborhood','locality','local_admin']; var alias_layers = ['geoname','osmnode','osmway','admin0','admin1','admin2','neighborhood','locality','local_admin'];
sanitize({ layers: 'poi,admin', text: 'test' }, function( err, clean ){ sanitize({ layers: 'poi,admin', text: 'test' }, function( err, clean ){
t.equal(err, undefined);
t.deepEqual(clean.types.from_layers, alias_layers, 'all layers found (no duplicates)'); t.deepEqual(clean.types.from_layers, alias_layers, 'all layers found (no duplicates)');
t.end(); t.end();
}); });

Loading…
Cancel
Save