diff --git a/backend/middleware/user.middleware.js b/backend/middleware/user.middleware.js index 6e675313..4d419ab9 100644 --- a/backend/middleware/user.middleware.js +++ b/backend/middleware/user.middleware.js @@ -15,7 +15,7 @@ function isAdminByEmail(req, res, next) { return res.sendStatus(400); } else { const role = user.accessLevel; - if (req.get('origin').includes('3001') || role === 'admin' || user.managedProjects.length > 0) { + if (role === 'admin' || user.managedProjects.length > 0) { next(); } else { next(res.sendStatus(401)); diff --git a/backend/routers/projects.router.js b/backend/routers/projects.router.js index f0762b83..cfa217b0 100644 --- a/backend/routers/projects.router.js +++ b/backend/routers/projects.router.js @@ -2,17 +2,18 @@ const express = require("express"); const router = express.Router(); const { ProjectController } = require('../controllers'); +const { AuthUtil } = require("../middleware"); // The base is /api/projects router.get('/', ProjectController.project_list); -router.post('/', ProjectController.create); +router.post('/', AuthUtil.verifyCookie, ProjectController.create); router.get('/:ProjectId', ProjectController.project_by_id); -router.put('/:ProjectId', ProjectController.update); +router.put('/:ProjectId', AuthUtil.verifyCookie, ProjectController.update); -router.patch('/:ProjectId', ProjectController.update); +router.patch('/:ProjectId', AuthUtil.verifyCookie, ProjectController.update); module.exports = router; diff --git a/backend/routers/projects.router.test.js b/backend/routers/projects.router.test.js index b4abbc6e..e7ebf712 100644 --- a/backend/routers/projects.router.test.js +++ b/backend/routers/projects.router.test.js @@ -1,18 +1,58 @@ const supertest = require('supertest'); const app = require('../app'); const request = supertest(app); +const jwt = require('jsonwebtoken'); +const { CONFIG_AUTH } = require('../config'); + const { setupDB } = require('../setup-test'); setupDB('api-projects'); -const { Project } = require('../models'); +const { Project, User } = require('../models'); const CONFIG = require('../config/auth.config'); const headers = {}; headers['x-customrequired-header'] = CONFIG.CUSTOM_REQUEST_HEADER; headers.Accept = 'application/json'; +headers.authorization = 'Bearer sometoken'; + +let token; + describe('CREATE', () => { + beforeAll( async () => { + const submittedData = { + name: { + firstName: 'test', + lastName: 'user', + }, + email: 'newtest@test.com', + }; + const user = await User.create(submittedData); + const auth_origin = 'TEST'; + token = jwt.sign( + { id: user.id, role: user.accessLevel, auth_origin }, + CONFIG_AUTH.SECRET, + { + expiresIn: `${CONFIG_AUTH.TOKEN_EXPIRATION_SEC}s`, + }, + ); + }) + test('Create a Project with POST to /api/projects/ without token', async (done) => { + // Test Data + const submittedData = { + name: 'projectName', + }; + + // Submit a project + const res = await request + .post('/api/projects/') + .set(headers) + .send(submittedData); + expect(res.status).toBe(401); + done(); + }); + test('Create a Project with POST to /api/projects/', async (done) => { // Test Data const submittedData = { @@ -23,6 +63,7 @@ describe('CREATE', () => { const res = await request .post('/api/projects/') .set(headers) + .set('Cookie', [`token=${token}`] ) .send(submittedData); expect(res.status).toBe(201); done(); @@ -40,6 +81,7 @@ describe('READ', () => { const res = await request .post('/api/projects/') .set(headers) + .set('Cookie', [`token=${token}`]) .send(submittedData); expect(res.status).toBe(201); @@ -54,7 +96,25 @@ describe('READ', () => { }); describe('UPDATE', () => { - test('Update a project with PATCH to /api/projects/:id', async (done) => { + beforeAll(async () => { + const submittedData = { + name: { + firstName: 'test', + lastName: 'user', + }, + email: 'newtest@test.com', + }; + const user = await User.create(submittedData); + const auth_origin = 'TEST'; + token = jwt.sign( + { id: user.id, role: user.accessLevel, auth_origin }, + CONFIG_AUTH.SECRET, + { + expiresIn: `${CONFIG_AUTH.TOKEN_EXPIRATION_SEC}s`, + }, + ); + }) + test('Update a project with PATCH to /api/projects/:id without a token', async (done) => { // Test Data const submittedData = { name: 'projectName', @@ -64,6 +124,7 @@ describe('UPDATE', () => { const res = await request .post('/api/projects/') .set(headers) + .set('Cookie', [`token=${token}`]) .send(submittedData); expect(res.status).toBe(201); @@ -76,10 +137,44 @@ describe('UPDATE', () => { .put(`/api/projects/${res.body._id}`) .set(headers) .send(updatedDataPayload); - expect(res2.status).toBe(200); + expect(res2.status).toBe(401); + + // Get project + const res3 = await request.get(`/api/projects/${res.body._id}`) + .set(headers); + expect(res3.status).toBe(200); + done(); + }); + test('Update a project with PATCH to /api/projects/:id with a token', async (done) => { + // Test Data + const submittedData = { + name: 'projectName', + }; + + // Submit a project + const res = await request + .post('/api/projects/') + .set(headers) + .set('Cookie', [`token=${token}`]) + .send(submittedData); + expect(res.status).toBe(201); + + const updatedDataPayload = { + name: 'updatedProjectName', + }; + + // Update project + const res2 = await request + .put(`/api/projects/${res.body._id}`) + .set(headers) + .set('Cookie', [`token=${token}`]) + .send(updatedDataPayload); + expect(res2.status).toBe(200) // Get project - const res3 = await request.get(`/api/projects/${res.body._id}`).set(headers); + const res3 = await request.get(`/api/projects/${res.body._id}`) + .set(headers) + .set('Cookie', [`token=${token}`]) expect(res3.status).toBe(200); const APIData = res3.body; @@ -89,7 +184,45 @@ describe('UPDATE', () => { }); describe('DELETE', () => { - test('Delete a project with POST to /api/projects/:id', async (done) => { + beforeAll(async () => { + const submittedData = { + name: { + firstName: 'test', + lastName: 'user', + }, + email: 'newtest@test.com', + }; + const user = await User.create(submittedData); + const auth_origin = 'TEST'; + token = jwt.sign( + { id: user.id, role: user.accessLevel, auth_origin }, + CONFIG_AUTH.SECRET, + { + expiresIn: `${CONFIG_AUTH.TOKEN_EXPIRATION_SEC}s`, + }, + ); + }) + test('Delete a project with POST to /api/projects/:id without a token', async (done) => { + // Test Data + const submittedData = { + name: 'projectName', + }; + + // Submit a project + const res = await request + .post('/api/projects/') + .set(headers) + .set('Cookie', [`token=${token}`]) + .send(submittedData); + expect(res.status).toBe(201); + + // Delete project + const res2 = await request.patch(`/api/projects/${res.body._id}`) + .set(headers); + expect(res2.status).toBe(401); + done(); +}); + test('Delete a project with POST to /api/projects/:id with a token', async (done) => { // Test Data const submittedData = { name: 'projectName', @@ -99,11 +232,14 @@ describe('DELETE', () => { const res = await request .post('/api/projects/') .set(headers) + .set('Cookie', [`token=${token}`]) .send(submittedData); expect(res.status).toBe(201); // Delete project - const res2 = await request.patch(`/api/projects/${res.body._id}`).set(headers); + const res2 = await request.patch(`/api/projects/${res.body._id}`) + .set(headers) + .set('Cookie', [`token=${token}`]) expect(res2.status).toBe(200); done(); }); diff --git a/backend/routers/recurringEvents.router.js b/backend/routers/recurringEvents.router.js index 66e5ab7d..23481745 100644 --- a/backend/routers/recurringEvents.router.js +++ b/backend/routers/recurringEvents.router.js @@ -4,6 +4,7 @@ const cors = require('cors'); const { RecurringEvent } = require('../models/recurringEvent.model'); const { RecurringEventController } = require('../controllers/'); +const { AuthUtil } = require('../middleware'); // GET /api/recurringevents/ router.get('/', cors(), (req, res) => { @@ -34,10 +35,10 @@ router.get('/:id', (req, res) => { }); }); -router.post('/', RecurringEventController.create); +router.post('/', AuthUtil.verifyCookie, RecurringEventController.create); -router.patch('/:RecurringEventId', RecurringEventController.update); +router.patch('/:RecurringEventId', AuthUtil.verifyCookie, RecurringEventController.update); -router.delete('/:RecurringEventId', RecurringEventController.destroy); +router.delete('/:RecurringEventId', AuthUtil.verifyCookie, RecurringEventController.destroy); module.exports = router; diff --git a/client/src/App.js b/client/src/App.js index d610b188..82fdf5ba 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -26,8 +26,6 @@ import HealthCheck from './pages/HealthCheck'; import SecretPassword from './pages/SecretPassword'; import UserWelcome from './pages/UserWelcome'; -import ProjectForm from './components/ProjectForm'; - import { ThemeProvider } from '@mui/material'; import theme from './theme'; diff --git a/client/src/components/ProjectForm.js b/client/src/components/ProjectForm.js index 2837f206..309f1c10 100644 --- a/client/src/components/ProjectForm.js +++ b/client/src/components/ProjectForm.js @@ -5,7 +5,6 @@ import { Redirect } from 'react-router-dom'; import { Typography, Box, - Divider, Button, Grid, Radio, diff --git a/client/src/components/manageProjects/editProject.js b/client/src/components/manageProjects/editProject.js index 8be19e9a..399bc3ab 100644 --- a/client/src/components/manageProjects/editProject.js +++ b/client/src/components/manageProjects/editProject.js @@ -9,7 +9,7 @@ import TitledBox from '../parts/boxes/TitledBox'; import { ReactComponent as EditIcon } from '../../svg/Icon_Edit.svg'; import { ReactComponent as PlusIcon } from '../../svg/PlusIcon.svg'; -import { Typography, Box, Divider } from '@mui/material'; +import { Typography, Box } from '@mui/material'; // Need to hold user state to check which type of user they are and conditionally render editing fields in this component // for user level block access to all except for the ones checked diff --git a/client/src/components/manageProjects/utilities/validateEventForm.js b/client/src/components/manageProjects/utilities/validateEventForm.js index dbee835f..6128e1b0 100644 --- a/client/src/components/manageProjects/utilities/validateEventForm.js +++ b/client/src/components/manageProjects/utilities/validateEventForm.js @@ -1,6 +1,5 @@ import validator from 'validator'; import { isWordInArrayInString } from './../../../utils/stringUtils.js'; -import { el } from 'date-fns/locale'; const validateEventForm = (vals, projectToEdit) => { let newErrors = {}; diff --git a/client/src/pages/ProjectList.js b/client/src/pages/ProjectList.js index 3c408e06..79e731f0 100644 --- a/client/src/pages/ProjectList.js +++ b/client/src/pages/ProjectList.js @@ -8,7 +8,6 @@ import { Box, CircularProgress, Typography, - Divider, Button, } from '@mui/material'; import { Link } from 'react-router-dom';