You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

160 lines
4.7 KiB

/**
* helper sanitizer methods for geo parameters
*/
var groups = require('./_groups'),
check = require('check-types'),
wrap = require('./wrap'),
_ = require('lodash');
/**
* Parse and validate rect parameter
*
* @param {string} key_prefix
* @param {object} clean
* @param {object} raw
* @param {bool} bbox_is_required
*/
function sanitize_rect( key_prefix, clean, raw, bbox_is_required ) {
// calculate full property names from the key_prefix
var properties = [ 'min_lat', 'max_lat', 'min_lon', 'max_lon' ].map(function(prop) {
return key_prefix + '.' + prop;
});
// sanitize the rect property group, this throws an exception if
// the group is not complete
var bbox_present;
if (bbox_is_required) {
bbox_present = groups.required(raw, properties);
} else {
bbox_present = groups.optional(raw, properties);
}
// don't bother checking individual elements if bbox is not required
// and not present
if (!bbox_present) { return; }
sanitize_bbox_min_max(raw, key_prefix);
sanitize_bbox_bounds(raw, key_prefix);
// use sanitize_coord to set values in `clean`
properties.forEach(function(prop) {
sanitize_coord(prop, clean, raw, true);
});
}
// validate max is greater than min for lat and lon
function sanitize_bbox_min_max(raw, key_prefix) {
['lat', 'lon'].forEach(function(dimension) {
const max = parseFloat(raw[`${key_prefix}.max_${dimension}`]);
const min = parseFloat(raw[`${key_prefix}.min_${dimension}`]);
if (max <= min) {
throw new Error(`${key_prefix}.min_${dimension} (${min}) must be less than ${key_prefix}.max_${dimension} (${max})`);
}
});
}
// validate lat/lon values are within bounds
function sanitize_bbox_bounds(raw, key_prefix) {
const bounds = [ { dimension: 'lat', range: 90},
{ dimension: 'lon', range: 180}];
bounds.forEach(function(bound) {
const values = {
max: parseFloat(raw[`${key_prefix}.max_${bound.dimension}`]),
min: parseFloat(raw[`${key_prefix}.min_${bound.dimension}`])
};
['min', 'max'].forEach(function(prefix) {
if (Math.abs(values[prefix]) > bound.range) {
const key =`${key_prefix}.${prefix}_${bound.dimension}`;
throw new Error(`${key} value ${values[prefix]} is outside range -${bound.range},${bound.range}`);
}
});
});
}
/**
* Parse and validate circle parameter
*
* @param {string} key_prefix
* @param {object} clean
* @param {object} raw
* @param {bool} circle_is_required
*/
function sanitize_circle( key_prefix, clean, raw, circle_is_required ) {
// sanitize both a point and a radius if radius is present
// otherwise just sanittize the point
if( check.assigned( raw[ key_prefix + '.radius' ] ) ){
sanitize_coord( key_prefix + '.radius', clean, raw, true );
sanitize_point( key_prefix, clean, raw, true);
} else {
sanitize_point( key_prefix, clean, raw, circle_is_required);
}
}
/**
* Parse and validate point parameter
*
* @param {string} key_prefix
* @param {object} clean
* @param {object} raw
* @param {bool} point_is_required
*/
function sanitize_point( key_prefix, clean, raw, point_is_required ) {
// calculate full property names from the key_prefix
var properties = [ 'lat', 'lon'].map(function(prop) {
return key_prefix + '.' + prop;
});
// sanitize the rect property group, this throws an exception if
// the group is not complete
var point_present;
if (point_is_required) {
point_present = groups.required(raw, properties);
} else {
point_present = groups.optional(raw, properties);
}
// don't bother checking individual elements if point is not required
// and not present
if (!point_present) { return; }
// check each property individually. now that it is known a bbox is present,
// all properties must exist, so pass the true flag for coord_is_required
properties.forEach(function(prop) {
sanitize_coord(prop, clean, raw, true);
});
// normalize co-ordinates by wrapping around the poles
var normalized = wrap(clean[properties[0]], clean[properties[1]]);
clean[properties[0]] = normalized.lat;
clean[properties[1]] = normalized.lon;
}
/**
* Validate lat,lon values
*
* @param {string} key - which key to validate
* @param {object} clean - cleaned parameters object
* @param {object} raw - the raw request object
* @param {bool} latlon_is_required
*/
function sanitize_coord( key, clean, raw, latlon_is_required ) {
var parsedValue = parseFloat( raw[key] );
if ( _.isFinite( parsedValue ) ) {
clean[key] = parsedValue;
}
else if (latlon_is_required) {
throw new Error(`missing param '${key}'`);
}
}
module.exports = {
sanitize_rect: sanitize_rect,
sanitize_coord: sanitize_coord,
sanitize_circle: sanitize_circle,
sanitize_point: sanitize_point
};