swaf/src/auth/password/PasswordAuthProof.ts

90 lines
3.0 KiB
TypeScript

import AuthProof from "../AuthProof";
import User from "../models/User";
import UserPasswordComponent from "./UserPasswordComponent";
import {Session, SessionData} from "express-session";
export default class PasswordAuthProof implements AuthProof<User> {
public static getProofForSession(session: Session & Partial<SessionData>): PasswordAuthProof | null {
return session.auth_password_proof ? new PasswordAuthProof(session) : null;
}
public static createAuthorizedProofForRegistration(session: Session): PasswordAuthProof {
const proofForSession = new PasswordAuthProof(session);
proofForSession.authorized = true;
proofForSession.forRegistration = true;
proofForSession.save();
return proofForSession;
}
public static createProofForLogin(session: Session & Partial<SessionData>): PasswordAuthProof {
return new PasswordAuthProof(session);
}
private readonly session: Session & Partial<SessionData>;
private authorized: boolean;
private forRegistration: boolean = false;
private userId: number | null;
private userPassword: UserPasswordComponent | null = null;
private constructor(session: Session & Partial<SessionData>) {
this.session = session;
this.authorized = session.auth_password_proof?.authorized || false;
this.forRegistration = session.auth_password_proof?.forRegistration || false;
this.userId = session.auth_password_proof?.userId || null;
}
public async getResource(): Promise<User | null> {
if (typeof this.userId !== 'number') return null;
return await User.getById(this.userId);
}
public setResource(user: User): void {
this.userId = user.getOrFail('id');
this.save();
}
public async isAuthorized(): Promise<boolean> {
return this.authorized;
}
public async isValid(): Promise<boolean> {
return (this.forRegistration || Boolean(await this.getResource())) &&
await this.isAuthorized();
}
public async revoke(): Promise<void> {
this.session.auth_password_proof = undefined;
}
private async getUserPassword(): Promise<UserPasswordComponent | null> {
if (!this.userPassword) {
this.userPassword = (await User.getById(this.userId))?.as(UserPasswordComponent) || null;
}
return this.userPassword;
}
public async authorize(passwordGuess: string): Promise<boolean> {
const password = await this.getUserPassword();
if (!password || !await password.verifyPassword(passwordGuess)) return false;
this.authorized = true;
this.save();
return true;
}
private save() {
this.session.auth_password_proof = {
authorized: this.authorized,
forRegistration: this.forRegistration,
userId: this.userId,
};
}
}
export type PasswordAuthProofSessionData = {
authorized: boolean,
forRegistration: boolean,
userId: number | null,
};