Skip to content

Commit

Permalink
refactor(validation): move validators into middleware
Browse files Browse the repository at this point in the history
Tell express app to use validator library
  • Loading branch information
chidimo committed May 12, 2019
1 parent f932933 commit 56018cd
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 91 deletions.
2 changes: 2 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from 'path';
import cookieParser from 'cookie-parser';
import logger from 'morgan';
import dotenv from 'dotenv';
import validator from 'express-validator';

import indexRouter from './routes/index';

Expand All @@ -18,6 +19,7 @@ app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(validator());

app.use('/', indexRouter);

Expand Down
104 changes: 17 additions & 87 deletions middleware/authentication.js
Original file line number Diff line number Diff line change
@@ -1,96 +1,26 @@
import { body, validationResult } from 'express-validator/check';
import { sanitizeBody } from 'express-validator/filter';
import jwt from 'jsonwebtoken';
// import debug from 'debug';

import users from '../utils/sample.users';
// import dev_logger from '../utils/loggers';

const AuthenticationMiddleware = {
generateToken: [

body('email')
.isEmail()
.withMessage('Please provide a valid email address')
.normalizeEmail(),
body('password')
.not().isEmpty().withMessage('Password is required')
.isLength({ min: 8 }).trim()
.withMessage('Password must be at least 8 characters')
.isLength({ max: 16 })
.withMessage('Password must be at most 16 characters')
.isAlphanumeric().withMessage('Password must be alphanumeric')
.custom((value, { req }) => {
if (value !== req.body.confirm_password) {
throw new Error(
'Password confirmation does not match password'
);
}
else return value;
}),
sanitizeBody('email').trim().escape(),
sanitizeBody('password').trim().escape(),
sanitizeBody('confirm_password').trim().escape(),

(req, res, next) => {

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}

req.token = jwt.sign(
req.body,
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
generateToken: (req, res, next) => {
req.token = jwt.sign(
req.body,
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
return next();
},

verifyToken: (req, res, next) => {
try {
req.user = jwt.verify(req.body.token, process.env.JWT_SECRET);
req.token = req.body.token;
return next();
}
],

verifyToken: [
body('email')
.isEmail()
.withMessage('Please provide a valid email address')
.normalizeEmail()
.custom((value, { req }) => {
const { email, password } = req.body;
const user = users.find(user => (user.email === email));
if (user === undefined) {
throw new Error('User not found');
}
if (user.password !== password) {
throw new Error('Wrong password');
}
return value;
}),

body('password')
.not().isEmpty().withMessage('Password is required')
.isLength({ min: 8 }).trim()
.withMessage('Password must be at least 8 characters')
.isLength({ max: 16 })
.withMessage('Password must be at most 16 characters')
.isAlphanumeric().withMessage('Password must be alphanumeric'),

sanitizeBody('email').trim().escape(),
sanitizeBody('password').trim().escape(),
(req, res, next) => {

const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}

try {
req.user = jwt.verify(req.body.token, process.env.JWT_SECRET);
req.token = req.body.token;
return next();
}
catch (err) {
res.status(422).json({ error: 'Invalid token' });
}
catch (err) {
res.status(422).json({ error: 'Invalid token' });
}
]
}
};

export default AuthenticationMiddleware;
93 changes: 93 additions & 0 deletions middleware/validators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { body, validationResult } from 'express-validator/check';
import { sanitizeBody } from 'express-validator/filter';

// import { dev_logger } from '../utils/loggers';

const ParamterValidators = {
emailValidator: [
body('email')
.isEmail()
.withMessage('Please provide a valid email address')
.normalizeEmail(),
sanitizeBody('email').trim().escape(),

(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
return next();
}
],

passwordValidator: [
body('password')
.not().isEmpty().withMessage('Password is required')
.isLength({ min: 8 }).trim()
.withMessage('Password must be at least 8 characters')
.isLength({ max: 16 })
.withMessage('Password must be at most 16 characters')
.isAlphanumeric().withMessage('Password must be alphanumeric'),
sanitizeBody('password').trim().escape(),
sanitizeBody('confirm_password').trim().escape(),

(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
return next();
}
],

confirmPasswordValidator: [
body('confirm_password')
.custom((value, { req }) => {
if (value !== req.body.password) {
throw new Error(
'Password confirmation does not match password'
);
}
else return value;
}),

(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
return next();
}
],

updateProfileValidator: [
body('firstName')
.not().isEmpty().withMessage('First name cannot be empty'),
body('lastName')
.not().isEmpty().withMessage('Last namecannot be empty'),
body('phone')
.not().isEmpty().withMessage('Phone number cannot be empty')
.matches(/^0\d{10}$/).withMessage(
'Wrong number format: E.G. 07012345678'),
body('home')
.not().isEmpty().withMessage('Home address cannot be empty'),
body('office')
.not().isEmpty().withMessage('Office address cannot be empty'),

sanitizeBody('firstName').trim().escape(),
sanitizeBody('lastName').trim().escape(),
sanitizeBody('phone').trim().escape(),
sanitizeBody('home').trim().escape(),
sanitizeBody('office').trim().escape(),

(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
return next();
}
]
};

export default ParamterValidators;
15 changes: 11 additions & 4 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import LoansController from '../controllers/LoansController';
import AppController from '../controllers/AppController';

import AuthenticationMiddleware from '../middleware/authentication';
import ParamterValidators from '../middleware/validators.js';

const router = express.Router();

Expand All @@ -15,23 +16,29 @@ router.get('/about', AppController.about);

router.post('/auth/signup',
AuthenticationMiddleware.generateToken,
ParamterValidators.emailValidator,
ParamterValidators.passwordValidator,
ParamterValidators.confirmPasswordValidator,
AuthController.signup
);
router.get('/auth/signup', AuthController.signup);
router.get('/auth/signup',AuthController.signup);
router.post('/auth/signin',
AuthenticationMiddleware.verifyToken,
ParamterValidators.passwordValidator,
AuthController.signin
);
router.get('/auth/signin', AuthController.signin);


router.get('/users/dashboard', UsersController.dashboard);

router.patch('/users/:email/verify', UsersController.verify_user);
router.patch('/users/:id/verify', UsersController.verify_user);
router.get('/users', UsersController.get_users);
router.get('/users/:id', UsersController.get_user);
router.get('/users?status=verified', UsersController.get_users);
router.patch('/users/:id/update', UsersController.update_user);
router.patch('/users/:id/update',
ParamterValidators.updateProfileValidator,
UsersController.update_user
);

router.get('/loans', LoansController.get_all_loans);
router.get('/loans/:id', LoansController.get_loan);
Expand Down

0 comments on commit 56018cd

Please sign in to comment.