Skip to content

Commit 8c36e45

Browse files
committed
Added unit tests for Audit Log: 1 test case for the frontend and 5 test cases for API calls.
1 parent d4b36e8 commit 8c36e45

File tree

4 files changed

+300
-138
lines changed

4 files changed

+300
-138
lines changed

api/main_endpoints/routes/Auth.js

Lines changed: 120 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use strict';
2-
const bcrypt = require('cryptjs');
2+
const bcrypt = require('bcryptjs');
33
const express = require('express');
44
const crypto = require('crypto');
55
const router = express.Router();
@@ -14,24 +14,21 @@ const { verifyCaptcha } = require('../util/captcha');
1414
const {
1515
checkIfTokenSent,
1616
checkIfTokenValid,
17-
decodeToken,
17+
decodeToken
1818
} = require('../util/token-functions');
1919
const jwt = require('jsonwebtoken');
20-
const { OK, BAD_REQUEST, FORBIDDEN, UNAUTHORIZED, NOT_FOUND, CONFLICT } =
21-
require('../../util/constants').STATUS_CODES;
22-
const membershipState = require('../../util/constants').MEMBERSHIP_STATE;
23-
const PASSWORD_RESET_EXPIRATION =
24-
require('../../util/constants').PASSWORD_RESET_EXPIRATION;
25-
const {
26-
sendVerificationEmail,
27-
sendPasswordReset,
28-
} = require('../util/emailHelpers');
2920
const {
30-
userWithEmailExists,
31-
checkIfPageCountResets,
32-
findPasswordReset,
33-
} = require('../util/userHelpers');
34-
21+
OK,
22+
BAD_REQUEST,
23+
FORBIDDEN,
24+
UNAUTHORIZED,
25+
NOT_FOUND,
26+
CONFLICT
27+
} = require('../../util/constants').STATUS_CODES;
28+
const membershipState = require('../../util/constants').MEMBERSHIP_STATE;
29+
const PASSWORD_RESET_EXPIRATION = require('../../util/constants').PASSWORD_RESET_EXPIRATION;
30+
const { sendVerificationEmail, sendPasswordReset } = require('../util/emailHelpers');
31+
const { userWithEmailExists, checkIfPageCountResets, findPasswordReset } = require('../util/userHelpers');
3532

