import ApplicationComponent from "../ApplicationComponent"; import {NextFunction, Request, Response} from "express"; import AuthGuard from "./AuthGuard"; import Controller from "../Controller"; import {ForbiddenHttpError} from "../HttpError"; import Middleware from "../Middleware"; import User from "./models/User"; import AuthProof from "./AuthProof"; export default class AuthComponent extends ApplicationComponent { private readonly authGuard: AuthGuard>; public constructor(authGuard: AuthGuard>) { super(); this.authGuard = authGuard; } public async init(): Promise { this.use(AuthMiddleware); } public getAuthGuard(): AuthGuard> { return this.authGuard; } } export class AuthMiddleware extends Middleware { private authGuard?: AuthGuard>; private user: User | null = null; protected async handle(req: Request, res: Response, next: NextFunction): Promise { this.authGuard = this.app.as(AuthComponent).getAuthGuard(); const proof = await this.authGuard.isAuthenticated(req.getSession()); if (proof) { this.user = await proof.getResource(); res.locals.user = this.user; } next(); } public getUser(): User | null { return this.user; } public getAuthGuard(): AuthGuard> { if (!this.authGuard) throw new Error('AuthGuard was not initialized.'); return this.authGuard; } } export class RequireRequestAuthMiddleware extends Middleware { protected async handle(req: Request, res: Response, next: NextFunction): Promise { const proof = await req.as(AuthMiddleware).getAuthGuard().isAuthenticatedViaRequest(req); if (!proof) { req.flash('error', `You must be logged in to access ${req.url}.`); res.redirect(Controller.route('auth', undefined, { redirect_uri: req.url, })); return; } next(); } } export class RequireAuthMiddleware extends Middleware { protected async handle(req: Request, res: Response, next: NextFunction): Promise { const authGuard = req.as(AuthMiddleware).getAuthGuard(); // Via request if (await authGuard.isAuthenticatedViaRequest(req)) { next(); return; } // Via session if (!await authGuard.isAuthenticated(req.getSession())) { req.flash('error', `You must be logged in to access ${req.url}.`); res.redirect(Controller.route('auth', undefined, { redirect_uri: req.url, })); return; } next(); } } export class RequireGuestMiddleware extends Middleware { protected async handle(req: Request, res: Response, next: NextFunction): Promise { if (await req.as(AuthMiddleware).getAuthGuard().isAuthenticated(req.getSession())) { res.redirectBack(); return; } next(); } } export class RequireAdminMiddleware extends Middleware { protected async handle(req: Request, res: Response, next: NextFunction): Promise { const user = req.as(AuthMiddleware).getUser(); if (!user || !user.is_admin) { throw new ForbiddenHttpError('secret tool', req.url); } next(); } }