add change password functionality

This commit is contained in:
StarAppeal
2024-12-08 04:20:14 +01:00
parent 884374c2f6
commit edb97386d1
5 changed files with 101 additions and 6 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
import "dotenv/config";
import mongoose, {Document, Schema} from "mongoose";
import mongoose, {Schema} from "mongoose";
import {ObjectId} from "mongodb";
export interface IUser {
@@ -95,6 +95,6 @@ const userSchema = new Schema<IUser>({
spotifyConfig: {type: spotifyConfigSchema},
timezone: {type: String, required: true},
location: {type: String, required: true},
});
}, {optimisticConcurrency: true});
export const UserModel = mongoose.model<IUser>('User', userSchema);
+4 -1
View File
@@ -16,7 +16,10 @@ export class UserService {
}
public async updateUserById(id: string, user: Partial<IUser>): Promise<IUser | null> {
return await UserModel.findByIdAndUpdate(id, user, {new: true}).exec();
return await UserModel.findByIdAndUpdate(id, user, {
new: true,
projection: {password: 0},
}).exec();
}
public async updateUser(user: IUser): Promise<IUser | null> {
+10 -3
View File
@@ -3,8 +3,8 @@ import {UserService} from "../db/services/db/UserService";
import {IUser} from "../db/models/user";
import {ObjectId} from "mongodb";
import {JwtAuthenticator} from "../utils/jwtAuthenticator";
import bcrypt from "bcrypt";
import crypto from "crypto"
import {PasswordUtils} from "../utils/passwordUtils";
export class RestAuth {
public createRouter() {
@@ -22,7 +22,14 @@ export class RestAuth {
return;
}
const hashedPassword = await bcrypt.hash(password, 10);
const passwordValidation = PasswordUtils.validatePassword(password);
if (!passwordValidation.valid) {
res.status(400).send({success: false, message: passwordValidation.message});
return;
}
const hashedPassword = await PasswordUtils.hashPassword(password);
const newUser: IUser = {
id: ObjectId.createFromTime(Date.now()),
name: username,
@@ -51,7 +58,7 @@ export class RestAuth {
return;
}
const isValid = await bcrypt.compare(password, user.password!);
const isValid = await PasswordUtils.comparePassword(password, user.password!);
if (!isValid) {
res.status(401).send({success: false, message: "Invalid password", id: "password"});
+33
View File
@@ -1,6 +1,7 @@
import express from "express";
import {UserService} from "../db/services/db/UserService";
import {IUser} from "../db/models/user";
import {PasswordUtils} from "../utils/passwordUtils";
export class RestUser {
public createRouter() {
@@ -18,6 +19,38 @@ export class RestUser {
res.status(200).send(user);
});
router.put("/me/password", async (req, res) => {
const userService = await UserService.create();
const user = await userService.getUserByUUID(req.payload.uuid);
const password = req.body.password;
const passwordConfirmation = req.body.passwordConfirmation;
if (password !== passwordConfirmation) {
res.status(400).send({
result: {
success: false,
message: "Passwörter stimmen nicht überein"
}
});
return;
}
const passwordValidation = PasswordUtils.validatePassword(password);
if (!passwordValidation.valid) {
res.status(400).send({result: passwordValidation});
return;
}
PasswordUtils.hashPassword(password).then(hashedPassword => {
user!.password = hashedPassword;
userService.updateUser(user!)
.then(() => {
res.status(200).send({result: {success: true, message: "Passwort erfolgreich geändert"}});
});
});
});
router.get("/:id", async (req, res) => {
const userService = await UserService.create();
const id = req.params.id;
+52
View File
@@ -0,0 +1,52 @@
import bcrypt from "bcrypt";
export type ValidationResult = {
valid: boolean;
message?: string;
};
export class PasswordUtils {
private constructor() {
}
public static async hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, 10);
}
public static async comparePassword(password: string, hashedPassword: string): Promise<boolean> {
const bcrypt = await import('bcrypt');
return bcrypt.compare(password, hashedPassword);
}
public static validatePassword(password: string): ValidationResult {
const minLength = 8;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumber = /[0-9]/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
if (password.length < minLength) {
return {valid: false, message: `Passwort muss mindestens ${minLength} Zeichen lang sein.`};
}
if (!hasUpperCase) {
return {valid: false, message: "Passwort muss mindestens einen Großbuchstaben enthalten."};
}
if (!hasLowerCase) {
return {valid: false, message: "Passwort muss mindestens einen Kleinbuchstaben enthalten."};
}
if (!hasNumber) {
return {valid: false, message: "Passwort muss mindestens eine Zahl enthalten."};
}
if (!hasSpecialChar) {
return {valid: false, message: "Passwort muss mindestens ein Sonderzeichen enthalten."};
}
return {valid: true, message: "Passwort ist gültig."};
}
}