3633
const AuditLogActions = require('../util/auditLogActions.js');
3734
const AuditLog = require('../models/AuditLog.js');
@@ -41,13 +38,13 @@ router.post('/register', async (req, res) => {
4138
const registrationStatus = await registerUser(req.body);
4239
if (registrationStatus.userSaved) {
4340
const name = req.body.firstName + ' ' + req.body.lastName;
44-
const user = await User.findOne({ email: req.body.email });
41+
const user = await User.findOne({email: req.body.email});
4542

4643
if (user) {
4744
AuditLog.create({
4845
userId: user._id,
4946
action: AuditLogActions.SIGN_UP,
50-
details: { email: req.body.email },
47+
details: {email: req.body.email}
5148
}).catch(logger.error);
5249
}
5350

@@ -56,7 +53,7 @@ router.post('/register', async (req, res) => {
5653
}
5754
if (registrationStatus.status === 'BAD_REQUEST') {
5855
return res.status(BAD_REQUEST).send({
59-
message: registrationStatus.message,
56+
message: registrationStatus.message
6057
});
6158
}
6259
return res.status(CONFLICT).send({ message: registrationStatus.message });
@@ -72,7 +69,7 @@ router.post('/resendVerificationEmail', async (req, res) => {
7269
if (!maybeUser) {
7370
return res.sendStatus(NOT_FOUND);
7471
}
75-
let name = maybeUser.firstName + ' ' + maybeUser.lastName;
72+
let name = maybeUser.firstName + ' ' + maybeUser.lastName;
7673
sendVerificationEmail(name, req.body.email);
7774
res.sendStatus(OK);
7875
});
@@ -83,15 +80,15 @@ router.post('/sendPasswordReset', async (req, res) => {
8380

8481
if (invalidEmail) {
8582
return res.status(BAD_REQUEST).send({
86-
message: 'Invalid email.',
83+
message: 'Invalid email.'
8784
});
8885
}
8986

9087
if (process.env.NODE_ENV === 'production') {
9188
const captchaValid = await verifyCaptcha(req.body.captchaToken);
9289
if (!captchaValid.success) {
9390
return res.status(BAD_REQUEST).send({
94-
message: 'Captcha verification failed.',
91+
message: 'Captcha verification failed.'
9592
});
9693
}
9794
}
@@ -104,22 +101,20 @@ router.post('/sendPasswordReset', async (req, res) => {
104101
return res.sendStatus(OK);
105102
}
106103
if (
107-
[membershipState.PENDING, membershipState.BANNED].includes(
108-
result.accessLevel
109-
)
104+
[
105+
membershipState.PENDING,
106+
membershipState.BANNED,
107+
].includes(result.accessLevel)
110108
) {
111109
return res.status(UNAUTHORIZED).send({
112-
message: 'Cannot reset password, account is in a bad state!',
110+
message: 'Cannot reset password, account is in a bad state!'
113111
});
114112
}
115113

116114
const buffer = crypto.randomBytes(12);
117115
let id = buffer.toString('base64');
118116

119-
const resetToken = id
120-
.replace(/\+/g, '-')
121-
.replace(/\//g, '_')
122-
.replace(/=+$/, '');
117+
const resetToken = id.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
123118
try {
124119
const passwordReset = new PasswordReset({
125120
resetToken,
@@ -134,7 +129,6 @@ router.post('/sendPasswordReset', async (req, res) => {
134129
});
135130
});
136131

137-
138132
// User Login
139133
router.post('/login', function(req, res) {
140134
if (!req.body.email || !req.body.password) {
@@ -143,7 +137,7 @@ router.post('/login', function(req, res) {
143137

144138
User.findOne(
145139
{
146-
email: req.body.email.toLowerCase(),
140+
email: req.body.email.toLowerCase()
147141
},
148142
function(error, user) {
149143
if (error) {
@@ -152,75 +146,83 @@ router.post('/login', function(req, res) {
152146
}
153147

154148
if (!user) {
155-
return res.status(UNAUTHORIZED).send({
156-
message: 'Username or password does not match our records.',
149+
res
150+
.status(UNAUTHORIZED)
151+
.send({
152+
message: 'Username or password does not match our records.'
153+
});
154+
} else {
155+
// Check if password matches database
156+
user.comparePassword(req.body.password, function(error, isMatch) {
157+
if (isMatch && !error) {
158+
if (user.accessLevel === membershipState.BANNED) {
159+
return res
160+
.status(UNAUTHORIZED)
161+
.send({
162+
message: 'The account with email ' +
163+
req.body.email +
164+
' is banned',
165+
});
166+
}
167+
168+
// Check if the user's email has been verified
169+
if (!user.emailVerified) {
170+
return res
171+
.status(UNAUTHORIZED)
172+
.send({ message: `The email ${req.body.email} has not been verified` });
173+
}
174+
175+
// If the username and password matches the database, assign and
176+
// return a jwt token
177+
const jwtOptions = {
178+
expiresIn: '2h'
179+
};
180+
181+
// check here to see if we should reset the pagecount. If so, do it
182+
if (checkIfPageCountResets(user.lastLogin)) {
183+
user.pagesPrinted = 0;
184+
}
185+
186+
// Include fields from the User model that should
187+
// be passed to the JSON Web Token (JWT)
188+
const userToBeSigned = {
189+
firstName: user.firstName,
190+
lastName: user.lastName,
191+
email: user.email,
192+
accessLevel: user.accessLevel,
193+
pagesPrinted: user.pagesPrinted,
194+
_id: user._id
195+
};
196+
user
197+
.save()
198+
.then(() => {
199+
const token = jwt.sign(
200+
userToBeSigned, config.secretKey, jwtOptions
201+
);
202+
// Create audit log on successful sign-in
203+
AuditLog.create({
204+
userId: user._id,
205+
action: AuditLogActions.LOG_IN,
206+
details: { email: user.email }
207+
}).catch(logger.error);
208+
209+
res.json({ token: 'JWT ' + token });
210+
})
211+
.catch((error) => {
212+
logger.error('unable to login user', error);
213+
res.sendStatus(SERVER_ERROR);
214+
});
215+
} else {
216+
res.status(UNAUTHORIZED).send({
217+
message: 'Username or password does not match our records.'
218+
});
219+
}
157220
});
158221
}
159-
160-
user.comparePassword(req.body.password, function(error, isMatch) {
161-
if (error || !isMatch) {
162-
return res.status(UNAUTHORIZED).send({
163-
message: 'Username or password does not match our records.',
164-
});
165-
}
166-
if (user.accessLevel === membershipState.BANNED) {
167-
return res.status(UNAUTHORIZED).send({
168-
message: 'The account with email ' + req.body.email + ' is banned',
169-
});
170-
}
171-
172-
if (!user.emailVerified) {
173-
return res.status(UNAUTHORIZED).send({
174-
message: `The email ${req.body.email} has not been verified`,
175-
});
176-
}
177-
178-
const jwtOptions = {
179-
expiresIn: '2h',
180-
};
181-
182-
if (checkIfPageCountResets(user.lastLogin)) {
183-
user.pagesPrinted = 0;
184-
}
185-
186-
user.lastLogin = new Date();
187-
188-
const userToBeSigned = {
189-
firstName: user.firstName,
190-
lastName: user.lastName,
191-
email: user.email,
192-
accessLevel: user.accessLevel,
193-
pagesPrinted: user.pagesPrinted,
194-
_id: user._id,
195-
};
196-
197-
user
198-
.save()
199-
.then(() => {
200-
const token = jwt.sign(
201-
userToBeSigned,
202-
config.secretKey,
203-
jwtOptions
204-
);
205-
AuditLog.create({
206-
userId: user._id,
207-
action: AuditLogActions.LOG_IN,
208-
details: { email: user.email },
209-
}).catch(logger.error);
210-
211-
res.json({ token: 'JWT' + token });
212-
})
213-
.catch((error) => {
214-
logger.error('unable to login user', error);
215-
res.sendStatus(SERVER_ERROR);
216-
});
217-
});
218222
}
219223
);
220224
});
221225

222-
223-
224226
// Verifies the users session if they have an active jwtToken.
225227
// Used on the inital load of root '/'
226228
// Returns the name and accesslevel of the user w/ the given access token
@@ -249,6 +251,7 @@ router.post('/generateHashedId', async (req, res) => {
249251
// bcrypts library
250252
bcrypt.genSalt(10, function(error, salt) {
251253
if (error) {
254+
// reject('Bcrypt failed')
252255
res.sendStatus(BAD_REQUEST);
253256
}
254257

@@ -272,39 +275,35 @@ router.post('/validateVerificationEmail', async (req, res) => {
272275
res.sendStatus(NOT_FOUND);
273276
}
274277

275-
bcrypt.compare(
276-
String(result._id),
277-
req.body.hashedId,
278-
async function(error, isMatch) {
279-
if (error) {
280-
res.sendStatus(BAD_REQUEST);
281-
}
282-
if (isMatch) {
283-
result.emailVerified = true;
284-
result.accessLevel = membershipState.NON_MEMBER;
285-
await result
286-
.save()
287-
.then((_) => {
288-
res.sendStatus(OK);
289-
})
290-
.catch((err) => {
291-
res.sendStatus(BAD_REQUEST);
292-
});
293-
} else {
294-
res.sendStatus(BAD_REQUEST);
295-
}
278+
bcrypt.compare(String(result._id), req.body.hashedId, async function(
279+
error,
280+
isMatch) {
281+
if (error) {
282+
res.sendStatus(BAD_REQUEST);
296283
}
297-
);
284+
if (isMatch) {
285+
result.emailVerified = true;
286+
result.accessLevel = membershipState.NON_MEMBER;
287+
await result
288+
.save()
289+
.then(_ => {
290+
res.sendStatus(OK);
291+
})
292+
.catch(err => {
293+
res.sendStatus(BAD_REQUEST);
294+
});
295+
} else {
296+
res.sendStatus(BAD_REQUEST);
297+
}
298+
});
298299
});
299300
});
300301

301302
router.post('/validatePasswordReset', async (req, res) => {
302303
try {
303304
const passwordReset = await findPasswordReset(req.body.resetToken);
304305
if (!passwordReset) {
305-
return res
306-
.status(NOT_FOUND)
307-
.send({ message: 'Invalid or expired reset tokennn.' });
306+
return res.status(NOT_FOUND).send({ message: 'Invalid or expired reset token.' });
308307
}
309308
res.sendStatus(OK);
310309
} catch (error) {
@@ -317,7 +316,7 @@ router.post('/resetPassword', async (req, res) => {
317316
const testPassword = testPasswordStrength(req.body.password);
318317
if (!testPassword.success) {
319318
return res.status(BAD_REQUEST).send({
320-
message: 'Password does not meet requirements.',
319+
message: 'Password does not meet requirements.'
321320
});
322321
}
323322

@@ -354,4 +353,3 @@ router.post('/resetPassword', async (req, res) => {
354353
});
355354

356355
module.exports = router;
357-

src/Pages/AuditLog/AuditLog.js

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { getAllLogs } from '../../APIFunctions/AuditLog';
33
import Pagination from './Components/Pagination';
44
import { useSCE } from '../../Components/context/SceContext';
@@ -37,21 +37,6 @@ export default function AuditLogPage() {
3737
'DELETE_CARD',
3838
];
3939

40-
const toggleActivityFilter = activity => {
41-
setActivityFilters(prev => (prev.includes(activity) ? prev.filter(a => a !== activity) : [...prev, activity]));
42-
};
43-
44-
const activityTypes = [
45-
'SIGN_UP',
46-
'LOG_IN',
47-
'UPDATE_USER',
48-
'PRINT_PAGE',
49-
'VERIFY_EMAIL',
50-
'EMAIL_SENT',
51-
'CHANGE_PW',
52-
'RESET_PW',
53-
];
54-
5540
const getAuditLogsFromDB = async () => {
5641
try {
5742
setLoading(true);

0 commit comments

Comments
 (0)