Skip to content

Commit

Permalink
Merge pull request #121 from softrams/64-test
Browse files Browse the repository at this point in the history
Password Utility Test
  • Loading branch information
Whamo12 committed Jul 15, 2020
2 parents 8fe0a8e + 8021985 commit 6eddac5
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 42 deletions.
14 changes: 9 additions & 5 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ module.exports = {
clearMocks: true,

// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
coverageDirectory: 'coverage',
roots: ['<rootDir>/src'],
transform: {
'^.+\\.ts?$': 'ts-jest',
'^.+\\.ts?$': 'ts-jest'
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.ts?$',
collectCoverage: true,
collectCoverageFrom: [
"src/**/*.ts"
],
collectCoverageFrom: ['src/**/*.ts'],
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
coveragePathIgnorePatterns: [
'<rootDir>/src/interfaces',
'<rootDir>/src/classes',
'<rootDir>/src/entity',
'<rootDir>/src/enums'
]
};
2 changes: 1 addition & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ createConnection().then((_) => {
app.patch('/api/forgot-password', authController.forgotPassword);
app.patch('/api/password-reset', authController.resetPassword);
app.post('/api/refresh', jwtMiddleware.checkRefreshToken, authController.refreshSession);
app.patch('/api/user/password', userController.updatePassword);
app.patch('/api/user/password', userController.updateUserPassword);
app.post('/api/login', authController.login);
app.post('/api/upload', jwtMiddleware.checkToken, fileUploadController.uploadFile);
app.get('/api/file/:id', jwtMiddleware.checkToken, fileUploadController.getFileById);
Expand Down
14 changes: 9 additions & 5 deletions src/routes/authentication.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { User } from '../entity/User';
import { v4 as uuidv4 } from 'uuid';
import { Response } from 'express';
import jwt = require('jsonwebtoken');
// tslint:disable-next-line: no-var-requires
const passwordUtility = require('../utilities/password.utility');
import { generateHash, passwordSchema, compare } from '../utilities/password.utility';
import { passwordRequirement } from '../enums/message-enum';
// tslint:disable-next-line: no-var-requires
const emailService = require('../services/email.service');
Expand Down Expand Up @@ -36,7 +35,12 @@ const login = async (req: UserRequest, res: Response) => {
.status(400)
.json('This account has not been activated. Please check for email verification or contact an administrator.');
}
const valid = await passwordUtility.compare(password, user.password);
let valid: boolean;
try {
valid = await compare(password, user.password);
} catch (err) {
return res.status(400).json(err);
}
if (valid) {
const tokens = generateTokens(user);
return res.status(200).json(tokens);
Expand Down Expand Up @@ -84,7 +88,7 @@ const resetPassword = async (req: UserRequest, res: Response) => {
if (password !== confirmPassword) {
return res.status(400).json('Passwords do not match');
}
if (!passwordUtility.passwordSchema.validate(password)) {
if (!passwordSchema.validate(password)) {
return res.status(400).json(passwordRequirement);
}
const user = await getConnection()
Expand All @@ -95,7 +99,7 @@ const resetPassword = async (req: UserRequest, res: Response) => {
})
.getOne();
if (user) {
user.password = await passwordUtility.generateHash(password);
user.password = await generateHash(password);
user.uuid = null;
await getConnection().getRepository(User).save(user);
return res.status(200).json('Password updated successfully');
Expand Down
27 changes: 14 additions & 13 deletions src/routes/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { Response } from 'express';
import { v4 as uuidv4 } from 'uuid';
import { validate } from 'class-validator';
import { passwordRequirement } from '../enums/message-enum';
// tslint:disable-next-line: no-var-requires
const passwordUtility = require('../utilities/password.utility');
import { generateHash, passwordSchema, updatePassword } from '../utilities/password.utility';

// tslint:disable-next-line: no-var-requires
const emailService = require('../services/email.service');
/**
Expand All @@ -29,10 +29,10 @@ const create = async (req: UserRequest, res: Response) => {
if (password !== confirmPassword) {
return res.status(400).json('Passwords do not match');
}
if (!passwordUtility.passwordSchema.validate(password)) {
if (!passwordSchema.validate(password)) {
return res.status(400).json(passwordRequirement);
}
user.password = await passwordUtility.generateHash(password);
user.password = await generateHash(password);
user.active = false;
user.uuid = uuidv4();
const errors = await validate(user);
Expand All @@ -58,7 +58,7 @@ const register = async (req: UserRequest, res: Response) => {
if (password !== confirmPassword) {
return res.status(400).json('Passwords do not match');
}
if (!passwordUtility.passwordSchema.validate(password)) {
if (!passwordSchema.validate(password)) {
return res.status(400).json(passwordRequirement);
}
const user = await getConnection()
Expand All @@ -69,7 +69,7 @@ const register = async (req: UserRequest, res: Response) => {
})
.getOne();
if (user) {
user.password = await passwordUtility.generateHash(password);
user.password = await generateHash(password);
user.uuid = null;
user.active = true;
user.firstName = firstName;
Expand Down Expand Up @@ -140,23 +140,24 @@ const verify = async (req: UserRequest, res: Response) => {
* @param {Response} res
* @returns Success message
*/
const updatePassword = async (req: UserRequest, res: Response) => {
const updateUserPassword = async (req: UserRequest, res: Response) => {
const { oldPassword, newPassword, confirmNewPassword } = req.body;
if (newPassword !== confirmNewPassword) {
return res.status(400).json('Passwords do not match');
}
if (newPassword === oldPassword) {
return res.status(400).json('New password can not be the same as the old password');
}
if (!passwordUtility.passwordSchema.validate(newPassword)) {
if (!passwordSchema.validate(newPassword)) {
return res.status(400).json(passwordRequirement);
}
const user = await getConnection().getRepository(User).findOne(req.user);
if (user) {
const callback = (resStatus: number, message: any) => {
res.status(resStatus).send(message);
};
user.password = await passwordUtility.updatePassword(oldPassword, user.password, newPassword, callback);
try {
user.password = await updatePassword(user.password, oldPassword, newPassword);
} catch (err) {
return res.status(400).json(err);
}
await getConnection().getRepository(User).save(user);
return res.status(200).json('Password updated successfully');
} else {
Expand Down Expand Up @@ -241,7 +242,7 @@ const getUsersById = async (userIds: number[]) => {
module.exports = {
create,
verify,
updatePassword,
updateUserPassword,
invite,
register,
patch,
Expand Down
44 changes: 44 additions & 0 deletions src/utilities/password.utility.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { generateHash, updatePassword, compare } from './password.utility';

describe('password utility', () => {
test('generateHash to work', async () => {
const password = 'qwerty';
const hashedPassword = await generateHash(password);
expect(hashedPassword).toBeDefined();
});

test('compare hash success', async (done) => {
const oldPassword = await generateHash('qwerty');
const currentPassword = 'qwerty';
await expect(compare(currentPassword, oldPassword)).resolves.toBeTruthy();
done();
});

test('compare hash failure', async (done) => {
const oldPassword = await generateHash('qwerty');
const currentPassword = 'qwerty2';
await expect(compare(currentPassword, oldPassword)).resolves.toBeFalsy();
done();
});

test('compare hash bcrypt failure', async (done) => {
await expect(compare(null, 0)).rejects.toBe('Bcrypt comparison failure');
done();
});

test('password updated successfully', async () => {
const currentPassword = 'qwerty';
const oldPassword = await generateHash(currentPassword);
const newPassword = 'newQwerty';
const result = await updatePassword(oldPassword, currentPassword, newPassword);
expect(result).toEqual(expect.anything());
});

test('password updated failure', async (done) => {
const currentPassword = 'qwerty2';
const oldPassword = await generateHash('1234');
const newPassword = 'newQwerty';
await expect(updatePassword(oldPassword, currentPassword, newPassword)).rejects.toBe('Incorrect previous password');
done();
});
});
33 changes: 15 additions & 18 deletions src/utilities/password.utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as bcrypt from 'bcrypt';
const passwordValidator = require('password-validator');

// Create a password schema
const passwordSchema = new passwordValidator();
export const passwordSchema = new passwordValidator();
passwordSchema
.is()
.min(12) // Minimum length 8
Expand All @@ -23,15 +23,15 @@ const saltRounds = 10;
* @param {Response} res
* @returns hashed password
*/
const generateHash = password => {
export const generateHash = (password: string): Promise<string> => {
return new Promise((resolve, reject) => {
bcrypt.genSalt(saltRounds, async (err, salt) => {
if (err) {
return Error('Bcrypt hash failed: ' + err);
reject('Bcrypt hash failed: ' + err);
} else {
bcrypt.hash(password, salt, async (hashErr, hash) => {
bcrypt.hash(password, salt, async (hashErr, hash: string) => {
if (hashErr) {
return Error('Bcrypt hash failed: ' + hashErr);
reject('Bcrypt hash failed: ' + hashErr);
} else {
resolve(hash);
}
Expand All @@ -46,13 +46,14 @@ const generateHash = password => {
* @param {Response} res
* @returns hashed password
*/
const updatePassword = (oldPassword, currentPassword, newPassword, callback) => {
export const updatePassword = (oldPassword, currentPassword, newPassword): Promise<string> => {
return new Promise(async (resolve, reject) => {
const valid = await compare(oldPassword, currentPassword);
const valid = await compare(currentPassword, oldPassword);
if (valid) {
resolve(await generateHash(newPassword));
const newPasswordHash = await generateHash(newPassword);
resolve(newPasswordHash);
} else {
callback(400, JSON.stringify('Incorrect previous password'));
reject('Incorrect previous password');
}
});
};
Expand All @@ -63,17 +64,13 @@ const updatePassword = (oldPassword, currentPassword, newPassword, callback) =>
* @param {Response} res
* @returns true/false
*/
const compare = (oldPassword, currentPassword) => {
export const compare = (currentPassword, oldPassword): Promise<boolean> => {
return new Promise((resolve, reject) => {
bcrypt.compare(oldPassword, currentPassword, (err, valid) => {
bcrypt.compare(currentPassword, oldPassword, (err, valid) => {
if (err) {
reject('Bcrypt comparison failure');
}
resolve(valid);
});
});
};

module.exports = {
generateHash,
updatePassword,
compare,
passwordSchema
};

0 comments on commit 6eddac5

Please sign in to comment.