diff --git a/src/controller/userController.ts b/src/controller/userController.ts new file mode 100644 index 0000000..603b782 --- /dev/null +++ b/src/controller/userController.ts @@ -0,0 +1,55 @@ +import { Request, Response } from "express"; +import speakeasy from "speakeasy"; +import QRCode from "qrcode"; +import InternalException from "../exceptions/internalException"; +import { CLUB_NAME } from "../env.defaults"; +import UserService from "../service/userService"; + +/** + * @description get user totp + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getUserTotp(req: Request, res: Response): Promise { + const userId = parseInt(req.userId); + + let { secret } = await UserService.getById(userId); + + const url = `otpauth://totp/Mitgliederverwaltung ${CLUB_NAME}?secret=${secret}`; + + QRCode.toDataURL(url) + .then((result) => { + res.json({ + dataUrl: result, + otp: secret, + }); + }) + .catch((err) => { + throw new InternalException("QRCode not created", err); + }); +} + +/** + * @description verify user totp + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function verifyUserTotp(req: Request, res: Response): Promise { + const userId = parseInt(req.userId); + let totp = req.body.totp; + + let { secret } = await UserService.getById(userId); + let valid = speakeasy.totp.verify({ + secret: secret, + encoding: "base32", + token: totp, + window: 2, + }); + + if (!valid) { + throw new InternalException("Token not valid or expired"); + } + res.sendStatus(204); +} diff --git a/src/routes/index.ts b/src/routes/index.ts index 2dcff79..3cfb76c 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -9,6 +9,7 @@ import errorHandler from "../middleware/errorHandler"; import setup from "./setup"; import auth from "./auth"; import admin from "./admin/index"; +import user from "./user"; export default (app: Express) => { app.set("query parser", "extended"); @@ -25,5 +26,6 @@ export default (app: Express) => { app.use("/auth", auth); app.use(authenticate); app.use("/admin", admin); + app.use("/user", user); app.use(errorHandler); }; diff --git a/src/routes/user.ts b/src/routes/user.ts new file mode 100644 index 0000000..40cabae --- /dev/null +++ b/src/routes/user.ts @@ -0,0 +1,14 @@ +import express from "express"; +import { getUserTotp, verifyUserTotp } from "../controller/userController"; + +var router = express.Router({ mergeParams: true }); + +router.get("/totp", async (req, res) => { + await getUserTotp(req, res); +}); + +router.post("/verify", async (req, res) => { + await verifyUserTotp(req, res); +}); + +export default router;