Roles done

This commit is contained in:
MathieuSevignyLavallee 2024-10-19 13:13:16 -04:00
parent d7986447c4
commit e30681705f
14 changed files with 227 additions and 223 deletions

View file

@ -15,7 +15,6 @@ const AuthSelection: React.FC = () => {
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
const data = await authService.fetchAuthData(); const data = await authService.fetchAuthData();
console.log(data);
setAuthData(data); setAuthData(data);
}; };

View file

@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom'; import { useNavigate, useLocation } from 'react-router-dom';
import apiService from '../../../services/ApiService'; import apiService from '../../../services/ApiService';
import { jwtDecode } from 'jwt-decode';
const OAuthCallback: React.FC = () => { const OAuthCallback: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -12,15 +11,7 @@ const OAuthCallback: React.FC = () => {
const user = searchParams.get('user'); const user = searchParams.get('user');
if (user) { if (user) {
// Save user data to localStorage or sessionStorage
console.log(user);
apiService.saveToken(user); apiService.saveToken(user);
const decodedToken = jwtDecode(user);
const { email } = decodedToken as { email: string;};
console.log(email + " connected!");
// Navigate to the dashboard or another page
navigate('/'); navigate('/');
} else { } else {
navigate('/login'); navigate('/login');

View file

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import { ENV_VARIABLES } from '../../../../constants';
import '../css/buttonAuth.css'; import '../css/buttonAuth.css';
interface ButtonAuthContainerProps { interface ButtonAuthContainerProps {
@ -8,7 +7,7 @@ interface ButtonAuthContainerProps {
} }
const handleAuthLogin = (provider: string) => { const handleAuthLogin = (provider: string) => {
window.location.href = `${ENV_VARIABLES.VITE_BACKEND_URL}/api/auth/` + provider; window.location.href = `/api/auth/` + provider;
}; };
const ButtonAuth: React.FC<ButtonAuthContainerProps> = ({ providerName, providerType }) => { const ButtonAuth: React.FC<ButtonAuthContainerProps> = ({ providerName, providerType }) => {

View file

@ -1,4 +1,4 @@
import { useNavigate, Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
// JoinRoom.tsx // JoinRoom.tsx
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
@ -11,7 +11,6 @@ import LoginContainer from '../../../../components/LoginContainer/LoginContainer
import ApiService from '../../../../services/ApiService'; import ApiService from '../../../../services/ApiService';
const SimpleLogin: React.FC = () => { const SimpleLogin: React.FC = () => {
const navigate = useNavigate();
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
@ -27,15 +26,10 @@ const SimpleLogin: React.FC = () => {
const login = async () => { const login = async () => {
const result = await ApiService.login(email, password); const result = await ApiService.login(email, password);
if (result !== true) {
if (result != true) {
setConnectionError(result); setConnectionError(result);
return; return;
} }
else {
navigate("/")
}
}; };

View file

@ -1,5 +1,3 @@
import { useNavigate } from 'react-router-dom';
// JoinRoom.tsx // JoinRoom.tsx
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
@ -10,7 +8,6 @@ import LoginContainer from '../../../../components/LoginContainer/LoginContainer
import ApiService from '../../../../services/ApiService'; import ApiService from '../../../../services/ApiService';
const Register: React.FC = () => { const Register: React.FC = () => {
const navigate = useNavigate();
const [name, setName] = useState(''); // State for name const [name, setName] = useState(''); // State for name
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
@ -46,8 +43,6 @@ const Register: React.FC = () => {
setConnectionError(result); setConnectionError(result);
return; return;
} }
navigate("/login");
}; };
return ( return (

View file

@ -1,5 +1,5 @@
import axios, { AxiosError, AxiosResponse } from 'axios'; import axios, { AxiosError, AxiosResponse } from 'axios';
import {jwtDecode} from 'jwt-decode'; import { jwtDecode } from 'jwt-decode';
import { ENV_VARIABLES } from '../constants'; import { ENV_VARIABLES } from '../constants';
import { QuizType } from '../Types/QuizType'; import { QuizType } from '../Types/QuizType';
@ -79,26 +79,25 @@ class ApiService {
public isLoggedInTeacher(): boolean { public isLoggedInTeacher(): boolean {
const token = this.getToken(); const token = this.getToken();
console.log("Check if loggedIn : " + token);
if (token == null) { if (token == null) {
return false; return false;
} }
try { try {
const decodedToken = jwtDecode(token) as { roles: string[] }; const decodedToken = jwtDecode(token) as { roles: string[] };
const userRoles = decodedToken.roles; const userRoles = decodedToken.roles;
const requiredRole = 'teacher'; const requiredRole = 'teacher';
if (!userRoles || !userRoles.includes(requiredRole)) { if (!userRoles || !userRoles.includes(requiredRole)) {
return false; return false;
} }
// Update token expiry // Update token expiry
this.saveToken(token); this.saveToken(token);
return true; return true;
} catch (error) { } catch (error) {
console.error("Error decoding token:", error); console.error("Error decoding token:", error);
@ -129,8 +128,12 @@ class ApiService {
const result: AxiosResponse = await axios.post(url, body, { headers: headers }); const result: AxiosResponse = await axios.post(url, body, { headers: headers });
if (result.status !== 200) { console.log(result);
throw new Error(`L'enregistrement a échoué. Status: ${result.status}`); if (result.status == 200) {
window.location.href = result.request.responseURL;
}
else {
throw new Error(`La connexion a échoué. Status: ${result.status}`);
} }
return true; return true;
@ -152,39 +155,52 @@ class ApiService {
* @returns true if successful * @returns true if successful
* @returns A error string if unsuccessful, * @returns A error string if unsuccessful,
*/ */
public async login(email: string, password: string): Promise<any> { /**
try { * @returns true if successful
* @returns An error string if unsuccessful
if (!email || !password) { */
throw new Error(`L'email et le mot de passe sont requis.`); public async login(email: string, password: string): Promise<any> {
} try {
if (!email || !password) {
const url: string = this.constructRequestUrl(`/auth/simple-auth/login`); throw new Error("L'email et le mot de passe sont requis.");
const headers = this.constructRequestHeaders();
const body = { email, password };
const result: AxiosResponse = await axios.post(url, body, { headers: headers });
if (result.status !== 200) {
throw new Error(`La connexion a échoué. Status: ${result.status}`);
}
this.saveToken(result.data.token);
return true;
} catch (error) {
console.log("Error details: ", error);
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const data = err.response?.data as { error: string } | undefined;
return data?.error || 'Erreur serveur inconnue lors de la requête.';
}
return `Une erreur inattendue s'est produite.`
} }
const url: string = this.constructRequestUrl(`/auth/simple-auth/login`);
const headers = this.constructRequestHeaders();
const body = { email, password };
const result: AxiosResponse = await axios.post(url, body, { headers: headers });
// If login is successful, redirect the user
if (result.status === 200) {
window.location.href = result.request.responseURL;
return true;
} else {
throw new Error(`La connexion a échoué. Statut: ${result.status}`);
}
} catch (error) {
console.log("Error details:", error);
// Handle Axios-specific errors
if (axios.isAxiosError(error)) {
const err = error as AxiosError;
const responseData = err.response?.data as { message?: string } | undefined;
// If there is a message field in the response, print it
if (responseData?.message) {
console.log("Backend error message:", responseData.message);
return responseData.message;
}
// If no message is found, return a fallback message
return "Erreur serveur inconnue lors de la requête.";
}
// Handle other non-Axios errors
return "Une erreur inattendue s'est produite.";
} }
}
/** /**
* @returns true if successful * @returns true if successful

View file

@ -15,7 +15,6 @@ class AuthService {
async fetchAuthData(){ async fetchAuthData(){
try { try {
const response = await fetch(this.constructRequestUrl('/auth/getActiveAuth')); const response = await fetch(this.constructRequestUrl('/auth/getActiveAuth'));
console.log("base url: " + this.BASE_URL);
const data = await response.json(); const data = await response.json();
return data.authActive; return data.authActive;
} catch (error) { } catch (error) {

View file

@ -7,8 +7,6 @@ services:
context: ./client context: ./client
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: frontend container_name: frontend
environment:
VITE_BACKEND_URL: http://localhost:3000
ports: ports:
- "5173:5173" - "5173:5173"
restart: always restart: always

View file

@ -43,8 +43,8 @@ class AuthManager{
} }
async login(userInfo,req,res,next){ async login(userInfo,req,res,next){
const tokenToSave = jwt.create(userInfo.email, userInfo._id); const tokenToSave = jwt.create(userInfo.email, userInfo._id,userInfo.roles);
res.redirect(`${process.env['FRONTEND_URL']}/auth/callback?user=${tokenToSave}`); res.redirect(`/auth/callback?user=${tokenToSave}`);
console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`) console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`)
} }

View file

@ -5,13 +5,13 @@ var { hasNestedValue } = require('../../../utils')
var jwt = require('../../../middleware/jwtToken') var jwt = require('../../../middleware/jwtToken')
class PassportOAuth { class PassportOAuth {
constructor(passportjs,auth_name){ constructor(passportjs, auth_name) {
this.passportjs = passportjs this.passportjs = passportjs
this.auth_name = auth_name this.auth_name = auth_name
} }
register(app, passport,endpoint, name, provider) { register(app, passport, endpoint, name, provider) {
const cb_url =`${process.env['BACKEND_URL']}${endpoint}/${name}/callback` const cb_url = `${process.env['BACKEND_URL']}${endpoint}/${name}/callback`
const self = this const self = this
passport.use(name, new OAuth2Strategy({ passport.use(name, new OAuth2Strategy({
@ -22,72 +22,72 @@ class PassportOAuth {
callbackURL: cb_url, callbackURL: cb_url,
passReqToCallback: true passReqToCallback: true
}, },
async function(req, accessToken, refreshToken, params, profile, done) { async function (req, accessToken, refreshToken, params, profile, done) {
try { try {
const userInfoResponse = await fetch(provider.OAUTH_USERINFO_URL, { const userInfoResponse = await fetch(provider.OAUTH_USERINFO_URL, {
headers: { 'Authorization': `Bearer ${accessToken}` } headers: { 'Authorization': `Bearer ${accessToken}` }
}); });
const userInfo = await userInfoResponse.json(); const userInfo = await userInfoResponse.json();
let received_user = { let received_user = {
auth_id: userInfo.sub, auth_id: userInfo.sub,
email: userInfo.email, email: userInfo.email,
name: userInfo.name, name: userInfo.name,
roles: [] roles: []
}; };
if(hasNestedValue(userInfo,provider.OAUTH_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
if(hasNestedValue(userInfo,provider.OAUTH_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
const user_association = await authUserAssoc.find_user_association(self.auth_name,received_user.auth_id) if (hasNestedValue(userInfo, provider.OAUTH_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
if (hasNestedValue(userInfo, provider.OAUTH_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
let user_account const user_association = await authUserAssoc.find_user_association(self.auth_name, received_user.auth_id)
if(user_association){
user_account = await users.getById(user_association.user_id) let user_account
} if (user_association) {
else { user_account = await users.getById(user_association.user_id)
let user_id = await users.getId(received_user.email)
if(user_id){
user_account = await users.getById(user_id);
} else {
received_user.password = users.generatePassword()
user_account = await self.passportjs.register(received_user)
} }
await authUserAssoc.link(self.auth_name,received_user.auth_id,user_account._id) else {
let user_id = await users.getId(received_user.email)
if (user_id) {
user_account = await users.getById(user_id);
} else {
received_user.password = users.generatePassword()
user_account = await self.passportjs.register(received_user)
}
await authUserAssoc.link(self.auth_name, received_user.auth_id, user_account._id)
}
user_account.name = received_user.name
user_account.roles = received_user.roles
await users.editUser(user_account)
// Store the tokens in the session
req.session.oauth2Tokens = {
accessToken: accessToken,
refreshToken: refreshToken,
expiresIn: params.expires_in
};
return done(null, user_account);
} catch (error) {
console.error(`Erreur dans la strategie OAuth2 '${name}' : ${error}`);
return done(error);
} }
}));
user_account.name = received_user.name
user_account.roles = received_user.roles
await users.editUser(user_account)
// Store the tokens in the session
req.session.oauth2Tokens = {
accessToken: accessToken,
refreshToken: refreshToken,
expiresIn: params.expires_in
};
return done(null, user_account);
} catch (error) {
console.error(`Erreur dans la strategie OAuth2 '${name}' : ${error}`);
return done(error);
}
}));
app.get(`${endpoint}/${name}`, (req, res, next) => { app.get(`${endpoint}/${name}`, (req, res, next) => {
passport.authenticate(name, { passport.authenticate(name, {
scope: 'openid profile email offline_access'+ ` ${provider.OAUTH_ADD_SCOPE}`, scope: 'openid profile email offline_access' + ` ${provider.OAUTH_ADD_SCOPE}`,
prompt: 'consent' prompt: 'consent'
})(req, res, next); })(req, res, next);
}); });
app.get(`${endpoint}/${name}/callback`, app.get(`${endpoint}/${name}/callback`,
(req, res, next) => { (req, res, next) => {
passport.authenticate(name, { failureRedirect: '/login' })(req, res, next); passport.authenticate(name, { failureRedirect: '/login' })(req, res, next);
}, },
(req, res) => { (req, res) => {
if (req.user) { if (req.user) {
self.passportjs.authenticate(req.user,req,res) self.passportjs.authenticate(req.user, req, res)
} else { } else {
res.status(401).json({ error: "L'authentification a échoué" }); res.status(401).json({ error: "L'authentification a échoué" });
} }

View file

@ -5,13 +5,13 @@ var { hasNestedValue } = require('../../../utils')
var jwt = require('../../../middleware/jwtToken') var jwt = require('../../../middleware/jwtToken')
class PassportOpenIDConnect { class PassportOpenIDConnect {
constructor(passportjs,auth_name){ constructor(passportjs, auth_name) {
this.passportjs = passportjs this.passportjs = passportjs
this.auth_name = auth_name this.auth_name = auth_name
} }
async getConfigFromConfigURL(name,provider){ async getConfigFromConfigURL(name, provider) {
try{ try {
const config = await fetch(provider.OIDC_CONFIG_URL) const config = await fetch(provider.OIDC_CONFIG_URL)
return await config.json() return await config.json()
} catch (error) { } catch (error) {
@ -19,10 +19,10 @@ class PassportOpenIDConnect {
} }
} }
async register(app, passport,endpoint, name, provider) { async register(app, passport, endpoint, name, provider) {
const config = await this.getConfigFromConfigURL(name,provider) const config = await this.getConfigFromConfigURL(name, provider)
const cb_url =`${process.env['BACKEND_URL']}${endpoint}/${name}/callback` const cb_url = `${process.env['BACKEND_URL']}${endpoint}/${name}/callback`
const self = this const self = this
passport.use(name, new OpenIDConnectStrategy({ passport.use(name, new OpenIDConnectStrategy({
@ -36,59 +36,60 @@ class PassportOpenIDConnect {
passReqToCallback: true, passReqToCallback: true,
scope: 'openid profile email ' + `${provider.OIDC_ADD_SCOPE}`, scope: 'openid profile email ' + `${provider.OIDC_ADD_SCOPE}`,
}, },
// patch pour la librairie permet d'obtenir les groupes, PR en cours mais "morte" : https://github.com/jaredhanson/passport-openidconnect/pull/101 // patch pour la librairie permet d'obtenir les groupes, PR en cours mais "morte" : https://github.com/jaredhanson/passport-openidconnect/pull/101
async function(req, issuer, profile, times, tok, done) { async function (req, issuer, profile, times, tok, done) {
try { try {
const received_user = { const received_user = {
auth_id: profile.id, auth_id: profile.id,
email: profile.emails[0].value, email: profile.emails[0].value,
name: profile.name.givenName, name: profile.name.givenName,
roles: [] roles: []
}; };
if(hasNestedValue(profile,provider.OIDC_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
if(hasNestedValue(profile,provider.OIDC_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
const user_association = await authUserAssoc.find_user_association(self.auth_name,received_user.auth_id)
let user_account if (hasNestedValue(profile, provider.OIDC_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
if(user_association){ if (hasNestedValue(profile, provider.OIDC_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
user_account = await users.getById(user_association.user_id)
} const user_association = await authUserAssoc.find_user_association(self.auth_name, received_user.auth_id)
else {
let user_id = await users.getId(received_user.email) let user_account
if(user_id){ if (user_association) {
user_account = await users.getById(user_id); user_account = await users.getById(user_association.user_id)
} else {
received_user.password = users.generatePassword()
user_account = await self.passportjs.register(received_user)
} }
await authUserAssoc.link(self.auth_name,received_user.auth_id,user_account._id) else {
let user_id = await users.getId(received_user.email)
if (user_id) {
user_account = await users.getById(user_id);
} else {
received_user.password = users.generatePassword()
user_account = await self.passportjs.register(received_user)
}
await authUserAssoc.link(self.auth_name, received_user.auth_id, user_account._id)
}
user_account.name = received_user.name
user_account.roles = received_user.roles
await users.editUser(user_account)
return done(null, user_account);
} catch (error) {
} }
}));
user_account.name = received_user.name
user_account.roles = received_user.roles
await users.editUser(user_account)
return done(null, user_account);
} catch (error) {
}
}));
app.get(`${endpoint}/${name}`, (req, res, next) => { app.get(`${endpoint}/${name}`, (req, res, next) => {
passport.authenticate(name, { passport.authenticate(name, {
scope: 'openid profile email offline_access'+ ` ${provider.OAUTH_ADD_SCOPE}`, scope: 'openid profile email offline_access' + ` ${provider.OAUTH_ADD_SCOPE}`,
prompt: 'consent' prompt: 'consent'
})(req, res, next); })(req, res, next);
}); });
app.get(`${endpoint}/${name}/callback`, app.get(`${endpoint}/${name}/callback`,
(req, res, next) => { (req, res, next) => {
passport.authenticate(name, { failureRedirect: '/login' })(req, res, next); passport.authenticate(name, { failureRedirect: '/login' })(req, res, next);
}, },
(req, res) => { (req, res) => {
if (req.user) { if (req.user) {
self.passportjs.authenticate(req.user,req,res) self.passportjs.authenticate(req.user, req, res)
} else { } else {
res.status(401).json({ error: "L'authentification a échoué" }); res.status(401).json({ error: "L'authentification a échoué" });
} }

View file

@ -6,52 +6,34 @@ const AppError = require('../../middleware/AppError.js');
const { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR } = require('../../constants/errorCodes'); const { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR } = require('../../constants/errorCodes');
const { name } = require('../../models/authProvider.js'); const { name } = require('../../models/authProvider.js');
class SimpleAuth{ class SimpleAuth {
constructor(authmanager,settings){ constructor(authmanager, settings) {
this.authmanager = authmanager this.authmanager = authmanager
this.providers = settings this.providers = settings
this.endpoint = "/api/auth/simple-auth" this.endpoint = "/api/auth/simple-auth"
} }
async registerAuth(expressapp){ async registerAuth(expressapp) {
try{ try {
expressapp.post(`${this.endpoint}/register`, (req,res,next)=>this.register(this,req,res)); expressapp.post(`${this.endpoint}/register`, (req, res, next) => this.register(this, req, res));
expressapp.post(`${this.endpoint}/login`, (req,res,next)=>this.authenticate(this,req,res)); expressapp.post(`${this.endpoint}/login`, (req, res, next) => this.authenticate(this, req, res));
expressapp.post(`${this.endpoint}/reset-password`, (req,res,next)=>this.resetPassword(this,req,res)); expressapp.post(`${this.endpoint}/reset-password`, (req, res, next) => this.resetPassword(this, req, res));
expressapp.post(`${this.endpoint}/change-password`, jwt.authenticate, (req,res,next)=>this.changePassword(this,req,res)); expressapp.post(`${this.endpoint}/change-password`, jwt.authenticate, (req, res, next) => this.changePassword(this, req, res));
} catch(error){ } catch (error) {
console.error(`La connexion ${name} de type ${provider.type} n'as pu être chargé.`) console.error(`La connexion ${name} de type ${provider.type} n'as pu être chargé.`)
} }
} }
async register(self,req, res) { async register(self, req, res) {
let userInfos = {
name: req.body.name,
email: req.body.email,
password: req.body.password,
roles: req.body.roles
}
let user = await self.authmanager.register(userInfos)
if(user) res.redirect("/")
else res.redirect("/login")
}
async authenticate(self,req, res, next) {
try { try {
const { email, password } = req.body; let userInfos = {
name: req.body.name,
if (!email || !password) { email: req.body.email,
throw new AppError(MISSING_REQUIRED_PARAMETER); password: req.body.password,
roles: req.body.roles
} }
let user = await self.authmanager.register(userInfos)
const user = await model.login(email, password); if (user) res.redirect("/login")
if (!user) {
throw new AppError(LOGIN_CREDENTIALS_ERROR);
}
user.name = user.name ?? user.email
self.authmanager.login(user,req,res,next)
} }
catch (error) { catch (error) {
return res.status(400).json({ return res.status(400).json({
@ -60,7 +42,29 @@ class SimpleAuth{
} }
} }
async resetPassword(self,req, res, next) { async authenticate(self, req, res, next) {
try {
const { email, password } = req.body;
if (!email || !password) {
const error = new Error("Email or password is missing");
error.statusCode = 400;
throw error;
}
const user = await model.login(email, password);
await self.authmanager.login(user, req, res, next);
} catch (error) {
const statusCode = error.statusCode || 500;
const message = error.message || "An internal server error occurred";
console.error(error);
return res.status(statusCode).json({ message });
}
}
async resetPassword(self, req, res, next) {
try { try {
const { email } = req.body; const { email } = req.body;
@ -85,7 +89,7 @@ class SimpleAuth{
} }
} }
async changePassword(self,req, res, next) { async changePassword(self, req, res, next) {
try { try {
const { email, oldPassword, newPassword } = req.body; const { email, oldPassword, newPassword } = req.body;
@ -114,7 +118,7 @@ class SimpleAuth{
return next(error); return next(error);
} }
} }
} }
module.exports = SimpleAuth; module.exports = SimpleAuth;

View file

@ -7,8 +7,8 @@ dotenv.config();
class Token { class Token {
create(email, userId) { create(email, userId, roles) {
return jwt.sign({ email, userId }, process.env.JWT_SECRET); return jwt.sign({ email, userId, roles }, process.env.JWT_SECRET);
} }
authenticate(req, res, next) { authenticate(req, res, next) {
@ -25,11 +25,11 @@ class Token {
req.user = payload; req.user = payload;
}); });
} catch (error) { } catch (error) {
return next(error); return next(error);
} }
return next(); return next();
} }
} }

View file

@ -64,24 +64,32 @@ class Users {
} }
async login(email, password) { async login(email, password) {
await db.connect(); try {
const conn = db.getConnection(); await db.connect();
const conn = db.getConnection();
const userCollection = conn.collection("users");
const userCollection = conn.collection("users"); const user = await userCollection.findOne({ email: email });
const user = await userCollection.findOne({ email: email }); if (!user) {
const error = new Error("User not found");
error.statusCode = 404;
throw error;
}
if (!user) { const passwordMatch = await this.verify(password, user.password);
return false;
if (!passwordMatch) {
const error = new Error("Password does not match");
error.statusCode = 401;
throw error;
}
return user;
} catch (error) {
console.error(error);
throw error;
} }
const passwordMatch = await this.verify(password, user.password);
if (!passwordMatch) {
return false;
}
return user;
} }
async resetPassword(email) { async resetPassword(email) {