routes/verify.js

/**
 * @module routes/verify
 * @author jesse reichler <mouser@donationcoder.com>
 * @copyright 5/1/19
 * @description
 * verify route for when users prove that they own an email, etc.
 */

"use strict";


// modules
const express = require("express");


// requirement service locator
const jrequire = require("../helpers/jrequire");

// models
const VerificationModel = jrequire("models/verification");

// controllers
const arserver = jrequire("arserver");

// helpers
const JrContext = require("../helpers/jrcontext");
const JrResult = require("../helpers/jrresult");














//---------------------------------------------------------------------------
function setupRouter(urlPath) {
	// create express router
	const router = express.Router();

	// setup routes
	router.get("/code/:code?", routerGetCode);
	router.post(/(code\/.*)?/, routerPostCode);
	router.get("/", routerGetIndex);

	// return router
	return router;
}
//---------------------------------------------------------------------------




//---------------------------------------------------------------------------
// router functions


async function routerGetCode(req, res, next) {
	const jrContext = JrContext.makeNew(req, res, next);
	await handleVerifyCode(jrContext, req.params.code);
}


async function routerPostCode(req, res, next) {
	const jrContext = JrContext.makeNew(req, res, next);
	// check required csrf token
	arserver.testCsrf(jrContext);

	const code = req.body.code;
	await handleVerifyCode(jrContext, code);
}


async function routerGetIndex(req, res, next) {
	const jrContext = JrContext.makeNew(req, res, next);
	res.render("account/verify", {
		jrResult: jrContext.mergeSessionMessages(),
		csrfToken: arserver.makeCsrf(jrContext),
	});
}
//---------------------------------------------------------------------------




//---------------------------------------------------------------------------
// helper functions


// this is an agnostic function that might handle all kinds of verifications (change of email, new account email, mobile text, onetime login code, multi-factor login, etc.)
async function handleVerifyCode(jrContext, code) {
	let successRedirectTo;

	// so we can check if verifying this code logs someone in
	const previouslyLoggedInUserId = arserver.getUntrustedLoggedInUserIdFromSession(jrContext);

	if (jrContext.isError()) {
		// just drop down, it's an error from the start (caller errore
	} else if (!code) {
		jrContext.pushError.makeError("Please specify the code to verify.");
	} else {
		successRedirectTo = await VerificationModel.verifiyCode(jrContext, code, {});
	}

	if (jrContext.isError()) {
		// on error, show verify form
		jrContext.res.render("account/verify", {
			jrResult: jrContext.mergeSessionMessages(),
			reqBody: jrContext.req.body,
			csrfToken: arserver.makeCsrf(jrContext),
		});
		return;
	}


	// success -- redirect and show flash message about success
	jrContext.addToThisSession();

	// if they are NOW logged in (and weren't before the verify code check), then check if they were waiting to go to another page
	const newlyLoggedInUserId = arserver.getUntrustedLoggedInUserIdFromSession(jrContext);
	if (newlyLoggedInUserId && (previouslyLoggedInUserId !== newlyLoggedInUserId)) {
		if (arserver.userLogsInCheckDiverted(jrContext)) {
			return;
		}
	}

	// redirect someplace specific on success?
	if (successRedirectTo) {
		jrContext.res.redirect(successRedirectTo);
		return;
	}

	// otherwise default
	jrContext.res.redirect("/");
}
//---------------------------------------------------------------------------




module.exports = {
	setupRouter,
};