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 { private user?: User; protected async handle(req: Request, res: Response, next: NextFunction): Promise { const proof = await req.as(AuthMiddleware).getAuthGuard().isAuthenticatedViaRequest(req); const user = await proof?.getResource(); if (user) { this.user = user; next(); return; } req.flash('error', `You must be logged in to access ${req.url}.`); res.redirect(Controller.route('auth', undefined, { redirect_uri: req.url, })); } public getUser(): User { if (!this.user) throw new Error('user not initialized.'); return this.user; } } export class RequireAuthMiddleware extends Middleware { private user?: User; protected async handle(req: Request, res: Response, next: NextFunction): Promise { const authGuard = req.as(AuthMiddleware).getAuthGuard(); // Via request let proof = await authGuard.isAuthenticatedViaRequest(req); let user = await proof?.getResource(); if (user) { this.user = user; next(); return; } // Via session proof = await authGuard.isAuthenticated(req.getSession()); user = await proof?.getResource(); if (user) { this.user = user; next(); return; } req.flash('error', `You must be logged in to access ${req.url}.`); res.redirect(Controller.route('auth', undefined, { redirect_uri: req.url, })); } public getUser(): User { if (!this.user) throw new Error('user not initialized.'); return this.user; } } 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(); } }