enable switch to pw totp in account settings
This commit is contained in:
parent
be22c78372
commit
ddb460f8d0
6 changed files with 165 additions and 4 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
import { LoginRoutineEnum } from "../../../enums/loginRoutineEnum";
|
||||||
|
|
||||||
export interface CreateUserCommand {
|
export interface CreateUserCommand {
|
||||||
mail: string;
|
mail: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
@ -18,6 +20,7 @@ export interface UpdateUserCommand {
|
||||||
export interface UpdateUserSecretCommand {
|
export interface UpdateUserSecretCommand {
|
||||||
id: string;
|
id: string;
|
||||||
secret: string;
|
secret: string;
|
||||||
|
routine: LoginRoutineEnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransferUserOwnerCommand {
|
export interface TransferUserOwnerCommand {
|
||||||
|
|
|
@ -75,6 +75,7 @@ export default abstract class UserCommandHandler {
|
||||||
.update(user)
|
.update(user)
|
||||||
.set({
|
.set({
|
||||||
secret: updateUser.secret,
|
secret: updateUser.secret,
|
||||||
|
routine: updateUser.routine,
|
||||||
})
|
})
|
||||||
.where("id = :id", { id: updateUser.id })
|
.where("id = :id", { id: updateUser.id })
|
||||||
.execute()
|
.execute()
|
||||||
|
|
|
@ -50,6 +50,7 @@ export async function login(req: Request, res: Response): Promise<any> {
|
||||||
window: 2,
|
window: 2,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
console.log(passedSecret, secret, passedSecret == secret);
|
||||||
valid = passedSecret == secret;
|
valid = passedSecret == secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import UserService from "../service/management/userService";
|
||||||
import { UpdateUserSecretCommand } from "../command/management/user/userCommand";
|
import { UpdateUserSecretCommand } from "../command/management/user/userCommand";
|
||||||
import UserCommandHandler from "../command/management/user/userCommandHandler";
|
import UserCommandHandler from "../command/management/user/userCommandHandler";
|
||||||
import SettingHelper from "../helpers/settingsHelper";
|
import SettingHelper from "../helpers/settingsHelper";
|
||||||
|
import { LoginRoutineEnum } from "../enums/loginRoutineEnum";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description request totp reset
|
* @description request totp reset
|
||||||
|
@ -101,6 +102,7 @@ export async function finishReset(req: Request, res: Response): Promise<any> {
|
||||||
let updateUserSecret: UpdateUserSecretCommand = {
|
let updateUserSecret: UpdateUserSecretCommand = {
|
||||||
id,
|
id,
|
||||||
secret,
|
secret,
|
||||||
|
routine: LoginRoutineEnum.totp,
|
||||||
};
|
};
|
||||||
await UserCommandHandler.updateSecret(updateUserSecret);
|
await UserCommandHandler.updateSecret(updateUserSecret);
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,15 @@ import QRCode from "qrcode";
|
||||||
import InternalException from "../exceptions/internalException";
|
import InternalException from "../exceptions/internalException";
|
||||||
import UserService from "../service/management/userService";
|
import UserService from "../service/management/userService";
|
||||||
import UserFactory from "../factory/admin/management/user";
|
import UserFactory from "../factory/admin/management/user";
|
||||||
import { TransferUserOwnerCommand, UpdateUserCommand } from "../command/management/user/userCommand";
|
import {
|
||||||
|
TransferUserOwnerCommand,
|
||||||
|
UpdateUserCommand,
|
||||||
|
UpdateUserSecretCommand,
|
||||||
|
} from "../command/management/user/userCommand";
|
||||||
import UserCommandHandler from "../command/management/user/userCommandHandler";
|
import UserCommandHandler from "../command/management/user/userCommandHandler";
|
||||||
import ForbiddenRequestException from "../exceptions/forbiddenRequestException";
|
import ForbiddenRequestException from "../exceptions/forbiddenRequestException";
|
||||||
import SettingHelper from "../helpers/settingsHelper";
|
import SettingHelper from "../helpers/settingsHelper";
|
||||||
|
import { LoginRoutineEnum } from "../enums/loginRoutineEnum";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description get my by id
|
* @description get my by id
|
||||||
|
@ -22,6 +27,21 @@ export async function getMeById(req: Request, res: Response): Promise<any> {
|
||||||
res.json(UserFactory.mapToSingle(user));
|
res.json(UserFactory.mapToSingle(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get my routine by id
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function getMyRoutine(req: Request, res: Response): Promise<any> {
|
||||||
|
const id = req.userId;
|
||||||
|
let user = await UserService.getById(id);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
routine: user.routine,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description get my totp
|
* @description get my totp
|
||||||
* @param req {Request} Express req object
|
* @param req {Request} Express req object
|
||||||
|
@ -33,8 +53,6 @@ export async function getMyTotp(req: Request, res: Response): Promise<any> {
|
||||||
|
|
||||||
let { secret, routine } = await UserService.getUserSecretAndRoutine(userId);
|
let { secret, routine } = await UserService.getUserSecretAndRoutine(userId);
|
||||||
|
|
||||||
console.log(secret);
|
|
||||||
|
|
||||||
const url = `otpauth://totp/FF Admin ${SettingHelper.getSetting("club.name")}?secret=${secret}`;
|
const url = `otpauth://totp/FF Admin ${SettingHelper.getSetting("club.name")}?secret=${secret}`;
|
||||||
|
|
||||||
QRCode.toDataURL(url)
|
QRCode.toDataURL(url)
|
||||||
|
@ -60,6 +78,11 @@ export async function verifyMyTotp(req: Request, res: Response): Promise<any> {
|
||||||
let totp = req.body.totp;
|
let totp = req.body.totp;
|
||||||
|
|
||||||
let { secret, routine } = await UserService.getUserSecretAndRoutine(userId);
|
let { secret, routine } = await UserService.getUserSecretAndRoutine(userId);
|
||||||
|
|
||||||
|
if (routine != LoginRoutineEnum.totp) {
|
||||||
|
throw new ForbiddenRequestException("only allowed for totp login");
|
||||||
|
}
|
||||||
|
|
||||||
let valid = speakeasy.totp.verify({
|
let valid = speakeasy.totp.verify({
|
||||||
secret: secret,
|
secret: secret,
|
||||||
encoding: "base32",
|
encoding: "base32",
|
||||||
|
@ -73,6 +96,106 @@ export async function verifyMyTotp(req: Request, res: Response): Promise<any> {
|
||||||
res.sendStatus(204);
|
res.sendStatus(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description change my password
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function changeMyPassword(req: Request, res: Response): Promise<any> {
|
||||||
|
const userId = req.userId;
|
||||||
|
let current = req.body.current;
|
||||||
|
let newpassword = req.body.newpassword;
|
||||||
|
|
||||||
|
let { secret, routine } = await UserService.getUserSecretAndRoutine(userId);
|
||||||
|
|
||||||
|
if (routine == LoginRoutineEnum.password && current != secret) {
|
||||||
|
throw new ForbiddenRequestException("passwords do not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
let updateUser: UpdateUserSecretCommand = {
|
||||||
|
id: userId,
|
||||||
|
secret: newpassword,
|
||||||
|
routine: LoginRoutineEnum.password,
|
||||||
|
};
|
||||||
|
await UserCommandHandler.updateSecret(updateUser);
|
||||||
|
|
||||||
|
res.sendStatus(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get change to totp
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function getChangeToTOTP(req: Request, res: Response): Promise<any> {
|
||||||
|
var secret = speakeasy.generateSecret({ length: 20, name: `FF Admin ${SettingHelper.getSetting("club.name")}` });
|
||||||
|
|
||||||
|
QRCode.toDataURL(secret.otpauth_url)
|
||||||
|
.then((result) => {
|
||||||
|
res.json({
|
||||||
|
dataUrl: result,
|
||||||
|
otp: secret.base32,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
throw new InternalException("QRCode not created", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description change to totp
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function changeToTOTP(req: Request, res: Response): Promise<any> {
|
||||||
|
const userId = req.userId;
|
||||||
|
let otp = req.body.otp;
|
||||||
|
let totp = req.body.totp;
|
||||||
|
|
||||||
|
let valid = speakeasy.totp.verify({
|
||||||
|
secret: otp,
|
||||||
|
encoding: "base32",
|
||||||
|
token: totp,
|
||||||
|
window: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
throw new InternalException("Token not valid or expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
let updateUser: UpdateUserSecretCommand = {
|
||||||
|
id: userId,
|
||||||
|
secret: otp,
|
||||||
|
routine: LoginRoutineEnum.totp,
|
||||||
|
};
|
||||||
|
await UserCommandHandler.updateSecret(updateUser);
|
||||||
|
|
||||||
|
res.sendStatus(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description change to password
|
||||||
|
* @param req {Request} Express req object
|
||||||
|
* @param res {Response} Express res object
|
||||||
|
* @returns {Promise<*>}
|
||||||
|
*/
|
||||||
|
export async function changeToPW(req: Request, res: Response): Promise<any> {
|
||||||
|
const userId = req.userId;
|
||||||
|
let newpassword = req.body.newpassword;
|
||||||
|
|
||||||
|
let updateUser: UpdateUserSecretCommand = {
|
||||||
|
id: userId,
|
||||||
|
secret: newpassword,
|
||||||
|
routine: LoginRoutineEnum.password,
|
||||||
|
};
|
||||||
|
await UserCommandHandler.updateSecret(updateUser);
|
||||||
|
|
||||||
|
res.sendStatus(204);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description transferOwnership
|
* @description transferOwnership
|
||||||
* @param req {Request} Express req object
|
* @param req {Request} Express req object
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { getMeById, getMyTotp, transferOwnership, updateMe, verifyMyTotp } from "../controller/userController";
|
import {
|
||||||
|
changeMyPassword,
|
||||||
|
changeToPW,
|
||||||
|
changeToTOTP,
|
||||||
|
getChangeToTOTP,
|
||||||
|
getMeById,
|
||||||
|
getMyRoutine,
|
||||||
|
getMyTotp,
|
||||||
|
transferOwnership,
|
||||||
|
updateMe,
|
||||||
|
verifyMyTotp,
|
||||||
|
} from "../controller/userController";
|
||||||
|
|
||||||
var router = express.Router({ mergeParams: true });
|
var router = express.Router({ mergeParams: true });
|
||||||
|
|
||||||
|
@ -7,14 +18,34 @@ router.get("/me", async (req, res) => {
|
||||||
await getMeById(req, res);
|
await getMeById(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get("/routine", async (req, res) => {
|
||||||
|
await getMyRoutine(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
router.get("/totp", async (req, res) => {
|
router.get("/totp", async (req, res) => {
|
||||||
await getMyTotp(req, res);
|
await getMyTotp(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get("/changeToTOTP", async (req, res) => {
|
||||||
|
await getChangeToTOTP(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
router.post("/verify", async (req, res) => {
|
router.post("/verify", async (req, res) => {
|
||||||
await verifyMyTotp(req, res);
|
await verifyMyTotp(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post("/changepw", async (req, res) => {
|
||||||
|
await changeMyPassword(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/changeToTOTP", async (req, res) => {
|
||||||
|
await changeToTOTP(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/changeToPW", async (req, res) => {
|
||||||
|
await changeToPW(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
router.put("/transferOwner", async (req, res) => {
|
router.put("/transferOwner", async (req, res) => {
|
||||||
await transferOwnership(req, res);
|
await transferOwnership(req, res);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue