genediazjr/disinfect

View on GitHub
lib/index.js

Summary

Maintainability
A
2 hrs
Test Coverage
'use strict';

const Caja = require('sanitizer');
const Hoek = require('@hapi/hoek');
const Joi = require('joi');
const internals = {};

internals.whiteRegex = new RegExp(/^[\s\f\n\r\t\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff\x09\x0a\x0b\x0c\x0d\x20\xa0]+$/);

internals.noop = (obj) => {

    return obj;
};

internals.recurseObj = (item, index, array) => {
    if (typeof array[index] === 'object') {
        array[index] = internals.sanitize(array[index]);
    }
    else {
        array[index] = Caja.sanitize(array[index]);
    }
};

internals.sanitize = (obj) => {

    const keys = Object.keys(obj);
    for (let i = 0; i < keys.length; ++i) {
        if (obj[keys[i]] !== null) {
            if (typeof obj[keys[i]] === 'object') {
                if (Array.isArray(obj[keys[i]])) {
                    obj[keys[i]].forEach(internals.recurseObj);
                }
                else {
                    obj[keys[i]] = internals.sanitize(obj[keys[i]]);
                }
            }
            else if (typeof obj === 'object') {
                obj[keys[i]] = Caja.sanitize(obj[keys[i]]);
            }
        }
    }
    return obj;
};

internals.deleteEmpty = (obj) => {

    const keys = Object.keys(obj);

    for (let i = 0; i < keys.length; ++i) {
        if (obj[keys[i]] === '' || obj[keys[i]] === null) {
            delete obj[keys[i]];
        }
    }

    return obj;
};

internals.deleteWhitespace = (obj) => {

    const keys = Object.keys(obj);

    for (let i = 0; i < keys.length; ++i) {
        if (internals.whiteRegex.test(obj[keys[i]])) {
            delete obj[keys[i]];
        }
    }

    return obj;
};

internals.disinfect = (inputObj, options, firstPass, secondPass) => {

    let cleansed = inputObj;
    if (cleansed && Object.keys(cleansed).length) {

        if (options[firstPass]) {
            cleansed = internals.sanitize(cleansed);
        }
        cleansed = options.genericSanitizer(cleansed);
        cleansed = options[secondPass](cleansed);
        if (options.deleteWhitespace) {
            cleansed = internals.deleteWhitespace(cleansed);
        }
        if (options.deleteEmpty) {
            cleansed = internals.deleteEmpty(cleansed);
        }
    }

    return cleansed;
};

internals.schema = Joi.object().keys({
    deleteEmpty: Joi.boolean().optional(),
    deleteWhitespace: Joi.boolean().optional(),
    disinfectQuery: Joi.boolean().optional(),
    disinfectParams: Joi.boolean().optional(),
    disinfectPayload: Joi.boolean().optional(),
    genericSanitizer: Joi.func().optional(),
    querySanitizer: Joi.func().optional(),
    paramsSanitizer: Joi.func().optional(),
    payloadSanitizer: Joi.func().optional()
});

internals.defaults = {
    deleteEmpty: false,
    deleteWhitespace: false,
    disinfectQuery: false,
    disinfectParams: false,
    disinfectPayload: false,
    genericSanitizer: internals.noop,
    querySanitizer: internals.noop,
    paramsSanitizer: internals.noop,
    payloadSanitizer: internals.noop
};


exports.plugin = {
    register: (server, options) => {

        const validateOptions = internals.schema.validate(options);
        if (validateOptions.error) {
            throw validateOptions.error;
        }

        const serverSettings = Hoek.applyToDefaults(internals.defaults, options);

        server.ext('onPostAuth', (request, reply) => {

            if (request.route.settings.plugins.disinfect === false) {
                return reply.continue;
            }

            if (request.payload || Object.keys(request.params).length || Object.keys(request.query).length) {

                request.route.settings.plugins._disinfect = Hoek.applyToDefaults(serverSettings, request.route.settings.plugins.disinfect || {});

                request.query = internals.disinfect(request.query, request.route.settings.plugins._disinfect, 'disinfectQuery', 'querySanitizer');
                request.params = internals.disinfect(request.params, request.route.settings.plugins._disinfect, 'disinfectParams', 'paramsSanitizer');
                request.payload = internals.disinfect(request.payload, request.route.settings.plugins._disinfect, 'disinfectPayload', 'payloadSanitizer');
            }

            return reply.continue;
        });
    },
    pkg: require('../package.json')
};