diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts index 519a5c1..d190898 100644 --- a/backend/src/auth/auth.controller.ts +++ b/backend/src/auth/auth.controller.ts @@ -34,9 +34,10 @@ export class AuthController { template: 'activation.ejs', data: { activationUrl }, }); - - res.status(201).json({ message: 'User created. Check your email to activate your account', - activationUrl }); + res.status(201).json({ + message: 'User created. Check your email to activate your account', + activationUrl + }); } catch (error: any) { console.error('Error sending email:', error); next(error); @@ -50,17 +51,11 @@ export class AuthController { return { token, code }; } - // Generate reset password token - async generateResetPasswordToken(user: any) { - const token = jwt.sign(user, process.env.JWT_SECRET, { expiresIn: '1h' }); - return { token }; - } - // Account activation @Post('activate') async activate(@Req() req: Request, @Res() res: Response) { const { token, code } = req.body; - + try { const user: any = jwt.verify(token, process.env.JWT_SECRET); @@ -91,9 +86,46 @@ export class AuthController { } } + /** + * Generates a JWT for a user. + * + * @param user **Any** *(supposed to be a User)* + * @param expiration **string** *Numerical value (ie: '10m' for 10 minutes; '1h' for 1 hr)* + * @returns **JSON object** *with signed JWT* + */ + async generateToken(user: any) { + const token = jwt.sign({ user: user }, process.env.JWT_SECRET, { expiresIn: "1h" }); + return { token }; + } + + // https://supertokens.com/blog/implementing-a-forgot-password-flow + // https://cheatsheetseries.owasp.org/cheatsheets/Forgot_Password_Cheat_Sheet.html @Post('forgot-password') async forgotPassword(@Req() req: Request, @Res() res: Response) { - + const { email } = req.body; + const user = await User.findOne({ email }); + + if (!user) return res.status(400).json({ message: 'User not found' }); + + const resetToken = await this.generateToken(user) + const resetLink = `${process.env.CLIENT_URL}/reset-password?token=${resetToken.token}`; + const template = 'reset-password.ejs'; + + try { + await sendEmail({ + email: user.email, + subject: 'Reset Password', + template, + data: { resetLink }, + }); + res.status(200).json({ + success: true, + message: 'Reset password link sent to email', + resetToken: resetToken.token, + }); + }catch (error: any) { + return res.status(500).json({ message: error.message }); + } } @Post('reset-password') diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index b05321b..3e0afbf 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -1,6 +1,6 @@ import Image from "next/image"; import Link from "next/link"; -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import styles from "../styles/Navbar.module.css"; import { useRouter } from "next/router"; import logo from '../../public/logo.png'; @@ -10,10 +10,28 @@ export default function Navbar() { const [isSignedIn, setIsSignedIn] = useState(false); const [isMenuOpen, setIsMenuOpen] = useState(false); + // Mock function to simulate user authentication check (you can replace this with your real logic) + const checkUserAuth = () => { + return true + }; + + // useEffect to check if the user is signed in when the component mounts + useEffect(() => { + const userSignedIn = checkUserAuth(); + setIsSignedIn(userSignedIn); + }, []); + const toggleMenu = () => { setIsMenuOpen(!isMenuOpen); }; + const handleSignOut = () => { + // Clear authentication token (or other methods of sign out) + localStorage.removeItem("authToken"); + setIsSignedIn(false); + router.push("/signin"); // Redirect to the sign-in page + }; + return (