Plato on Github
Report Home
lib/validation.js
Maintainability
62.60
Lines of code
228
Difficulty
59.13
Estimated Errors
1.94
Function weight
By Complexity
By SLOC
'use strict'; // Load modules const Boom = require('boom'); const Hoek = require('hoek'); const Joi = require('joi'); // Declare internals const internals = {}; exports.compile = function (rule) { // null, undefined, true - anything allowed // false - nothing allowed // {...} - ... allowed return (rule === false ? Joi.object({}).allow(null) : typeof rule === 'function' ? rule : !rule || rule === true ? null // false tested earlier : Joi.compile(rule)); }; exports.query = function (request, next) { return internals.input('query', request, next); }; exports.payload = function (request, next) { if (request.method === 'get' || request.method === 'head') { // When route.method is '*' return next(); } return internals.input('payload', request, next); }; exports.params = function (request, next) { return internals.input('params', request, next); }; exports.headers = function (request, next) { return internals.input('headers', request, next); }; internals.input = function (source, request, next) { const postValidate = (err, value) => { request.orig[source] = request[source]; if (value !== undefined) { request[source] = value; } if (!err) { return next(); } if (err.isDeveloperError) { return next(err); } // failAction: 'error', 'log', 'ignore', function (source, err, next) if (request.route.settings.validate.failAction === 'ignore') { return next(); } // Prepare error const error = (err.isBoom ? err : Boom.badRequest(err.message, err)); error.output.payload.validation = { source: source, keys: [] }; if (err.details) { for (let i = 0; i < err.details.length; ++i) { error.output.payload.validation.keys.push(Hoek.escapeHtml(err.details[i].path)); } } if (request.route.settings.validate.errorFields) { const fields = Object.keys(request.route.settings.validate.errorFields); for (let i = 0; i < fields.length; ++i) { const field = fields[i]; error.output.payload[field] = request.route.settings.validate.errorFields[field]; } } request._log(['validation', 'error', source], error); // Log only if (request.route.settings.validate.failAction === 'log') { return next(); } // Return error if (typeof request.route.settings.validate.failAction !== 'function') { return next(error); } // Custom handler request._protect.run(next, (exit) => { const reply = request.server._replier.interface(request, request.route.realm, exit); request.route.settings.validate.failAction(request, reply, source, error); }); }; const localOptions = { context: { headers: request.headers, params: request.params, query: request.query, payload: request.payload, auth: request.auth } }; delete localOptions.context[source]; Hoek.merge(localOptions, request.route.settings.validate.options); const schema = request.route.settings.validate[source]; if (typeof schema !== 'function') { return Joi.validate(request[source], schema, localOptions, postValidate); } request._protect.run(postValidate, (exit) => { return schema(request[source], localOptions, exit); }); }; exports.response = function (request, next) { if (request.route.settings.response.sample) { const currentSample = Math.ceil((Math.random() * 100)); if (currentSample > request.route.settings.response.sample) { return next(); } } const response = request.response; const statusCode = response.isBoom ? response.output.statusCode : response.statusCode; const statusSchema = request.route.settings.response.status[statusCode]; if (statusCode >= 400 && !statusSchema) { return next(); // Do not validate errors by default } const schema = statusSchema || request.route.settings.response.schema; if (schema === null) { return next(); // No rules } if (!response.isBoom && request.response.variety !== 'plain') { return next(Boom.badImplementation('Cannot validate non-object response')); } const postValidate = (err, value) => { if (!err) { if (value !== undefined && request.route.settings.response.modify) { if (response.isBoom) { response.output.payload = value; } else { response.source = value; } } return next(); } // failAction: 'error', 'log' if (request.route.settings.response.failAction === 'log') { request._log(['validation', 'response', 'error'], err.message); return next(); } return next(Boom.badImplementation(err.message)); }; const localOptions = { context: { headers: request.headers, params: request.params, query: request.query, payload: request.payload, auth: { isAuthenticated: request.auth.isAuthenticated, credentials: request.auth.credentials } } }; const source = response.isBoom ? response.output.payload : response.source; Hoek.merge(localOptions, request.route.settings.response.options); if (typeof schema !== 'function') { return Joi.validate(source, schema, localOptions, postValidate); } request._protect.run(postValidate, (exit) => { return schema(source, localOptions, exit); }); };