diff --git a/server/controllers/applicationsController.ts b/server/controllers/applicationsController.ts index 400c26f..4778427 100644 --- a/server/controllers/applicationsController.ts +++ b/server/controllers/applicationsController.ts @@ -1,5 +1,4 @@ import { Request, Response } from 'express'; -import { CustomRequest } from '../types/customRequest'; import { pool } from '../config/sql-db'; interface StatusCount { @@ -104,7 +103,7 @@ const createApplication = async (req: Request, res: Response) => { } }; -const getApplicationById = async (req: CustomRequest<{ id: string }>, res: Response) => { +const getApplicationById = async (req: Request, res: Response) => { const { id } = req.params; try { const query = ` @@ -145,7 +144,7 @@ const getApplicationById = async (req: CustomRequest<{ id: string }>, res: Respo } }; -const updateApplication = async (req: CustomRequest<{ id: string }>, res: Response) => { +const updateApplication = async (req: Request, res: Response) => { const { id } = req.params; if (!req.user) { @@ -184,7 +183,7 @@ const updateApplication = async (req: CustomRequest<{ id: string }>, res: Respon } }; -const getAggregatedUserStats = async (req: CustomRequest<{ userId: string }>, res: Response) => { +const getAggregatedUserStats = async (req: Request, res: Response) => { const { userId } = req.params; if (!req.user || req.user.id !== userId) return res.status(401).json({ message: 'You are not authorized to retrieve those records' }); diff --git a/server/controllers/authController.ts b/server/controllers/authController.ts index 28df5f3..5fc5c5c 100644 --- a/server/controllers/authController.ts +++ b/server/controllers/authController.ts @@ -1,37 +1,9 @@ -import jwt from 'jsonwebtoken'; -import User from '../models/userModel'; -import asyncHandler from 'express-async-handler'; +import { Request, Response } from 'express'; +import { NotAuthorizedError } from '../errors'; -const authSession = asyncHandler(async (req, res) => { - let token; - - if (req.cookies.token) { - try { - token = req.cookies.token; - const secret = process.env.JWT_SECRET as string; - const decoded = jwt.verify(token, secret) as jwt.JwtPayload; - - if (!decoded.id) { - throw new Error('Invalid token - ID not found'); - } - - const user = await User.findById(decoded.id).select('-password'); - - if (!user) throw new Error('User not found'); - - res.locals.user = user; - res.json({ isAuthenticated: true, user: res.locals.user }); - } catch (error) { - console.error(error); - res.status(401); - throw new Error('Not authorized, token failed'); - } - } - - if (!token) { - res.status(401); - throw new Error('Not authorized, no token'); - } -}); +const authSession = async (_req: Request, res: Response) => { + if (!res.locals.user) throw new NotAuthorizedError(); + res.json({ isAuthenticated: true, user: res.locals.user }); +}; export { authSession }; diff --git a/server/controllers/postController.ts b/server/controllers/postController.ts index 313cc79..19d4ce6 100644 --- a/server/controllers/postController.ts +++ b/server/controllers/postController.ts @@ -1,7 +1,6 @@ import Post from '../models/postModel'; import Thread from '../models/threadModel'; import { Request, Response, NextFunction } from 'express'; -import { CustomRequest } from '../types/customRequest'; // ENDPOINT GET api/forums/:forumId/threads/:threadId/posts // PURPOSE Retrieve all posts from a specific thread @@ -27,7 +26,7 @@ const listPostsByThreadId = async (req: Request, res: Response, next: NextFuncti // ENDPOINT POST api/forums/:forumId/threads/:threadId/posts // PURPOSE Create a new post on thread // ACCESS Private -const createPost = async (req: CustomRequest, res: Response, next: NextFunction) => { +const createPost = async (req: Request, res: Response, next: NextFunction) => { const { threadId } = req.params; const { content } = req.body; @@ -60,7 +59,7 @@ const createPost = async (req: CustomRequest, res: Response, next: NextFunction) // ENDPOINT PUT api/forums/:forumId/threads/:threadId/:postId // PURPOSE Update an existing post // ACCESS Private -const updatePost = async (req: CustomRequest, res: Response, next: NextFunction) => { +const updatePost = async (req: Request, res: Response, next: NextFunction) => { const { postId } = req.params; const { content } = req.body; @@ -97,7 +96,7 @@ const updatePost = async (req: CustomRequest, res: Response, next: NextFunction) // ENDPOINT DELETE api/forums/:forumId/threads/:threadId/:postId // PURPOSE Delete an existing post // ACCESS Private, Admin -const deletePost = async (req: CustomRequest, res: Response, next: NextFunction) => { +const deletePost = async (req: Request, res: Response, next: NextFunction) => { const { postId } = req.params; try { diff --git a/server/controllers/threadController.ts b/server/controllers/threadController.ts index 5a32ecc..68bc798 100644 --- a/server/controllers/threadController.ts +++ b/server/controllers/threadController.ts @@ -1,12 +1,11 @@ import Post from '../models/postModel'; import Thread from '../models/threadModel'; import { Request, Response, NextFunction } from 'express'; -import { CustomRequest } from '../types/customRequest'; // ENDPOINT POST api/:forumId/threads // PURPOSE Create a new thread // ACCESS Private -const createThread = async (req: CustomRequest, res: Response, next: NextFunction) => { +const createThread = async (req: Request, res: Response, next: NextFunction) => { const { forumId } = req.params; const { title, content } = req.body; @@ -36,7 +35,7 @@ const createThread = async (req: CustomRequest, res: Response, next: NextFunctio // ENDPOINT GET api/threads // PURPOSE Retrieve all threads // ACCESS Private -const getAllThreads = async (req: CustomRequest, res: Response, next: NextFunction) => { +const getAllThreads = async (req: Request, res: Response, next: NextFunction) => { try { const threads = await Thread.find({}).populate('user', 'firstName lastName').exec(); res.status(200).json(threads); @@ -102,7 +101,7 @@ const getThreadById = async (req: Request, res: Response, next: NextFunction) => // ENDPOINT PUT api/forums/:forumId/threads/:threadId // PURPOSE Update a specific thread // ACCESS Private/Admin -const updateThread = async (req: CustomRequest, res: Response, next: NextFunction) => { +const updateThread = async (req: Request, res: Response, next: NextFunction) => { const { forumId, threadId } = req.params; const { title, content } = req.body; @@ -135,7 +134,7 @@ const updateThread = async (req: CustomRequest, res: Response, next: NextFunctio // ENDPOINT DELETE api/forums/:forumId/threads/:threadId // PURPOSE Delete a specific thread // ACCESS Private/Admin -const deleteThread = async (req: CustomRequest, res: Response, next: NextFunction) => { +const deleteThread = async (req: Request, res: Response, next: NextFunction) => { const { forumId, threadId } = req.params; try { diff --git a/server/middleware/authMiddleware.ts b/server/middleware/authMiddleware.ts index beddda8..066d581 100644 --- a/server/middleware/authMiddleware.ts +++ b/server/middleware/authMiddleware.ts @@ -1,38 +1,36 @@ -import jwt from 'jsonwebtoken'; +import jwt, { JwtPayload } from 'jsonwebtoken'; import User from '../models/userModel'; -import asyncHandler from 'express-async-handler'; -import { CustomRequest } from '../types/customRequest'; - -const protect = asyncHandler(async (req: CustomRequest, res, next) => { - let token; - - if (req.cookies.token) { - try { - token = req.cookies.token; - const secret = process.env.JWT_SECRET as string; - const decoded = jwt.verify(token, secret) as jwt.JwtPayload; - - if (!decoded.id) { - throw new Error('Invalid token - ID not found'); - } - - const user = await User.findById(decoded.id).select('-password'); - - if (!user) throw new Error('User not found'); - req.user = { id: user._id.toString() }; - res.locals.user = user; - next(); - } catch (error) { - console.error(error); - res.status(401); - throw new Error('Not authorized, token failed'); - } +import { Request, Response, NextFunction } from 'express'; +import { NotAuthorizedError } from '../errors'; + +interface UserPayload { + id: string; +} + +declare module 'express-serve-static-core' { + interface Request { + user?: UserPayload; } +} + +const protect = async (req: Request, res: Response, next: NextFunction) => { + const { token } = req.cookies; + + if (!token) throw new NotAuthorizedError(); + + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET!) as JwtPayload; + + const user = await User.findById(decoded.id).select('-password'); + + if (!user) throw new NotAuthorizedError(); - if (!token) { - res.status(401); - throw new Error('Not authorized, no token'); + req.user = { id: user._id.toString() }; + res.locals.user = user; + next(); + } catch (error) { + throw new NotAuthorizedError(); } -}); +}; export { protect }; diff --git a/server/routes/alumniRoutes.ts b/server/routes/alumniRoutes.ts index cb12bfd..c4a3d7b 100644 --- a/server/routes/alumniRoutes.ts +++ b/server/routes/alumniRoutes.ts @@ -1,10 +1,10 @@ import express from 'express'; - import { protect } from '../middleware/authMiddleware'; import { getAllAlumniData } from '../controllers/alumniControllers'; const router = express.Router(); -router.get('/', protect, getAllAlumniData); +router.use(protect); /* Require Auth for ALL routes below */ +router.get('/', getAllAlumniData); export default router; diff --git a/server/routes/applicationsRoutes.ts b/server/routes/applicationsRoutes.ts index 32a198e..840eaf6 100644 --- a/server/routes/applicationsRoutes.ts +++ b/server/routes/applicationsRoutes.ts @@ -1,4 +1,5 @@ import express from 'express'; +import { protect } from '../middleware/authMiddleware'; import { createApplication, getAllApplications, @@ -9,17 +10,17 @@ import { updateNotificationPeriod, pauseNotifications, } from '../controllers/applicationsController'; -import { protect } from '../middleware/authMiddleware'; const router = express.Router(); -router.get('/aggregated-user-stats/:userId', protect, getAggregatedUserStats); -router.get('/statuses', protect, getStatuses); -router.get('/', protect, getAllApplications); -router.get('/:id', protect, getApplicationById); -router.post('/', protect, createApplication); -router.put('/:id', protect, updateApplication); -router.put('/:id/notification-period', protect, updateNotificationPeriod); -router.put('/:id/pause-notifications', protect, pauseNotifications); +router.use(protect); /* Require Auth for ALL routes below */ +router.get('/aggregated-user-stats/:userId', getAggregatedUserStats); +router.get('/statuses', getStatuses); +router.get('/', getAllApplications); +router.get('/:id', getApplicationById); +router.post('/', createApplication); +router.put('/:id', updateApplication); +router.put('/:id/notification-period', updateNotificationPeriod); +router.put('/:id/pause-notifications', pauseNotifications); export default router; diff --git a/server/routes/authRoutes.ts b/server/routes/authRoutes.ts index 6346b75..4764f38 100644 --- a/server/routes/authRoutes.ts +++ b/server/routes/authRoutes.ts @@ -1,9 +1,10 @@ import express from 'express'; - +import { protect } from '../middleware/authMiddleware'; import { authSession } from '../controllers/authController'; const router = express.Router(); +router.use(protect); /* Require Auth for ALL routes below */ router.get('/validate-session', authSession); export default router; diff --git a/server/routes/forumRoutes.ts b/server/routes/forumRoutes.ts index 7638e3a..a4e0a94 100644 --- a/server/routes/forumRoutes.ts +++ b/server/routes/forumRoutes.ts @@ -1,6 +1,5 @@ import express from 'express'; import { protect } from '../middleware/authMiddleware'; - import { addForum, deleteForum, @@ -8,7 +7,6 @@ import { getForumById, updateForum, } from '../controllers/forumController'; - import { createThread, deleteThread, @@ -17,7 +15,6 @@ import { updateThread, getAllThreads, } from '../controllers/threadController'; - import { listPostsByThreadId, createPost, @@ -27,28 +24,30 @@ import { const router = express.Router(); -router.get('/threads', protect, getAllThreads); -router.get('/threads/:threadId', protect, getThreadById); +router.use(protect); /* Require Auth for ALL routes below */ + +router.get('/threads', getAllThreads); +router.get('/threads/:threadId', getThreadById); //Forum Routes -router.post('/', protect, addForum); //TODO Protect with admin auth -router.get('/', protect, getAllForums); -router.get('/:forumId', protect, getForumById); -router.put('/:forumId', protect, updateForum); //TODO Protect with admin auth -router.delete('/:forumId', protect, deleteForum); //TODO Protect with admin auth +router.post('/', addForum); //TODO Protect with admin auth +router.get('/', getAllForums); +router.get('/:forumId', getForumById); +router.put('/:forumId', updateForum); //TODO Protect with admin auth +router.delete('/:forumId', deleteForum); //TODO Protect with admin auth //Thread Routes -router.post('/:forumId/threads', protect, createThread); -router.get('/:forumId/threads', protect, listThreadsByForumId); -router.get('/:forumId/threads/:threadId', protect, getThreadById); -router.put('/:forumId/threads/:threadId', protect, updateThread); -router.delete('/:forumId/threads/:threadId', protect, deleteThread); //TODO Protect with admin auth +router.post('/:forumId/threads', createThread); +router.get('/:forumId/threads', listThreadsByForumId); +router.get('/:forumId/threads/:threadId', getThreadById); +router.put('/:forumId/threads/:threadId', updateThread); +router.delete('/:forumId/threads/:threadId', deleteThread); //TODO Protect with admin auth //Post Routes -router.get('/:forumId/threads/:threadId/posts', protect, listPostsByThreadId); -router.post('/:forumId/threads/:threadId/posts', protect, createPost); -router.put('/:forumId/threads/:threadId/posts/:postId', protect, updatePost); -router.delete('/:forumId/threads/:threadId/posts/:postId', protect, deletePost); //TODO Protect with admin auth +router.get('/:forumId/threads/:threadId/posts', listPostsByThreadId); +router.post('/:forumId/threads/:threadId/posts', createPost); +router.put('/:forumId/threads/:threadId/posts/:postId', updatePost); +router.delete('/:forumId/threads/:threadId/posts/:postId', deletePost); //TODO Protect with admin auth export default router; diff --git a/server/routes/imageRoutes.ts b/server/routes/imageRoutes.ts index 058548d..ec85cd9 100644 --- a/server/routes/imageRoutes.ts +++ b/server/routes/imageRoutes.ts @@ -1,6 +1,6 @@ import express from 'express'; -import { uploadProfilePicture, generatePresignedUrl } from '../controllers/imageController'; import { protect } from '../middleware/authMiddleware'; +import { uploadProfilePicture, generatePresignedUrl } from '../controllers/imageController'; const router = express.Router(); @@ -8,12 +8,8 @@ import multer from 'multer'; const storage = multer.memoryStorage(); const upload = multer({ storage: storage }); -router.post( - '/profile-picture/:userID', - protect, - upload.single('profilePicture'), - uploadProfilePicture, -); +router.use(protect); /* Require Auth for ALL routes below */ +router.post('/profile-picture/:userID', upload.single('profilePicture'), uploadProfilePicture); //TODO Not currently being used router.get('/generate-url', generatePresignedUrl); diff --git a/server/routes/profileRoutes.ts b/server/routes/profileRoutes.ts index e8a1244..b2979a6 100644 --- a/server/routes/profileRoutes.ts +++ b/server/routes/profileRoutes.ts @@ -1,6 +1,5 @@ import express from 'express'; import { protect } from '../middleware/authMiddleware'; - import { createProfile, getAllProfiles, @@ -10,9 +9,11 @@ import { const router = express.Router(); -router.post('/', protect, createProfile); -router.put('/:userID', protect, updateProfile); -router.get('/:userID', protect, getProfileById); -router.get('/', protect, getAllProfiles); +router.use(protect); /* Require Auth for ALL routes below */ + +router.post('/', createProfile); +router.put('/:userID', updateProfile); +router.get('/:userID', getProfileById); +router.get('/', getAllProfiles); export default router; diff --git a/server/routes/userRoutes.ts b/server/routes/userRoutes.ts index e26c09b..6f9dd4e 100644 --- a/server/routes/userRoutes.ts +++ b/server/routes/userRoutes.ts @@ -1,19 +1,20 @@ import express from 'express'; +import { protect } from '../middleware/authMiddleware'; import { registerUser, authUser, getUserById, // deleteUserByEmail, } from '../controllers/userController'; -import { protect } from '../middleware/authMiddleware'; const router = express.Router(); router.post('/login', authUser); router.post('/register', registerUser); +router.use(protect); /* Require Auth for ALL routes below */ +router.get('/:userId', getUserById); //TODO Disabled until admin auth is created -//router.delete("/:email", protect, deleteUserByEmail); -router.get('/:userId', protect, getUserById); +//router.delete("/:email", deleteUserByEmail); export default router; diff --git a/server/types/customRequest.ts b/server/types/customRequest.ts deleted file mode 100644 index 84f28a3..0000000 --- a/server/types/customRequest.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Request } from 'express'; - -interface UserPayload { - id: string; -} - -export interface CustomRequest
> extends Request { - user?: UserPayload; - params: P; -}