Promote auth view to core

This commit is contained in:
Alice Gaudon 2020-07-14 15:06:30 +02:00
parent a0c385bbbe
commit d6266e4396
3 changed files with 83 additions and 29 deletions

View File

@ -0,0 +1,34 @@
import Controller from "../Controller";
import {NextFunction, Request, Response} from "express";
import {REQUIRE_AUTH_MIDDLEWARE, REQUIRE_GUEST_MIDDLEWARE} from "./AuthComponent";
export default abstract class AuthController extends Controller {
public getRoutesPrefix(): string {
return '/auth';
}
public routes() {
this.get('/', this.getAuth, 'auth', REQUIRE_GUEST_MIDDLEWARE);
this.post('/', this.postAuth, 'auth', REQUIRE_GUEST_MIDDLEWARE);
this.get('/check', this.getCheckAuth, 'check_auth');
this.post('/logout', this.postLogout, 'logout', REQUIRE_AUTH_MIDDLEWARE);
}
protected async getAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
const registerEmail = req.flash('register_confirm_email');
res.render('auth/auth', {
register_confirm_email: registerEmail.length > 0 ? registerEmail[0] : null,
});
}
protected abstract async postAuth(req: Request, res: Response, next: NextFunction): Promise<void>;
protected abstract async getCheckAuth(req: Request, res: Response, next: NextFunction): Promise<void>;
protected async postLogout(req: Request, res: Response, next: NextFunction): Promise<void> {
await req.authGuard.logout(req.session!);
req.flash('success', 'Successfully logged out.');
res.redirectBack('/');
}
}

View File

