import AuthProof from "./AuthProof"; import MysqlConnectionManager from "../db/MysqlConnectionManager"; import User from "./models/User"; import UserEmail from "./models/UserEmail"; import {Connection} from "mysql"; export default abstract class AuthGuard

{ public abstract async getProofForSession(session: Express.Session): Promise

; public async getUserForSession(session: Express.Session): Promise { if (!await this.isAuthenticated(session)) return null; return await User.getById(session.auth_id); } public async authenticateOrRegister(session: Express.Session, proof: P): Promise { if (!await proof.isAuthorized()) { throw new AuthError('Invalid argument: cannot authenticate with an unauthorized proof.'); } let user = await proof.getUser(); if (!user) { // Register const callbacks: (() => Promise)[] = []; await MysqlConnectionManager.wrapTransaction(async connection => { const email = await proof.getEmail(); user = new User({ name: email.split('@')[0], }); await user.save(connection, c => callbacks.push(c)); const userEmail = new UserEmail({ user_id: user.id, email: email, main: true, }); await userEmail.save(connection, c => callbacks.push(c)); }); for (const callback of callbacks) { await callback(); } if (!user) { throw new Error('Unable to register user.'); } } session.auth_id = user.id; } public async isAuthenticated(session: Express.Session): Promise { return await this.checkCurrentSessionProofValidity(session); } public async logout(session: Express.Session): Promise { const proof = await this.getProofForSession(session); if (proof) { await proof.revoke(session); } session.auth_id = undefined; } private async checkCurrentSessionProofValidity(session: Express.Session): Promise { if (typeof session.auth_id !== 'number') return false; const proof = await this.getProofForSession(session); if (!proof || !await proof.isValid() || !await proof.isAuthorized() || !await proof.isOwnedBy(session.auth_id)) { await this.logout(session); return false; } return true; } } export class AuthError extends Error { constructor(message: string) { super(message); } }