2024-08-25 13:36:19 +02:00
|
|
|
import { Request, Response } from "express";
|
|
|
|
import { JWTHelper } from "../helpers/jwtHelper";
|
|
|
|
import { JWTToken } from "../type/jwtTypes";
|
|
|
|
import InternalException from "../exceptions/internalException";
|
|
|
|
import RefreshCommandHandler from "../command/refreshCommandHandler";
|
|
|
|
import { CreateRefreshCommand } from "../command/refreshCommand";
|
|
|
|
import speakeasy from "speakeasy";
|
|
|
|
import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException";
|
|
|
|
import QRCode from "qrcode";
|
2025-02-15 10:59:54 +01:00
|
|
|
import { CreateUserCommand } from "../command/management/user/userCommand";
|
|
|
|
import UserCommandHandler from "../command/management/user/userCommandHandler";
|
|
|
|
import { CreateInviteCommand, DeleteInviteCommand } from "../command/management/user/inviteCommand";
|
|
|
|
import InviteCommandHandler from "../command/management/user/inviteCommandHandler";
|
2024-08-25 13:36:19 +02:00
|
|
|
import MailHelper from "../helpers/mailHelper";
|
2025-02-15 10:59:54 +01:00
|
|
|
import InviteService from "../service/management/inviteService";
|
|
|
|
import UserService from "../service/management/userService";
|
2024-08-25 13:36:19 +02:00
|
|
|
import CustomRequestException from "../exceptions/customRequestException";
|
2024-08-25 18:07:34 +02:00
|
|
|
import { CLUB_NAME } from "../env.defaults";
|
2025-02-15 10:59:54 +01:00
|
|
|
import { CreateUserPermissionCommand } from "../command/management/user/userPermissionCommand";
|
|
|
|
import UserPermissionCommandHandler from "../command/management/user/userPermissionCommandHandler";
|
|
|
|
import InviteFactory from "../factory/admin/management/invite";
|
2024-08-25 13:36:19 +02:00
|
|
|
|
2024-11-23 14:25:31 +01:00
|
|
|
/**
|
|
|
|
* @description get all invites
|
|
|
|
* @param req {Request} Express req object
|
|
|
|
* @param res {Response} Express res object
|
|
|
|
* @returns {Promise<*>}
|
|
|
|
*/
|
2024-11-24 12:36:12 +01:00
|
|
|
export async function getInvites(req: Request, res: Response): Promise<any> {
|
|
|
|
let invites = await InviteService.getAll();
|
|
|
|
|
|
|
|
res.json(InviteFactory.mapToBase(invites));
|
|
|
|
}
|
2024-11-23 14:25:31 +01:00
|
|
|
|
2024-08-25 13:36:19 +02:00
|
|
|
/**
|
|
|
|
* @description start first user
|
|
|
|
* @param req {Request} Express req object
|
|
|
|
* @param res {Response} Express res object
|
|
|
|
* @returns {Promise<*>}
|
|
|
|
*/
|
2024-09-01 14:55:05 +02:00
|
|
|
export async function inviteUser(req: Request, res: Response, isInvite: boolean = true): Promise<any> {
|
2024-08-25 13:36:19 +02:00
|
|
|
let origin = req.headers.origin;
|
|
|
|
let username = req.body.username;
|
|
|
|
let mail = req.body.mail;
|
|
|
|
let firstname = req.body.firstname;
|
|
|
|
let lastname = req.body.lastname;
|
|
|
|
|
|
|
|
let users = await UserService.getByMailOrUsername(mail, username);
|
|
|
|
if (users.length == 1) {
|
|
|
|
// username or mail is used
|
|
|
|
if (users[0].username == username && users[0].mail == mail) {
|
|
|
|
throw new CustomRequestException(409, "Username and Mail are already in use");
|
|
|
|
} else if (users[0].username == username) {
|
|
|
|
throw new CustomRequestException(409, "Username is already in use");
|
|
|
|
} else {
|
|
|
|
throw new CustomRequestException(409, "Mail is already in use");
|
|
|
|
}
|
|
|
|
} else if (users.length >= 2) {
|
|
|
|
throw new CustomRequestException(409, "Username and Mail are already in use");
|
|
|
|
}
|
|
|
|
|
2024-08-25 18:07:34 +02:00
|
|
|
var secret = speakeasy.generateSecret({ length: 20, name: `Mitgliederverwaltung ${CLUB_NAME}` });
|
2024-08-25 13:36:19 +02:00
|
|
|
|
|
|
|
let createInvite: CreateInviteCommand = {
|
|
|
|
username: username,
|
|
|
|
mail: mail,
|
|
|
|
firstname: firstname,
|
|
|
|
lastname: lastname,
|
|
|
|
secret: secret.base32,
|
|
|
|
};
|
|
|
|
let token = await InviteCommandHandler.create(createInvite);
|
|
|
|
|
|
|
|
// sendmail
|
2024-12-28 18:03:33 +01:00
|
|
|
await MailHelper.sendMail(
|
2024-08-25 13:36:19 +02:00
|
|
|
mail,
|
2024-08-25 18:07:34 +02:00
|
|
|
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
2024-09-01 14:55:05 +02:00
|
|
|
`Öffne folgenden Link: ${origin}/${isInvite ? "invite" : "setup"}/verify?mail=${mail}&token=${token}`
|
2024-08-25 13:36:19 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
res.sendStatus(204);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Create first user
|
|
|
|
* @param req {Request} Express req object
|
|
|
|
* @param res {Response} Express res object
|
|
|
|
* @returns {Promise<*>}
|
|
|
|
*/
|
|
|
|
export async function verifyInvite(req: Request, res: Response): Promise<any> {
|
|
|
|
let mail = req.body.mail;
|
|
|
|
let token = req.body.token;
|
|
|
|
|
2024-11-23 14:25:31 +01:00
|
|
|
let { secret, username } = await InviteService.getByMailAndToken(mail, token);
|
2024-08-25 13:36:19 +02:00
|
|
|
|
2024-08-25 18:07:34 +02:00
|
|
|
const url = `otpauth://totp/Mitgliederverwaltung ${CLUB_NAME}?secret=${secret}`;
|
2024-08-25 13:36:19 +02:00
|
|
|
|
|
|
|
QRCode.toDataURL(url)
|
|
|
|
.then((result) => {
|
2024-08-25 18:07:34 +02:00
|
|
|
res.json({
|
|
|
|
dataUrl: result,
|
|
|
|
otp: secret,
|
2024-11-23 14:25:31 +01:00
|
|
|
username,
|
2024-08-25 18:07:34 +02:00
|
|
|
});
|
2024-08-25 13:36:19 +02:00
|
|
|
})
|
|
|
|
.catch((err) => {
|
2024-09-06 10:08:19 +02:00
|
|
|
throw new InternalException("QRCode not created", err);
|
2024-08-25 13:36:19 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Create first user
|
|
|
|
* @param req {Request} Express req object
|
|
|
|
* @param res {Response} Express res object
|
|
|
|
* @returns {Promise<*>}
|
|
|
|
*/
|
2024-08-26 13:47:08 +02:00
|
|
|
export async function finishInvite(req: Request, res: Response, grantAdmin: boolean = false): Promise<any> {
|
2024-08-25 13:36:19 +02:00
|
|
|
let mail = req.body.mail;
|
|
|
|
let token = req.body.token;
|
|
|
|
let totp = req.body.totp;
|
|
|
|
|
|
|
|
let { secret, username, firstname, lastname } = await InviteService.getByMailAndToken(mail, token);
|
|
|
|
|
|
|
|
let valid = speakeasy.totp.verify({
|
|
|
|
secret: secret,
|
|
|
|
encoding: "base32",
|
|
|
|
token: totp,
|
|
|
|
window: 2,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!valid) {
|
|
|
|
throw new UnauthorizedRequestException("Token not valid or expired");
|
|
|
|
}
|
|
|
|
|
|
|
|
let createUser: CreateUserCommand = {
|
|
|
|
username: username,
|
|
|
|
firstname: firstname,
|
|
|
|
lastname: lastname,
|
|
|
|
mail: mail,
|
|
|
|
secret: secret,
|
2024-10-07 18:09:27 +02:00
|
|
|
isOwner: grantAdmin,
|
2024-08-25 13:36:19 +02:00
|
|
|
};
|
|
|
|
let id = await UserCommandHandler.create(createUser);
|
|
|
|
|
2024-11-23 12:11:19 +01:00
|
|
|
let accessToken = await JWTHelper.buildToken(id);
|
2024-08-25 13:36:19 +02:00
|
|
|
|
|
|
|
let refreshCommand: CreateRefreshCommand = {
|
|
|
|
userId: id,
|
|
|
|
};
|
2024-11-23 12:11:19 +01:00
|
|
|
let refreshToken = await RefreshCommandHandler.create(refreshCommand);
|
2024-08-25 13:36:19 +02:00
|
|
|
|
|
|
|
let deleteInvite: DeleteInviteCommand = {
|
|
|
|
mail: mail,
|
|
|
|
token: token,
|
|
|
|
};
|
|
|
|
await InviteCommandHandler.deleteByTokenAndMail(deleteInvite);
|
|
|
|
|
|
|
|
res.json({
|
|
|
|
accessToken,
|
|
|
|
refreshToken,
|
|
|
|
});
|
|
|
|
}
|
2024-11-23 14:25:31 +01:00
|
|
|
|
|
|
|
/**
|
2024-11-24 12:36:12 +01:00
|
|
|
* @description delete invite by mail
|
2024-11-23 14:25:31 +01:00
|
|
|
* @param req {Request} Express req object
|
|
|
|
* @param res {Response} Express res object
|
|
|
|
* @returns {Promise<*>}
|
|
|
|
*/
|
2024-11-24 12:36:12 +01:00
|
|
|
export async function deleteInvite(req: Request, res: Response): Promise<any> {
|
|
|
|
const mail = req.params.mail;
|
|
|
|
|
|
|
|
await InviteCommandHandler.deleteByMail(mail);
|
|
|
|
|
|
|
|
res.sendStatus(204);
|
2024-11-23 14:25:31 +01:00
|
|
|
}
|