ff-admin-server/src/controller/inviteController.ts

177 lines
5.3 KiB
TypeScript
Raw Normal View History

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";
import { CreateUserCommand } from "../command/userCommand";
import UserCommandHandler from "../command/userCommandHandler";
import { CreateInviteCommand, DeleteInviteCommand } from "../command/inviteCommand";
import InviteCommandHandler from "../command/inviteCommandHandler";
import MailHelper from "../helpers/mailHelper";
import InviteService from "../service/inviteService";
import UserService from "../service/userService";
import CustomRequestException from "../exceptions/customRequestException";
import { CLUB_NAME } from "../env.defaults";
2024-08-27 17:54:59 +02:00
import { CreateUserPermissionCommand } from "../command/userPermissionCommand";
import UserPermissionCommandHandler from "../command/userPermissionCommandHandler";
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");
}
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
let mailhelper = new MailHelper();
await mailhelper.sendMail(
mail,
`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;
let { secret } = await InviteService.getByMailAndToken(mail, token);
const url = `otpauth://totp/Mitgliederverwaltung ${CLUB_NAME}?secret=${secret}`;
2024-08-25 13:36:19 +02:00
QRCode.toDataURL(url)
.then((result) => {
res.json({
dataUrl: result,
otp: secret,
});
2024-08-25 13:36:19 +02:00
})
.catch((err) => {
throw new InternalException("QRCode not created");
});
}
/**
* @description Create first user
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
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,
};
let id = await UserCommandHandler.create(createUser);
if (grantAdmin) {
2024-08-27 17:54:59 +02:00
let createPermission: CreateUserPermissionCommand = {
permission: "*",
userId: id,
};
2024-08-27 17:54:59 +02:00
await UserPermissionCommandHandler.create(createPermission);
}
2024-08-25 13:36:19 +02:00
let jwtData: JWTToken = {
userId: id,
mail: mail,
2024-08-25 13:36:19 +02:00
username: username,
firstname: firstname,
lastname: lastname,
permissions: {
...(grantAdmin ? { admin: true } : {}),
},
2024-08-25 13:36:19 +02:00
};
let accessToken: string;
let refreshToken: string;
JWTHelper.create(jwtData)
.then((result) => {
accessToken = result;
})
.catch((err) => {
console.log(err);
throw new InternalException("Failed accessToken creation");
});
let refreshCommand: CreateRefreshCommand = {
userId: id,
};
refreshToken = await RefreshCommandHandler.create(refreshCommand);
let deleteInvite: DeleteInviteCommand = {
mail: mail,
token: token,
};
await InviteCommandHandler.deleteByTokenAndMail(deleteInvite);
res.json({
accessToken,
refreshToken,
});
}