Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CHE-173] Refactor Auth Middleware #148

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions server/controllers/applicationsController.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Request, Response } from 'express';
import { CustomRequest } from '../types/customRequest';
import { pool } from '../config/sql-db';

interface StatusCount {
Expand Down Expand Up @@ -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 = `
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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' });
Expand Down
40 changes: 6 additions & 34 deletions server/controllers/authController.ts
Original file line number Diff line number Diff line change
@@ -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 };
7 changes: 3 additions & 4 deletions server/controllers/postController.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down
9 changes: 4 additions & 5 deletions server/controllers/threadController.ts
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down
62 changes: 30 additions & 32 deletions server/middleware/authMiddleware.ts
Original file line number Diff line number Diff line change
@@ -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 };
4 changes: 2 additions & 2 deletions server/routes/alumniRoutes.ts
Original file line number Diff line number Diff line change
@@ -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;
19 changes: 10 additions & 9 deletions server/routes/applicationsRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import express from 'express';
import { protect } from '../middleware/authMiddleware';
import {
createApplication,
getAllApplications,
Expand All @@ -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;
3 changes: 2 additions & 1 deletion server/routes/authRoutes.ts
Original file line number Diff line number Diff line change
@@ -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;
37 changes: 18 additions & 19 deletions server/routes/forumRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import express from 'express';
import { protect } from '../middleware/authMiddleware';

import {
addForum,
deleteForum,
getAllForums,
getForumById,
updateForum,
} from '../controllers/forumController';

import {
createThread,
deleteThread,
Expand All @@ -17,7 +15,6 @@ import {
updateThread,
getAllThreads,
} from '../controllers/threadController';

import {
listPostsByThreadId,
createPost,
Expand All @@ -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;
10 changes: 3 additions & 7 deletions server/routes/imageRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
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();

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);
Expand Down
11 changes: 6 additions & 5 deletions server/routes/profileRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import express from 'express';
import { protect } from '../middleware/authMiddleware';

import {
createProfile,
getAllProfiles,
Expand All @@ -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;
Loading
Loading