2020-04-24 12:12:27 +02:00
|
|
|
import AuthProof from "./AuthProof";
|
|
|
|
import MysqlConnectionManager from "../db/MysqlConnectionManager";
|
|
|
|
import User from "./models/User";
|
|
|
|
import UserEmail from "./models/UserEmail";
|
2020-04-25 09:35:49 +02:00
|
|
|
import {Connection} from "mysql";
|
2020-04-24 12:12:27 +02:00
|
|
|
|
|
|
|
export default abstract class AuthGuard<P extends AuthProof> {
|
2020-04-25 09:35:49 +02:00
|
|
|
public abstract async getProofForSession(session: Express.Session): Promise<P | null>;
|
2020-04-24 12:12:27 +02:00
|
|
|
|
|
|
|
public async getUserForSession(session: Express.Session): Promise<User | null> {
|
|
|
|
if (!await this.isAuthenticated(session)) return null;
|
|
|
|
return await User.getById<User>(session.auth_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async authenticateOrRegister(session: Express.Session, proof: P): Promise<void> {
|
|
|
|
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<void>)[] = [];
|
|
|
|
|
|
|
|
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<boolean> {
|
|
|
|
return await this.checkCurrentSessionProofValidity(session);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async logout(session: Express.Session): Promise<void> {
|
2020-04-25 09:35:49 +02:00
|
|
|
const proof = await this.getProofForSession(session);
|
2020-04-24 12:12:27 +02:00
|
|
|
if (proof) {
|
2020-04-25 09:35:49 +02:00
|
|
|
await proof.revoke(session);
|
2020-04-24 12:12:27 +02:00
|
|
|
}
|
|
|
|
session.auth_id = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
private async checkCurrentSessionProofValidity(session: Express.Session): Promise<boolean> {
|
|
|
|
if (typeof session.auth_id !== 'number') return false;
|
|
|
|
|
2020-04-25 09:35:49 +02:00
|
|
|
const proof = await this.getProofForSession(session);
|
2020-04-24 12:12:27 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|