2020-07-14 15:06:30 +02:00
|
|
|
import Controller from "../Controller";
|
|
|
|
import {NextFunction, Request, Response} from "express";
|
2020-11-11 19:08:33 +01:00
|
|
|
import AuthComponent, {AuthMiddleware, RequireAuthMiddleware, RequireGuestMiddleware} from "./AuthComponent";
|
|
|
|
import {BadRequestError} from "../HttpError";
|
2020-11-14 17:24:42 +01:00
|
|
|
import ModelFactory from "../db/ModelFactory";
|
|
|
|
import User from "./models/User";
|
|
|
|
import UserPasswordComponent from "./password/UserPasswordComponent";
|
|
|
|
import UserNameComponent from "./models/UserNameComponent";
|
2020-07-14 15:06:30 +02:00
|
|
|
|
2020-11-11 19:08:33 +01:00
|
|
|
export default class AuthController extends Controller {
|
2020-07-14 15:06:30 +02:00
|
|
|
public getRoutesPrefix(): string {
|
|
|
|
return '/auth';
|
|
|
|
}
|
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
public routes(): void {
|
2020-11-14 17:24:42 +01:00
|
|
|
this.post('/logout', this.postLogout, 'logout', RequireAuthMiddleware);
|
|
|
|
|
2020-11-11 19:08:33 +01:00
|
|
|
this.use(async (req, res, next) => {
|
|
|
|
const authGuard = this.getApp().as(AuthComponent).getAuthGuard();
|
|
|
|
if (await authGuard.interruptAuth(req, res)) return;
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
this.get('/', this.getAuth, 'auth', RequireGuestMiddleware);
|
2020-11-11 19:08:33 +01:00
|
|
|
this.post('/login', this.postLogin, 'login', RequireGuestMiddleware);
|
|
|
|
this.post('/register', this.postRegister, 'register', RequireGuestMiddleware);
|
2020-07-14 15:06:30 +02:00
|
|
|
}
|
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
protected async getAuth(req: Request, res: Response, _next: NextFunction): Promise<void> {
|
2020-11-11 19:08:33 +01:00
|
|
|
const authGuard = this.getApp().as(AuthComponent).getAuthGuard();
|
|
|
|
|
2020-11-14 17:24:42 +01:00
|
|
|
const userModelFactory = ModelFactory.get(User);
|
|
|
|
const hasUsername = userModelFactory.hasComponent(UserNameComponent);
|
2020-07-14 15:06:30 +02:00
|
|
|
res.render('auth/auth', {
|
2020-11-11 19:08:33 +01:00
|
|
|
auth_methods: authGuard.getAuthMethodNames(),
|
2020-11-14 17:24:42 +01:00
|
|
|
has_username: hasUsername,
|
|
|
|
register_with_password: hasUsername && userModelFactory.hasComponent(UserPasswordComponent),
|
2020-07-14 15:06:30 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-11 19:08:33 +01:00
|
|
|
protected async postLogin(req: Request, res: Response): Promise<void> {
|
|
|
|
return await this.handleAuth(req, res, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected async postRegister(req: Request, res: Response): Promise<void> {
|
|
|
|
return await this.handleAuth(req, res, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected async handleAuth(req: Request, res: Response, isRegistration: boolean): Promise<void> {
|
2020-11-15 12:20:11 +01:00
|
|
|
if (isRegistration && !req.body.auth_method) {
|
|
|
|
throw new BadRequestError('Cannot register without specifying desired auth_method.',
|
|
|
|
'Please specify auth_method.', req.url);
|
|
|
|
}
|
|
|
|
|
2020-11-11 19:08:33 +01:00
|
|
|
const authGuard = this.getApp().as(AuthComponent).getAuthGuard();
|
|
|
|
|
|
|
|
const identifier = req.body.identifier;
|
|
|
|
if (!identifier) throw new BadRequestError('Identifier not specified.', 'Please try again.', req.originalUrl);
|
|
|
|
|
|
|
|
// Get requested auth method
|
|
|
|
if (req.body.auth_method) {
|
|
|
|
const method = await authGuard.getAuthMethodByName(req.body.auth_method);
|
|
|
|
if (!method) {
|
|
|
|
throw new BadRequestError('Invalid auth method: ' + req.body.auth_method,
|
|
|
|
'Available methods are: ' + authGuard.getAuthMethodNames(), req.url);
|
|
|
|
}
|
|
|
|
|
2020-11-15 12:20:11 +01:00
|
|
|
// Register
|
|
|
|
if (isRegistration) return await method.attemptRegister(req, res, identifier);
|
|
|
|
|
2020-11-11 19:08:33 +01:00
|
|
|
const user = await method.findUserByIdentifier(identifier);
|
2020-11-14 17:24:42 +01:00
|
|
|
|
2020-11-15 12:20:11 +01:00
|
|
|
// Redirect to registration if user not found
|
|
|
|
if (!user) return await this.redirectToRegistration(req, res, identifier);
|
2020-07-14 15:06:30 +02:00
|
|
|
|
2020-11-11 19:08:33 +01:00
|
|
|
// Login
|
|
|
|
return await method.attemptLogin(req, res, user);
|
|
|
|
}
|
|
|
|
|
|
|
|
const methods = await authGuard.getAuthMethodsByIdentifier(identifier);
|
|
|
|
|
2020-11-15 12:20:11 +01:00
|
|
|
// Redirect to registration if user not found
|
|
|
|
if (methods.length === 0) return await this.redirectToRegistration(req, res, identifier);
|
2020-11-11 19:08:33 +01:00
|
|
|
|
2020-11-15 12:20:11 +01:00
|
|
|
// Login
|
2020-11-11 19:08:33 +01:00
|
|
|
const {user, method} = methods[0];
|
|
|
|
return await method.attemptLogin(req, res, user);
|
|
|
|
}
|
2020-07-14 15:06:30 +02:00
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
protected async postLogout(req: Request, res: Response, _next: NextFunction): Promise<void> {
|
2020-11-11 19:08:33 +01:00
|
|
|
const userId = typeof req.body.user_id === 'string' ? parseInt(req.body.user_id) : null;
|
|
|
|
|
|
|
|
const proofs = await req.as(AuthMiddleware).getAuthGuard().getProofs(req);
|
|
|
|
|
|
|
|
for (const proof of proofs) {
|
|
|
|
if (userId === null || (await proof.getResource())?.id === userId) {
|
|
|
|
await proof.revoke();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-14 15:06:30 +02:00
|
|
|
req.flash('success', 'Successfully logged out.');
|
2020-07-15 11:42:49 +02:00
|
|
|
res.redirect(req.query.redirect_uri?.toString() || '/');
|
2020-07-14 15:06:30 +02:00
|
|
|
}
|
|
|
|
|
2020-11-11 19:08:33 +01:00
|
|
|
protected async redirectToRegistration(req: Request, res: Response, identifier: string): Promise<void> {
|
|
|
|
req.flash('register_identifier', identifier);
|
|
|
|
req.flash('info', `User with identifier "${identifier}" not found.`);
|
|
|
|
res.redirect(Controller.route('auth', undefined, {
|
|
|
|
redirect_uri: req.query.redirect_uri?.toString() || undefined,
|
|
|
|
}));
|
|
|
|
}
|
2020-09-25 23:42:15 +02:00
|
|
|
}
|