All files / modules/admin index.js

100% Statements 26/26
100% Branches 4/4
100% Functions 5/5
100% Lines 26/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110      5x 5x 5x 5x 5x             5x             5x                     5x 3x 3x 1x   2x 2x 1x           1x                       5x 1x               5x 1x               5x 1x               5x 1x                         1x 1x     5x              
/**
 * @module admin
 */
const adminRepo = require("../../repositories/admin");
const jose = require("../jose");
const digest = require("../digest");
const config = require("../../config").jose.aud;
const mail = require("../mail");
 
/**
 * Temporary logs of bugreports.
 * Solely used for weekly notification of admins
 * and cleared afterwards to ensure privacy of users.
 */
const bugReports = [];
 
/**
 * Temporary logs contact requests.
 * Solely used for weekly notification of admins
 * and cleared afterwards to ensure privacy of users.
 */
const contactRequests = [];
 
/**
 * Attempt to log in admin and generate a JWE token
 * if successful.
 * Throws an error on failure with appropriate message.
 * @param {String} email
 * @param {String} password
 * @return {Object} JWE token on success
 * @throws {Error} on invalid email or password
 */
const logInAdmin = async (email, password) => {
    const findResult = await adminRepo.findByEmail(email);
    if (findResult.rows.length === 0) {
        throw new Error("Invalid admin email.");
    }
    const admin = findResult.rows[0];
    if (digest.hashPassWithSaltInHex(password, admin.salt) === admin.passwordHash) {
        return jose.signAndEncrypt({
            sub: admin.id.toString(),
            name: admin.username,
            email: email,
        });
    } else {
        throw new Error("Invalid admin password.");
    }
};
 
/**
 * Attempt to authenticate admin
 * by JWE. Upon successful verification,
 * the admin's (user)name is returned.
 * Otherwise, a JWE or JWT error is thrown.
 * @param {Object} jwe
 * @return {string} name of admin
 */
const authenticateAdmin = (jwe) => {
    return jose.decryptAndVerify(jwe, config).name;
};
 
/**
 * Log a copy of a bugreport in
 * weekly temp storage.
 * @param {Object} bugreport
 */
const logBugReport = (bugreport) => {
    bugReports.push(bugreport);
};
 
/**
 * Log a copy of a contact request in
 * weekly temp storage.
 * @param {Object} contactRequest
 */
const logContactRequest = (contactRequest) => {
    contactRequests.push(contactRequest);
};
 
/**
 * Send weekly summary of bugreports and contact
 * requests to admins, then clear temp storage
 * to ensure privacy of users.
 */
const sendSummary = () => {
    mail.sendEmail(
        process.env.DEFAULT_EMAIL_ADDRESS,
        process.env.SUMMARY_EMAIL_ADDRESS,
        "Your RDFmapped weekly summary",
        `Hello,\nHere is your rdfmapped.com weekly summary.\n\n` +
        `Number of new bugreports: ${bugReports.length}\nNumber of new contact requests: ${contactRequests.length}\n\n\n` +
        `Bug reports: ${bugReports.toString()}\n\n` +
        `Contact requests: ${contactRequests.toString()}\n\n`,
        `<p>Hello,</p><p>Here is your rdfmapped.com weekly summary.<br></p>` +
        `<p>Number of new bugreports: <b>${bugReports.length}</b></p>` +
        `<p>Number of new contact requests: <b>${contactRequests.length}</b><br></p>` +
        `<p>Bug reports: <code>${JSON.stringify(bugReports)}</code><br></p>` +
        `<p>Contact requests: <code>${JSON.stringify(contactRequests)}</code></p>`);
    bugReports.length = 0;
    contactRequests.length = 0;
};
 
module.exports = {
    logInAdmin,
    authenticateAdmin,
    logBugReport,
    logContactRequest,
    sendSummary,
};