.ts
TypeScript
(application/typescript)
// 3rd-party
import type { ReqHandler } from "@ethicdevs/react-monolith";
// app
import { AppRoute, AppRouteParams } from "../../routes.defs";
import LoginView, { LoginViewProps } from "../../views/auth/LoginView";
import { makeAuthService } from "../../services/auth";

const postLoginAction: ReqHandler = async (request, reply) => {
  const { email_address: emailAddress, password } =
    request.body as AppRouteParams[AppRoute.AUTH_LOGIN_ACTION]["body"];

  const authService = makeAuthService({
    cryptoService: request.cryptoService,
    request,
  });

  const reqHandler = reply.makeRequestHandler(request, reply);

  const initialValues = { emailAddress };

  if (request.validationError != null) {
    const { message: errorMessage } = request.validationError;

    return reqHandler<LoginViewProps>(LoginView.name, {
      errorMessage,
      initialValues,
    });
  }

  if (emailAddress.trim() === "") {
    return reqHandler<LoginViewProps>(LoginView.name, {
      errorMessage: "Please provide a non-empty email address.",
      initialValues,
    });
  }

  if (password.trim() === "") {
    return reqHandler<LoginViewProps>(LoginView.name, {
      errorMessage: "Please provide a non-empty password.",
      initialValues,
    });
  }

  if ((await authService.isExistingEmailAddress(emailAddress)) === false) {
    return reqHandler<LoginViewProps>(LoginView.name, {
      errorMessage:
        "Invalid credentials. Please verify your input and try again.",
      initialValues,
    });
  }

  const [isLoginAllowed, user] = await authService.isUserLoginAllowed(
    emailAddress,
    password
  );

  if (isLoginAllowed === false || user == null) {
    return reqHandler<LoginViewProps>(LoginView.name, {
      errorMessage:
        "Invalid credentials. Please verify your input and try again.",
      initialValues,
    });
  }

  // Set the session data such as the user is authenticated.
  request.session.data.authenticated = true;
  request.session.data.curr_user_avatar_uri = user.avatarUri;
  request.session.data.curr_user_role = user.role;
  request.session.data.curr_user_uid = user.id;
  request.session.data.curr_user_username = user.username;

  // Log success
  console.log(`User (id: ${user.id}, role: ${user.role}) just logged!`);

  // In case a redirect to url is set in session, go there.
  const authRedirectToUrl = request.session.data.auth_redirect_to;
  if (authRedirectToUrl != null) {
    console.log("Will redirect back after login to uri:", authRedirectToUrl);
    request.session.data.auth_redirect_to = null; // prevent replay attack
    reply.redirect(302, authRedirectToUrl);
    return reply;
  }

  // Everything is ok, redirect to user dashboard
  reply.redirect(302, request.namedViewsPathMap[AppRoute.USER_DASHBOARD]);
  return reply;
};

export default postLoginAction;