Skip to content

Commit

Permalink
feat(dependencies): upgrade all and switch tonew Joi ✨
Browse files Browse the repository at this point in the history
  • Loading branch information
PierreBrisorgueil committed Jun 22, 2020
1 parent 1950bbd commit ef5a50f
Show file tree
Hide file tree
Showing 25 changed files with 6,825 additions and 6,509 deletions.
3 changes: 3 additions & 0 deletions config/defaults/development.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ module.exports = {
},
// zxcvbn is used to manage password security
zxcvbn: {
forbiddenPasswords: ['12345678', 'azertyui', 'qwertyui', 'azertyuiop', 'qwertyuiop'],
minSize: 8,
maxSize: 126,
minimumScore: 3,
},
// jwt is for token authentification
Expand Down
2 changes: 0 additions & 2 deletions lib/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const startSequelize = () => new Promise(((resolve, reject) => {
}
}));


// Establish a MongoDB connection, instantiating all models
const startMongoose = async () => {
try {
Expand All @@ -55,7 +54,6 @@ const startExpress = async () => {
}
};


/**
* Bootstrap the required services
* @return {Object} db, orm, and app instances
Expand Down
1 change: 0 additions & 1 deletion lib/helpers/errors.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/**
* Module dependencies
*/
Expand Down
8 changes: 8 additions & 0 deletions lib/helpers/files.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
/**
* Module dependencies
*/
const fs = require('fs');

/**
* @desc readFile from path
* @param {String} file path
* @return {String} file
*/
exports.readFile = async (path) => new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) {
Expand Down
43 changes: 43 additions & 0 deletions lib/helpers/joi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Module dependencies
*/
const zxcvbn = require('zxcvbn');
const path = require('path');

const config = require(path.resolve('./config'));

/**
* @desc Joi extension for zxcvbn
*/
exports.joiZxcvbn = (joi) => ({
type: 'zxcvbn',
base: joi.string(),
messages: {
'password.common': 'password is too common',
'password.strength': 'password must have a strength of at least {{#minScore}}',
},
rules: {
strength: {
method(minScore) {
// this.addRule throws unknown function error
return this.$_addRule({ name: 'strength', args: { minScore } });
},
args: [
{
name: 'minScore',
ref: true,
assert: joi.number().required(),
message: 'must be a number',
},
],
validate(value, helpers, args) {
if (config.zxcvbn.forbiddenPasswords.includes(value)) {
return helpers.error('password.common');
} if (zxcvbn(value).score < args.minScore) {
return helpers.error('password.strength', { minScore: args.minScore });
}
return value;
},
},
},
});
1 change: 0 additions & 1 deletion lib/helpers/mails.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/**
* Module dependencies
*/
Expand Down
8 changes: 4 additions & 4 deletions lib/middlewares/model.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@

/**
* Module dependencies
*/
const _ = require('lodash');
const Joi = require('joi');
const path = require('path');

const config = require(path.resolve('./config'));
Expand All @@ -12,7 +10,7 @@ const responses = require(path.resolve('./lib/helpers/responses'));
/**
* get Joi result
*/
module.exports.getResultFromJoi = (body, schema, options) => Joi.validate(body, schema, options, (err, data) => {
module.exports.getResultFromJoi = (body, schema, options) => schema.validate(body, options, (err, data) => {
if (err) {
const output = {
status: 'failed',
Expand Down Expand Up @@ -49,10 +47,12 @@ module.exports.isValid = (schema) => (req, res, next) => {
result.error.details.forEach((err) => {
description += (`${err.message.charAt(0).toUpperCase() + err.message.slice(1).toLowerCase()}. `);
});

if (result.error._original && (result.error._original.password || result.error._original.firstname)) result.error._original = _.pick(result.error._original, config.whitelists.users.default);
return responses.error(res, 422, 'Schema validation error', description)(result.error);
}
// else return req.body with the data after Joi validation
req.body = result;
req.body = result.value;
return next();
}
next();
Expand Down
2 changes: 0 additions & 2 deletions lib/services/seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const path = require('path');
const AppError = require(path.resolve('./lib/helpers/AppError'));
const config = require('../../config');


// global seed options object
let seedOptions = {};

Expand Down Expand Up @@ -48,7 +47,6 @@ module.exports.start = async (options, UserService, TaskService) => {
if (_.has(options, 'seedAdmin')) seedOptions.seedAdmin = options.seedAdmin;
if (_.has(options, 'seedTasks')) seedOptions.seedTasks = options.seedTasks;


try {
if (process.env.NODE_ENV === 'production') {
pwd = await UserService.generateRandomPassphrase();
Expand Down
1 change: 0 additions & 1 deletion modules/core/tests/core.config.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ describe('Configuration Tests:', () => {
process.env.NODE_ENV = nodeEnv;
});


it('should seed admin, and "regular" user accounts when NODE_ENV is set to "test" when they already exist', async () => {
const nodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'test';
Expand Down
1 change: 0 additions & 1 deletion modules/tasks/controllers/tasks.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ exports.delete = async (req, res) => {
}
};


/**
* @desc MiddleWare to ask the service the task for this id
* @param {Object} req - Express request object
Expand Down
4 changes: 2 additions & 2 deletions modules/tasks/models/tasks.schema.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/**
* Module dependencies
*/
const Joi = require('joi');
const Joi = require('@hapi/joi');

/**
* Data Schema
*/
const TaskSchema = Joi.object().keys({
title: Joi.string().trim().default('').required(),
description: Joi.string().allow('').default(''),
description: Joi.string().allow('').default('').required(),
user: Joi.string().trim().default(''),
});

Expand Down
3 changes: 1 addition & 2 deletions modules/tasks/tests/tasks.crud.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('Tasks CRUD Tests :', () => {
.expect(422);
expect(result.body.type).toBe('error');
expect(result.body.message).toEqual('Schema validation error');
expect(result.body.description).toBe('Title must be a string. ');
expect(result.body.description).toBe('"title" must be a string. ');
} catch (err) {
console.log(err);
expect(err).toBeFalsy();
Expand Down Expand Up @@ -237,7 +237,6 @@ describe('Tasks CRUD Tests :', () => {
}
});


test('should be able to get list of tasks', async () => {
// get list
try {
Expand Down
19 changes: 8 additions & 11 deletions modules/tasks/tests/tasks.schema.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
* Module dependencies.
*/
const _ = require('lodash');
const Joi = require('joi');
const path = require('path');

const config = require(path.resolve('./config'));
const options = _.clone(config.joi.validationOptions);
const schema = require('../models/tasks.schema');


// Globals
let task;

Expand All @@ -25,7 +23,7 @@ describe('Tasks Schema Tests :', () => {
});

test('should be valid a task example without problems', (done) => {
const result = Joi.validate(task, schema.Task, options);
const result = schema.Task.validate(task, options);
expect(typeof result).toBe('object');
expect(result.error).toBeFalsy();
done();
Expand All @@ -34,16 +32,16 @@ describe('Tasks Schema Tests :', () => {
test('should be able to show an error when trying a schema without title', (done) => {
task.title = '';

const result = Joi.validate(task, schema.Task, options);
const result = schema.Task.validate(task, options);
expect(typeof result).toBe('object');
expect(result.error).toBeDefined();
done();
});

test('should be able to show an error when trying a schema without description', (done) => {
task.description = '';
task.description = null;

const result = Joi.validate(task, schema.Task, options);
const result = schema.Task.validate(task, options);
expect(typeof result).toBe('object');
expect(result.error).toBeDefined();
done();
Expand All @@ -52,18 +50,17 @@ describe('Tasks Schema Tests :', () => {
test('should not show an error when trying a schema with user', (done) => {
task.user = '507f1f77bcf86cd799439011';

const result = Joi.validate(task, schema.Task, options);
const result = schema.Task.validate(task, options);
expect(typeof result).toBe('object');
expect(result.error).toBeFalsy();
done();
});

test('should be able to show an error when trying a different schema', (done) => {
test('should be able remove unknown when trying a different schema', (done) => {
task.toto = '';

const result = Joi.validate(task, schema.Task, options);
expect(typeof result).toBe('object');
expect(result.error).toBeDefined();
const result = schema.Task.validate(task, options);
expect(result.toto).toBeUndefined();
done();
});
});
1 change: 0 additions & 1 deletion modules/uploads/tests/uploads.crud.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,6 @@ describe('Uploads CRUD Tests :', () => {
});
});


// Mongoose disconnect
afterAll(async () => {
try {
Expand Down
1 change: 0 additions & 1 deletion modules/users/controllers/admin.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ exports.update = async (req, res) => {
}
};


/**
* @desc Endpoint to ask the service to delete a user
* @param {Object} req - Express request object
Expand Down
2 changes: 0 additions & 2 deletions modules/users/controllers/users/users.images.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const responses = require(path.resolve('./lib/helpers/responses'));
const UploadsService = require(path.resolve('./modules/uploads/services/uploads.service'));
const UserService = require('../../services/user.service');


/**
* @desc Endpoint to ask the service to update a user profile avatar
* @param {Object} req - Express request object
Expand All @@ -35,7 +34,6 @@ exports.updateAvatar = async (req, res) => {
}
};


/**
* @desc Endpoint to ask the service to delete a user profile avatar
* @param {Object} req - Express request object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ exports.updatePassword = async (req, res) => {
if (!await UserService.comparePassword(req.body.currentPassword, user.password)) return responses.error(res, 422, 'Unprocessable Entity', 'Current password is incorrect')();
if (req.body.newPassword !== req.body.verifyPassword) return responses.error(res, 422, 'Unprocessable Entity', 'Passwords do not match')();


password = UserService.checkPassword(req.body.newPassword);

user = await UserService.update(user, { password }, 'recover');
Expand Down
3 changes: 1 addition & 2 deletions modules/users/models/user.model.mongoose.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const UserMongoose = new Schema({
unique: 'Email already exists',
},
avatar: String,
roles: [],
roles: [String],
/* Provider */
provider: String,
providerData: {},
Expand Down Expand Up @@ -48,7 +48,6 @@ UserMongoose.set('toJSON', {
*/
// UserMongoose.methods.authenticate = password => this.password === this.hashPassword(password);


// UserMongoose.static('findOneOrCreate', async (condition, doc) => {
// const one = await this.findOne(condition);
// return one || this.create(doc).then((document) => {
Expand Down
16 changes: 8 additions & 8 deletions modules/users/models/user.schema.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Module dependencies
*/
const joiZxcvbn = require('joi-zxcvbn');
const PlainJoi = require('joi');
const PlainJoi = require('@hapi/joi');
const path = require('path');

const Joi = PlainJoi.extend(joiZxcvbn(PlainJoi));
const joiHelpers = require(path.resolve('./lib/helpers/joi'));
const Joi = PlainJoi.extend(joiHelpers.joiZxcvbn(PlainJoi));
const config = require(path.resolve('./config'));

/**
Expand All @@ -23,19 +23,19 @@ const UserSchema = Joi.object().keys({
.trim()
.allow('')
.optional(),
email: Joi.string().email({ minDomainAtoms: 2 }),
email: Joi.string().email(),
avatar: Joi.string().trim().default(''),
roles: Joi.array().items(Joi.string().valid(config.whitelists.users.roles)).min(1).default(['user']),
roles: Joi.array().items(Joi.string().valid(...config.whitelists.users.roles)).min(1).default(['user']),
/* Extra */
updated: Joi.date(),
created: Joi.date().default(Date.now, 'current date'),
created: Joi.date(),
/* Provider */
provider: Joi.string(),
providerData: Joi.object(),
additionalProvidersData: Joi.object(),
/* Password */
password: Joi.string().min(4).max(128).default('')
.zxcvbn(config.zxcvbn.minimumScore),
password: Joi.zxcvbn().strength(config.zxcvbn.minimumScore).min(config.zxcvbn.minSize).max(config.zxcvbn.maxSize)
.default(''),
resetPasswordToken: Joi.string(),
resetPasswordExpires: Joi.date(),
});
Expand Down
1 change: 0 additions & 1 deletion modules/users/routes/users.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const model = require(path.resolve('./lib/middlewares/model'));
const policy = require(path.resolve('./lib/middlewares/policy'));
const usersSchema = require('../models/user.schema');


const config = require(path.resolve('./config'));

module.exports = (app) => {
Expand Down
1 change: 0 additions & 1 deletion modules/users/services/oAuth.service.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

const path = require('path');
const { OAuth2Client } = require('google-auth-library');

Expand Down
7 changes: 3 additions & 4 deletions modules/users/tests/user.crud.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ describe('User CRUD Tests :', () => {
.expect(422);
expect(result.body.type).toBe('error');
expect(result.body.message).toBe('Schema validation error');
expect(result.body.description).toEqual('Password password strength score 0 does not suffice the minimum of 3. ');
expect(result.body.description).toEqual('Password must have a strength of at least 3. "password" length must be at least 8 characters long. ');
} catch (err) {
console.log(err);
expect(err).toBeFalsy();
Expand All @@ -105,8 +105,8 @@ describe('User CRUD Tests :', () => {
.expect(422);
expect(result.body.type).toBe('error');
expect(result.body.message).toBe('Schema validation error');
expect(result.body.description).toEqual('Password password strength score 0 does not suffice the minimum of 3. ');
expect(JSON.parse(result.body.error).original.password).toBeUndefined();
expect(result.body.description).toEqual('Password must have a strength of at least 3. "password" length must be at least 8 characters long. ');
expect(JSON.parse(result.body.error)._original.password).toBeUndefined();
} catch (err) {
console.log(err);
expect(err).toBeFalsy();
Expand Down Expand Up @@ -775,7 +775,6 @@ describe('User CRUD Tests :', () => {
expect(err).toBeFalsy();
}


try {
const result = await UserService.get(user);

Expand Down
Loading

0 comments on commit ef5a50f

Please sign in to comment.