<commit_before>/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/* Password Reset handlers (invoked by router to render templates)                                */
/*                                                                                                */
/* GET functions render template pages; POST functions process post requests then redirect.       */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

'use strict';

const crypto = require('crypto');     // nodejs.org/api/crypto.html
const Scrypt = require('scrypt-kdf'); // scrypt key derivation function

const User = require('../../models/user.js');
const Mail = require('../../lib/mail.js');

/*
 * Password reset sequence is:
 * - GET  /password/reset-request
 * - POST /password/reset-request with email; 302 ->
 * - GET  /password/reset-request-confirm
 * - e-mail is sent to 'email' with reset link '/password/reset/{token}'
 * - GET  /password/reset/{token}
 * - POST /password/reset/{token} with password & passwordConfirm; 302 ->
 * - GET  /password/reset/confirm
 */


class PasswordResetHandlers {

    /**
     * GET /password/reset-request - render request password reset page
     */
    static async request(ctx) {
        await ctx.render('password-reset-request');
    }


    /**
     * POST /password/reset-request - process request password reset
     *
     * Send e-mail with password reset link
     */
    static async processRequest(ctx) {
        const email = ctx.request.body.email;

        const [ user ] = await User.getBy('email', email);

        // current timestamp for token expiry in base36
        const now = Math.floor(Date.now()/1000).toString(36);

        // random sha256 hash; 1st 8 chars of hash in base36 gives 42 bits of entropy
        const hash = crypto.createHash('sha256').update(Math.random().toString());
        const rndHash = parseInt(hash.digest('hex'), 16).toString(36).slice(0, 8);
        const token = now+'-'+rndHash; // note use timestamp first so it is easier to identify old tokens in db

        // note: do createHash() before checking if user exists to mitigate against timing attacks
        if (!user) { ctx.redirect('/password/reset-request-confirm'); return; }

        // record reset request in db
        await User.update(user.UserId, { PasswordResetRequest: token });

        // send e-mail with generated token
        const context = { firstname: user.firstname, host: ctx.host, token: token };
        const info = await Mail.send(email, 'password-reset.email', context);

        ctx.set('X-Reset-Token', token);               // for testing
        ctx.set('X-Sendmail-Response', info.response); // for testing

        ctx.redirect('/password/reset-request-confirm');
    }
<commit_msg>Fix case of db fields<commit_after>/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/* Password Reset handlers (invoked by router to render templates)                                */
/*                                                                                                */
/* GET functions render template pages; POST functions process post requests then redirect.       */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

'use strict';

const crypto = require('crypto');     // nodejs.org/api/crypto.html
const Scrypt = require('scrypt-kdf'); // scrypt key derivation function

const User = require('../../models/user.js');
const Mail = require('../../lib/mail.js');

/*
 * Password reset sequence is:
 * - GET  /password/reset-request
 * - POST /password/reset-request with email; 302 ->
 * - GET  /password/reset-request-confirm
 * - e-mail is sent to 'email' with reset link '/password/reset/{token}'
 * - GET  /password/reset/{token}
 * - POST /password/reset/{token} with password & passwordConfirm; 302 ->
 * - GET  /password/reset/confirm
 */


class PasswordResetHandlers {

    /**
     * GET /password/reset-request - render request password reset page
     */
    static async request(ctx) {
        await ctx.render('password-reset-request');
    }


    /**
     * POST /password/reset-request - process request password reset
     *
     * Send e-mail with password reset link
     */
    static async processRequest(ctx) {
        const email = ctx.request.body.email;

        const [ user ] = await User.getBy('Email', email);

        // current timestamp for token expiry in base36
        const now = Math.floor(Date.now()/1000).toString(36);

        // random sha256 hash; 1st 8 chars of hash in base36 gives 42 bits of entropy
        const hash = crypto.createHash('sha256').update(Math.random().toString());
        const rndHash = parseInt(hash.digest('hex'), 16).toString(36).slice(0, 8);
        const token = now+'-'+rndHash; // note use timestamp first so it is easier to identify old tokens in db

        // note: do createHash() before checking if user exists to mitigate against timing attacks
        if (!user) { ctx.redirect('/password/reset-request-confirm'); return; }

        // record reset request in db
        await User.update(user.UserId, { PasswordResetRequest: token });

        // send e-mail with generated token
        const context = { firstname: user.Firstname, host: ctx.host, token: token };
        const info = await Mail.send(email, 'password-reset.email', context);

        ctx.set('X-Reset-Token', token); // for testing
        ctx.set('X-Sendmail-Response', info.response); // for testing

        ctx.redirect('/password/reset-request-confirm');
    }

{'fraction_non_alphanumeric': 0.15381907778951073, 'fraction_numerical': 0.011263639563533967, 'mean_word_length': 1.8344139650872817, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1768884', 'n_tokens_mistral': 1652, 'n_tokens_neox': 1557, 'n_words': 432}