@ -1,16 +1,16 @@
import {Request, Response} from "express"; import {NextFunction, Request, Response} from "express";
import Controller from "../../Controller"; import Controller from "../../Controller";
import MagicLink from "../models/MagicLink"; import MagicLink from "../models/MagicLink";
import {REQUIRE_AUTH_MIDDLEWARE, REQUIRE_GUEST_MIDDLEWARE} from "../AuthComponent";
import {BadRequestError} from "../../HttpError"; import {BadRequestError} from "../../HttpError";
import UserEmail from "../models/UserEmail"; import UserEmail from "../models/UserEmail";
import MagicLinkController from "./MagicLinkController"; import MagicLinkController from "./MagicLinkController";
import {MailTemplate} from "../../Mail"; import {MailTemplate} from "../../Mail";
import {AuthError, PendingApprovalAuthError} from "../AuthGuard"; import {AuthError, PendingApprovalAuthError} from "../AuthGuard";
import geoip from "geoip-lite"; import geoip from "geoip-lite";
import AuthController from "../AuthController";
export default abstract class MagicLinkAuthController extends Controller { export default abstract class MagicLinkAuthController extends AuthController {
public static async checkAndAuth(req: Request, res: Response, magicLink: MagicLink): Promise<void> { public static async checkAndAuth(req: Request, res: Response, magicLink: MagicLink): Promise<void> {
if (magicLink.getSessionID() !== req.sessionID!) throw new BadOwnerMagicLink(); if (magicLink.getSessionID() !== req.sessionID!) throw new BadOwnerMagicLink();
if (!await magicLink.isAuthorized()) throw new UnauthorizedMagicLink(); if (!await magicLink.isAuthorized()) throw new UnauthorizedMagicLink();
@ -49,33 +49,17 @@ export default abstract class MagicLinkAuthController extends Controller {
this.magicLinkMailTemplate = magicLinkMailTemplate; this.magicLinkMailTemplate = magicLinkMailTemplate;
} }
protected async getAuth(request: Request, response: Response, next: NextFunction): Promise<void> {
public getRoutesPrefix(): string {
return '/auth';
}
routes(): void {
this.get('/', this.getAuth, 'auth', REQUIRE_GUEST_MIDDLEWARE);
this.post('/', this.postAuth, 'auth', REQUIRE_GUEST_MIDDLEWARE);
this.get('/check', this.getCheckAuth, 'check_auth');
this.get('/logout', this.getLogout, 'logout', REQUIRE_AUTH_MIDDLEWARE);
}
protected async getAuth(request: Request, response: Response): Promise<void> {
const registerEmail = request.flash('register_confirm_email');
const link = await MagicLink.bySessionID(request.sessionID!, [this.loginMagicLinkActionType, this.registerMagicLinkActionType]); const link = await MagicLink.bySessionID(request.sessionID!, [this.loginMagicLinkActionType, this.registerMagicLinkActionType]);
if (link && await link.isValid()) { if (link && await link.isValid()) {
response.redirect(Controller.route('magic_link_lobby')); response.redirect(Controller.route('magic_link_lobby'));
return; return;
} }
response.render('auth', { await super.getAuth(request, response, next);
register_confirm_email: registerEmail.length > 0 ? registerEmail[0] : null,
});
} }
protected async postAuth(req: Request, res: Response): Promise<void> { protected async postAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
const email = req.body.email; const email = req.body.email;
if (!email) throw new BadRequestError('Email not specified.', 'Please try again.', req.originalUrl); if (!email) throw new BadRequestError('Email not specified.', 'Please try again.', req.originalUrl);
@ -118,7 +102,7 @@ export default abstract class MagicLinkAuthController extends Controller {
/** /**
* Check whether a magic link is authorized, and authenticate if yes * Check whether a magic link is authorized, and authenticate if yes
*/ */
protected async getCheckAuth(req: Request, res: Response): Promise<void> { protected async getCheckAuth(req: Request, res: Response, next: NextFunction): Promise<void> {
const magicLink = await MagicLink.bySessionID(req.sessionID!, [this.loginMagicLinkActionType, this.registerMagicLinkActionType]); const magicLink = await MagicLink.bySessionID(req.sessionID!, [this.loginMagicLinkActionType, this.registerMagicLinkActionType]);
if (!magicLink) { if (!magicLink) {
@ -149,12 +133,6 @@ export default abstract class MagicLinkAuthController extends Controller {
}); });
return; return;
} }
protected async getLogout(req: Request, res: Response): Promise<void> {
await req.authGuard.logout(req.session!);
req.flash('success', 'Successfully logged out.');
res.redirectBack('/');
}
} }
export class BadOwnerMagicLink extends AuthError { export class BadOwnerMagicLink extends AuthError {

42
views/auth/auth.njk Normal file
View File

@ -0,0 +1,42 @@
{% extends 'layouts/base.njk' %}
{% import 'macros.njk' as macros %}
{% set title = 'Authentication / Registration' %}
{% set decription = 'Join ' + app.name + ' and share your files!' %}
{% set h1 = 'Authentication and registration' %}
{% block body %}
<div class="container">
<div class="panel">
{% if register_confirm_email %}
<form action="/auth" method="POST" id="register-form">
<h2>Register</h2>
{{ macros.message('question', 'Do you wish to create a new account with ' + register_confirm_email + '?', false, false) }}
{{ macros.message('warning', 'If you already have an account, please log in with your existing email first and then add your new email in the Account page.', false, true) }}
<input type="hidden" name="email" value="{{ register_confirm_email }}">
<input type="hidden" name="confirm_register" value="confirm">
<div class="form-field">
<div class="form-display">Email: {{ register_confirm_email }}</div>
</div>
<a href="/auth" class="button transparent">Go back</a>
<button type="submit" class="primary">Register</button>
{{ macros.csrf(getCSRFToken) }}
</form>
{% else %}
<form action="/auth" method="POST" id="login-form">
<h2>Log in or register</h2>
{# {{ macros.message('info', 'If we don\'t find your email address in our database, you will be able to register.', false, true) }}#}
<div class="input-field">
{{ macros.field(_locals, 'email', 'email', query.email or '', 'Your email address', "If we don't find your email address in our database, you will be able to register.", 'required') }}
</div>
<button type="submit">Authenticate</button>
{{ macros.csrf(getCSRFToken) }}
</form>
{% endif %}
</div>
</div>
{% endblock %}