dbmedialab/reader-critics

View on GitHub
src/app/routes/api/suggestionHandler.ts

Summary

Maintainability
A
0 mins
Test Coverage
//
// LESERKRITIKK v2 (aka Reader Critics)
// Copyright (C) 2017 DB Medialab/Aller Media AS, Oslo, Norway
// https://github.com/dbmedialab/reader-critics/
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.
//

import {
    Request,
    Response,
} from 'express';
import { default as axios } from 'axios';

import Suggestion from 'base/Suggestion';
import { suggestionService } from 'app/services';

import { errorResponse, okResponse } from './apiResponse';
import config from 'app/config';

import * as app from 'app/util/applib';
const log = app.createLog();

const maxEmailLength = 254;
const maxCommentLength = 2000;

const adjust = (requ : Request, field : string, len : number) => (
    String(requ.body[field]).valueOf().substr(0, len)
);

function sendSuggestion(requ){
    const email = adjust(requ, 'email', maxEmailLength);
    const comment = adjust(requ, 'comment', maxCommentLength);

    const suggest : Suggestion = {
        email,
        comment,
        remote: {
            ipAddress: requ.connection.remoteAddress.toString(),
            userAgent: (requ.headers['user-agent'] || '').toString(),
        },
    };

    log('Received comment from "%s"', email);

    return suggestionService.save(suggest);
}

function getErrorCode (errorCode) {
    const ERROR_CODES = {
        'missing-input-secret': 'Unexpected Server Error (1)',
        'invalid-input-secret': 'Unexpected Server Error (2)',
        'missing-input-response': 'Missing reCAPTCHA value',
        'invalid-input-response': 'Invalid reCATPCHA value',
        'timeout-or-duplicate': 'The validation has timed out and is no longer valid',
        'bad-request': 'The request is invalid or malformed',
    };
    if (Array.isArray(errorCode)) {
        const errors = errorCode.map(function (code) {
            return getErrorCode(code);
        });
        return errors.join('\r\n');
    }
    return ERROR_CODES[errorCode] || (
        errorCode ? ('Unexpected reCAPTCHA error: ' + errorCode) : 'Unexpected reCAPTCHA error');
}

export default function(requ : Request, resp : Response) : void {
    if (!requ.body.captcha) {
        const msg = 'Missing captcha parameter';
        return errorResponse(resp, new Error(msg), msg, {
            status: 400,
        });
    }
    const secretKey = config.get('recaptcha.key.secret');
    const captchaVerifyURL = 'https://www.google.com/recaptcha/api/siteverify?secret='
    +secretKey+'&response='+requ.body.captcha+'&remoteip='+requ.connection.remoteAddress.toString();
    axios.post(captchaVerifyURL)
        .then(function(response) {
            if (response.data && response.data.success) {
                sendSuggestion(requ)
                    .then(() => {
                        okResponse(resp, { sent: true });
                    })
                    .catch(error => errorResponse(resp, error));
            } else {
                const msg = getErrorCode(response.data['error-codes']);
                errorResponse(resp, new Error(msg), msg, {
                    status: 400,
                });
            }
        });
}