thegameofcode/cipherlayer

View on GitHub
src/middlewares/pinValidation.js

Summary

Maintainability
B
4 hrs
Test Coverage
'use strict';

const log = require('../logger/service');
const _ = require('lodash');
const phoneMng = require('../managers/phone');
const isValidJSON = require('../managers/json_validator');
const config = require('../../config');

const errInvalidFields = {
    err: 'auth_proxy_error',
    des: 'Invalid JSON fields'
};

let _settings = {};

function pinValidation(req, res, next) {
    if (!_settings.phoneVerification || !_settings.phoneVerification.pinValidationEndpoints) {
        return next();
    }

    const endPoints = _settings.phoneVerification.pinValidationEndpoints;

    const path = String(req.url);
    const body = _.clone(req.body);
    let requiresPinValidation = false;
    let validBodySchema = false;
    let pinValidationConfig = {};

    // TODO: replace with map() or some()
    for (let i = 0; i < endPoints.length; i++) {
        const exp = endPoints[i].path;

        const check = exp.replace(/\*/g, '.*');

        const match = path.match(check);
        requiresPinValidation = (match !== null && path === match[0] && req.method.toUpperCase() === endPoints[i].method.toUpperCase());
        if (requiresPinValidation) {
            const fieldsSchema = {
                id: '/MePhones',
                type: 'object',
                properties: {},
                additionalProperties: true
            };

            fieldsSchema.properties[endPoints[i].fields.countryISO] = { type: 'string', required: true };
            fieldsSchema.properties[endPoints[i].fields.phoneNumber] = { type: 'string', required: true };

            if (isValidJSON(body, fieldsSchema)) {
                validBodySchema = true;
                pinValidationConfig = endPoints[i];
                break;
            }
        }
    }

    if (!requiresPinValidation) {
        return next();
    }
    const user = req.user;
    if (!user) {
        const err = {err: 'invalid_headers', des: 'no user in headers'};
        res.send(401, err);
        return next(err);
    }

    if (!validBodySchema) {
        log.warn('Invalid body params when checking for pin validation');
        res.send(400, errInvalidFields);
        return next(errInvalidFields);
    }

    const phone = body[pinValidationConfig.fields.phoneNumber];
    const countryISO = body[pinValidationConfig.fields.countryISO];

    const pin = req.headers ? req.headers['x-otp-pin'] : null;
    log.info({pinValidation: { user: user.id, pin }});
    phoneMng(_settings).verifyPhone(user.id, phone, countryISO, pin, function (err) {
        if (err) {
            log.error({ err }, 'Error validating phone');

            if (!err.code) {
                res.send(500, err);
                return next(err);
            }

            const errCode = err.code;
            delete(err.code);
            res.send(errCode, err);
            return next(err);
        }

        return next();
    });
}

module.exports = function (settings) {
    _settings = _.extend({}, config, settings);

    return pinValidation;
};