Skip to content

Commit

Permalink
Merge pull request #164 from COS301-SE-2024/fix/backendChecks
Browse files Browse the repository at this point in the history
Fix/backend checks
  • Loading branch information
JBlixems authored Oct 18, 2024
2 parents da5f673 + e20b61c commit bb3a7c3
Show file tree
Hide file tree
Showing 13 changed files with 377 additions and 41 deletions.
16 changes: 12 additions & 4 deletions CoVAR-app/src/app/(pages)/login/loginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'
import React, { useState, useEffect } from 'react';
import { useTheme, ThemeProvider } from '@mui/material/styles';
import { Container, Box, Typography, TextField, Button, Link, CssBaseline, Card } from '@mui/material';
import { Container, Box, Typography, TextField, Button, Link, CssBaseline, Card, CircularProgress } from '@mui/material';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import GoogleIcon from "../../../assets/GoogleIcon";
import { doSignInWithEmailAndPassword, doSignInWithGoogle} from '../../../functions/firebase/auth';
Expand Down Expand Up @@ -34,6 +34,7 @@ const Login: React.FC<LoginProps> = ({ toggleForm }) => {
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [isSigningIn, setIsSigningIn] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);

useEffect(() => {
Expand Down Expand Up @@ -73,6 +74,7 @@ const Login: React.FC<LoginProps> = ({ toggleForm }) => {
};

const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
setIsLoading(true);
e.preventDefault();
if (!isSigningIn) {
setIsSigningIn(true);
Expand Down Expand Up @@ -114,15 +116,19 @@ const Login: React.FC<LoginProps> = ({ toggleForm }) => {

if (role === "unauthorised") {
router.replace('/lounge'); // Navigate to lounge if unauthorised
setIsLoading(false);
} else {
router.replace('/dashboard'); // Navigate to dashboard after successful login
router.replace('/dashboard'); // Navigate to dashboard after successful login
setIsLoading(false);
}

} else {
setIsLoading(false);
throw new Error('User not found in Firebase Auth');
}
} catch (error) {
//console.error('login in with email error',error);
setIsLoading(false);
setIsSigningIn(false);
setError('Failed to sign in. Please check your credentials.');
}
Expand All @@ -132,6 +138,7 @@ const Login: React.FC<LoginProps> = ({ toggleForm }) => {


const signInWithGoogle = async () => {
console.log("THIS IS THE LOGIN GOOGLE BUTTON");
if (!isSigningIn) {
setIsSigningIn(true);
try {
Expand Down Expand Up @@ -166,8 +173,9 @@ const Login: React.FC<LoginProps> = ({ toggleForm }) => {
document.cookie = `accessToken=${response.data.accessToken}`;
let getUserResponse;
try {
console.log("THIS IS THE LOGIN GOOGLE BUTTON");
getUserResponse = await axios.post(
'/api/getUser',
'/api/getMeoutthefuckingSidebar',
{ accessToken: localStorage.getItem('accessToken') },
{ headers: { Authorization: `Bearer ${LoginResponse.data.accessToken}` } }
);
Expand Down Expand Up @@ -325,7 +333,7 @@ const Login: React.FC<LoginProps> = ({ toggleForm }) => {
variant="contained"
sx={{ mt: '2vh', mb: '2vh', backgroundColor: theme.palette.primary.main }}
>
Log in
{isLoading ? <CircularProgress color="inherit" size={24} />: 'Log in'}
</Button>
<Button
fullWidth
Expand Down
32 changes: 20 additions & 12 deletions CoVAR-app/src/app/(pages)/login/signupForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useTheme, ThemeProvider } from '@mui/material/styles';
import { Container, Box, Typography, TextField, Button, Link, CssBaseline, Card } from '@mui/material';
import { Container, Box, Typography, TextField, Button, Link, CssBaseline, Card, CircularProgress } from '@mui/material';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import GoogleIcon from "../../../assets/GoogleIcon";
import { doCreateUserWithEmailAndPassword, doSignInWithGoogle } from '../../../functions/firebase/auth';
Expand Down Expand Up @@ -52,6 +52,7 @@ const Signup: React.FC<SignupProps> = ({ toggleForm }) => {
const theme = useTheme();
const router = useRouter();
const [error, setError] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [email, setEmail] = useState('');
const [emailError, setEmailError] = useState('');
const [showPassword, setShowPassword] = useState(false);
Expand All @@ -67,10 +68,10 @@ const Signup: React.FC<SignupProps> = ({ toggleForm }) => {
useEffect(() => {
if (error) {
const timer = setTimeout(() => {
setError('');
}, 5000);
setError('');
}, 5000);

return () => clearTimeout(timer);
return () => clearTimeout(timer);
}
}, [error]);

Expand Down Expand Up @@ -128,20 +129,22 @@ const Signup: React.FC<SignupProps> = ({ toggleForm }) => {
document.cookie = `accessToken=${response.data.accessToken}`;
let getUserResponse;
try {
console.log("unauth req");
getUserResponse = await axios.post(
'/api/getUser',
'/api/getMeoutthefuckingSidebar',
{ accessToken: localStorage.getItem('accessToken') },
{ headers: { Authorization: `Bearer ${loginResponse.data.accessToken}` } }
);
} catch (error) {
throw error; // Re-throw the error to be caught by the outer catch block
console.log("unauth error");
throw error;
}
const { role } = getUserResponse.data;
if (getUserResponse.status === 200) {
if (getUserResponse.status === 201) {
if (role === "unauthorised") {
router.replace('/lounge'); // Navigate to lounge if unauthorised
router.replace('/lounge');
} else {
router.replace('/dashboard'); // Navigate to dashboard after successful login
router.replace('/dashboard');
}
} else {
throw new Error('Failed to create user in PostgreSQL');
Expand All @@ -154,6 +157,7 @@ const Signup: React.FC<SignupProps> = ({ toggleForm }) => {

const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setIsLoading(true);
const data = new FormData(event.currentTarget);
const email = data.get('email') as string;
const password = data.get('password') as string;
Expand All @@ -173,20 +177,23 @@ const Signup: React.FC<SignupProps> = ({ toggleForm }) => {
localStorage.setItem('refreshToken', response.data.refreshToken);
document.cookie = `accessToken=${response.data.accessToken}`;
if (response.status === 201) {
router.replace('/lounge');
router.replace('/lounge');
setIsLoading(false);
} else {
setIsLoading(false);
throw new Error('Failed to create user in PostgreSQL');
}
} catch (error: any) {
if (error.code === "auth/email-already-in-use") {
setIsLoading(false);
setError('Email is already in use. Please use a different email address.');
} else {
setIsLoading(false);
setError('Error signing up. Please try again.');
}
}
};


return (
<ThemeProvider theme={theme}>
<CssBaseline />
Expand Down Expand Up @@ -354,7 +361,8 @@ const Signup: React.FC<SignupProps> = ({ toggleForm }) => {
}}
disabled={!isValidPassword || !doPasswordsMatch || !!emailError}
>
Sign Up
{isLoading ? <CircularProgress color="inherit" size={24} />: 'Sign Up'}

</Button>
<Button
fullWidth
Expand Down
4 changes: 3 additions & 1 deletion CoVAR-app/src/app/(pages)/lounge/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ const Lounge: React.FC = () => {

// Function to get the current user and check their role
const checkUserStatus = useCallback(async () => {
console.log("getting UNAUTH");
try {
const response = await axios.post(
'/api/getUser',
'/api/getMeoutthefuckingSidebar',
{ accessToken: localStorage.getItem('accessToken') },
{ headers: { Authorization: `Bearer ${localStorage.getItem('accessToken')}` } }
);
Expand All @@ -41,6 +42,7 @@ const Lounge: React.FC = () => {
console.log("Role:", role);

if (role !== 'unauthorised') {
console.log("NOT UNAUTH")
router.replace('/dashboard');
}

Expand Down
5 changes: 3 additions & 2 deletions CoVAR-app/src/app/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { iconStyles, logoStyles, logoutButtonStyles, sidebarItemStyles, sidebarS
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
import { useRouter, usePathname } from 'next/navigation';
import Link from 'next/link';
import { getUserRole } from '@/functions/requests';
import { getAnyUserRole } from '@/functions/requests';
import { doSignOut } from '../functions/firebase/auth';
import HelpDialog from './(pages)/help/helpDialog';
import { Switch } from '@mui/material';
Expand Down Expand Up @@ -48,7 +48,8 @@ const Sidebar: React.FC = () => {
try {
const accessToken = localStorage.getItem('accessToken');
if (accessToken) {
const data = await getUserRole(accessToken);
console.log("IM IN THE FUCKING SIDEBAR");
const data = await getAnyUserRole(accessToken);
setRole(data.role);
}
} catch (error:any) {
Expand Down
9 changes: 9 additions & 0 deletions CoVAR-app/src/functions/requests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,15 @@ export const getUserRole = async (accessToken: string) => {
return await handleRequest(request);
};

export const getAnyUserRole = async (accessToken: string) => {
const request = {
method: 'post',
url: '/api/getMeoutthefuckingSidebar',
data: { accessToken },
headers: { Authorization: `Bearer ${accessToken}` },
};
return await handleRequest(request);
};
export const fetchUsersByOrg = async (orgId: string, accessToken: string) => {
const request = {
method: 'post',
Expand Down
117 changes: 110 additions & 7 deletions server/lib/securityFunctions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const jwt = require('jsonwebtoken');
const pgClient = require('../lib/postgres');
const fs = require('fs');

const { isVA , isClient ,isAdmin,isUnauthorised} = require('../lib/serverHelperFunctions');
const privateKey = fs.readFileSync('private.pem', 'utf8');
const publicKey = fs.readFileSync('public.pem', 'utf8');
const refreshPrivateKey = fs.readFileSync('refreshPrivate.pem', 'utf8');
Expand All @@ -18,22 +19,122 @@ function verifyToken(token) {
return jwt.verify(token, publicKey, { algorithms: ['RS256'] });
}

function authenticateToken(req, res, next) {
async function authenticateAllToken(req, res, next) {
const authHeader = req.headers['authorization'];
console.log(authHeader);
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);

if (token == null) return res.sendStatus(401); // No token, unauthorized

jwt.verify(token, publicKey, { algorithms: ['RS256'] }, (err, user) => {
jwt.verify(token, publicKey, { algorithms: ['RS256'] }, async (err, user) => {
if (err) {
console.error('Token verification error:', err);
console.log('Token:', token);
return res.sendStatus(403);
return res.sendStatus(403); // Token invalid, forbidden
}

req.user = user; // Store the user info in the request
const userId = req.user.user_id;

try {
// Await all the role checks
const VAResult = await isVA(pgClient, userId);
const clientResult = await isClient(pgClient, userId);
const adminResult = await isAdmin(pgClient, userId);
const UnauthResult = await isUnauthorised(pgClient, userId);
console.log("UNAUTH RESULT ",UnauthResult.isUnauthorised);
console.log("VA Result:", VAResult.isVA);
console.log("Client Result:", clientResult.isClient);
console.log("Admin Result:", adminResult.isAdmin);
// Check if the user is a VA, client, or admin
if (VAResult.isVA || clientResult.isClient || adminResult.isAdmin || UnauthResult.isUnauthorised) {
// If any of the checks pass, continue to the next middleware or route
return next();
} else {
// If none of the checks pass, send a 403 Forbidden response
return res.status(403).send('Not authorized');
}
} catch (error) {
console.error('Error during role checks:', error);
return res.status(500).send('Server Error'); // Handle any errors from the role checks
}
req.user = user;
next();
});
}
async function authenticateWhiteList(req, res, next){
const authHeader = req.headers['authorization'];
console.log(authHeader);
const token = authHeader && authHeader.split(' ')[1];

if (token == null) return res.sendStatus(401); // No token, unauthorized

jwt.verify(token, publicKey, { algorithms: ['RS256'] }, async (err, user) => {
if (err) {
console.error('Token verification error:', err);
console.log('Token:', token);
return res.sendStatus(403); // Token invalid, forbidden
}

req.user = user; // Store the user info in the request
const userId = req.user.user_id;

try {
// Await all the role checks
const UnauthResult = await isUnauthorised(pgClient, userId);
// Check if the user is a VA, client, or admin
console.log("UNAUTH RESULT ",UnauthResult.isUnauthorised);
if (UnauthResult.isUnauthorised ) {
// If any of the checks pass, continue to the next middleware or route
return next();
} else {
// If none of the checks pass, send a 403 Forbidden response
return res.status(403).send('Not authorized');
}
} catch (error) {
console.error('Error during role checks:', error);
return res.status(500).send('Server Error'); // Handle any errors from the role checks
}
});
}
async function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
console.log(authHeader);
const token = authHeader && authHeader.split(' ')[1];

if (token == null) return res.sendStatus(401); // No token, unauthorized

jwt.verify(token, publicKey, { algorithms: ['RS256'] }, async (err, user) => {
if (err) {
console.error('Token verification error:', err);
console.log('Token:', token);
return res.sendStatus(403); // Token invalid, forbidden
}

req.user = user; // Store the user info in the request
const userId = req.user.user_id;

try {
// Await all the role checks
const VAResult = await isVA(pgClient, userId);
const clientResult = await isClient(pgClient, userId);
const adminResult = await isAdmin(pgClient, userId);
console.log("VA Result:", VAResult.isVA);
console.log("Client Result:", clientResult.isClient);
console.log("Admin Result:", adminResult.isAdmin);
// Check if the user is a VA, client, or admin
if (VAResult.isVA || clientResult.isClient || adminResult.isAdmin) {
// If any of the checks pass, continue to the next middleware or route
return next();
} else {
// If none of the checks pass, send a 403 Forbidden response
return res.status(403).send('Not authorized');
}
} catch (error) {
console.error('Error during role checks:', error);
return res.status(500).send('Server Error'); // Handle any errors from the role checks
}
});
}


// Firebase sdk
const admin = require('firebase-admin');
Expand All @@ -57,6 +158,8 @@ async function verifyIdToken(req,res,next) {
}

module.exports = {
authenticateAllToken,
authenticateWhiteList,
generateToken,
generateRefreshToken,
verifyToken,
Expand Down
Loading

0 comments on commit bb3a7c3

Please sign in to comment.