-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
…roject
- Loading branch information
Satyajit Dey
committed
May 14, 2020
1 parent
49d2e88
commit 50028e2
Showing
16 changed files
with
3,250 additions
and
197 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,35 @@ | ||
var debug = require('debug')('cms-backend-api:*'); | ||
var express = require('express'); | ||
var logger = require('morgan'); | ||
var mongoose=require('mongoose'); | ||
const express = require('express'); | ||
const logger = require('morgan'); | ||
const bodyParser = require('body-parser'); | ||
const UsersRouter = require('./routes/users.route'); | ||
const AuthRouter = require('./routes/auth.route'); | ||
|
||
//custom modules | ||
var indexRouter = require('./routes/index'); | ||
var usersRouter = require('./routes/users'); | ||
|
||
//connect to database | ||
var connect = mongoose.connect(process.env.DB_URL,{ | ||
autoIndex: false, | ||
useNewUrlParser: true, | ||
useUnifiedTopology: true | ||
}); | ||
|
||
connect.then((db) => { | ||
debug('Connected to database ' + process.env.DB_URL); | ||
}, (err) => { console.log(err); }); | ||
|
||
|
||
|
||
var app = express(); | ||
const app = express(); | ||
|
||
//middleware | ||
app.use(logger('dev')); | ||
app.use(express.json()); | ||
app.use(express.urlencoded({ extended: false })); | ||
|
||
//routes | ||
app.use('/', indexRouter); | ||
app.use('/users', usersRouter); | ||
app.use(function (req, res, next) { | ||
res.header('Access-Control-Allow-Origin', '*'); | ||
res.header('Access-Control-Allow-Credentials', 'true'); | ||
res.header('Access-Control-Allow-Methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'); | ||
res.header('Access-Control-Expose-Headers', 'Content-Length'); | ||
res.header('Access-Control-Allow-Headers', 'Accept, Authorization, Content-Type, X-Requested-With, Range'); | ||
if (req.method === 'OPTIONS') { | ||
return res.send(200); | ||
} else { | ||
return next(); | ||
} | ||
}); | ||
|
||
app.use(bodyParser.json()); | ||
UsersRouter.routesConfig(app); | ||
AuthRouter.routesConfig(app); | ||
|
||
app.get(process.env.API_ENPOINT_BASE, (req, res) => { | ||
res.send(`CMS API v1.`) | ||
}); | ||
|
||
module.exports = app; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
const jwt = require('jsonwebtoken'); | ||
const crypto = require('crypto'); | ||
|
||
exports.login = (req, res) => { | ||
try { | ||
let refreshId = req.body.userId + process.env.AUTH_SECRET; | ||
let salt = crypto.randomBytes(16).toString('base64'); | ||
let hash = crypto.createHmac('sha512', salt).update(refreshId).digest("base64"); | ||
req.body.refreshKey = salt; | ||
let token = jwt.sign(req.body, process.env.AUTH_SECRET); | ||
let b = new Buffer(hash); | ||
let refresh_token = b.toString('base64'); | ||
res.status(201).send({accessToken: token, refreshToken: refresh_token}); | ||
} catch (err) { | ||
res.status(500).send({errors: err}); | ||
} | ||
}; | ||
|
||
exports.logout = (req, res) => { | ||
res.status(204).send({accessToken: null, refreshToken: null}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
const UserModel = require('../models/users.model'); | ||
const crypto = require('crypto'); | ||
|
||
exports.insert = (req, res) => { | ||
let salt = crypto.randomBytes(16).toString('base64'); | ||
let hash = crypto.createHmac('sha512', salt).update(req.body.password).digest("base64"); | ||
req.body.password = salt + "$" + hash; | ||
UserModel.createUser(req.body) | ||
.then((result) => { | ||
res.status(201).send({id: result._id}); | ||
}); | ||
}; | ||
|
||
exports.list = (req, res) => { | ||
let limit = req.query.limit && req.query.limit <= 100 ? parseInt(req.query.limit) : 10; | ||
let page = 0; | ||
if (req.query) { | ||
if (req.query.page) { | ||
req.query.page = parseInt(req.query.page); | ||
page = Number.isInteger(req.query.page) ? req.query.page : 0; | ||
} | ||
} | ||
|
||
UserModel.list(limit, page) | ||
.then((result) => { | ||
res.status(200).send(result); | ||
}) | ||
}; | ||
|
||
exports.getById = (req, res) => { | ||
UserModel.findById(req.params.userId) | ||
.then((result) => { | ||
res.status(200).send(result); | ||
}).catch(err => res.status(400).send({'message': err.message})); | ||
}; | ||
|
||
exports.patchById = (req, res) => { | ||
if (req.body.password) { | ||
let salt = crypto.randomBytes(16).toString('base64'); | ||
let hash = crypto.createHmac('sha512', salt).update(req.body.password).digest("base64"); | ||
req.body.password = salt + "$" + hash; | ||
} | ||
|
||
UserModel.patchUser(req.params.userId, req.body) | ||
.then((result) => { | ||
res.status(204).send({}); | ||
}); | ||
|
||
}; | ||
|
||
exports.removeById = (req, res) => { | ||
UserModel.removeById(req.params.userId) | ||
.then((result) => { | ||
res.status(204).send({}); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
exports.minimumPermissionLevelRequired = (required_permission_level) => { | ||
return (req, res, next) => { | ||
let user_permission_level = parseInt(req.jwt.permissionLevel); | ||
if (user_permission_level & required_permission_level) { | ||
return next(); | ||
} else { | ||
return res.status(403).send(); | ||
} | ||
}; | ||
}; | ||
|
||
exports.onlySameUserOrAdminCanDoThisAction = (req, res, next) => { | ||
|
||
let user_permission_level = parseInt(req.jwt.permissionLevel); | ||
let userId = req.jwt.userId; | ||
if (req.params && req.params.userId && userId === req.params.userId) { | ||
return next(); | ||
} else { | ||
if (user_permission_level & process.env.AUTH_PERMISSION_ADMIN) { | ||
return next(); | ||
} else { | ||
return res.status(403).send(); | ||
} | ||
} | ||
|
||
}; | ||
|
||
exports.sameUserCantDoThisAction = (req, res, next) => { | ||
let userId = req.jwt.userId; | ||
|
||
if (req.params.userId !== userId) { | ||
return next(); | ||
} else { | ||
return res.status(400).send(); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
const {check} = require('express-validator'); | ||
const crypto = require('crypto'); | ||
const jwt = require('jsonwebtoken'); | ||
const UserModel = require('../models/users.model'); | ||
|
||
exports.authFieldValidationRules = () => { | ||
return [ | ||
// email should not be empty | ||
check('email', 'email empty').notEmpty(), | ||
// email must be valid | ||
check('email', 'email is not valid').isEmail().normalizeEmail(), | ||
// password should not be empty | ||
check('password', 'password empty').notEmpty() | ||
] | ||
}; | ||
|
||
exports.matchEmailAndPassword = (req, res, next) => { | ||
const {email, password} = req.body; | ||
UserModel.findByEmail(email).then(user => { | ||
if (!user) { | ||
return res.status(404).send({errors: `User with email:<${email}> doesn't exist`}); | ||
} else { | ||
let passwordFields = user.password.split('$'); | ||
let salt = passwordFields[0]; | ||
let hash = crypto.createHmac('sha512', salt).update(password).digest("base64"); | ||
if (hash === passwordFields[1]) { | ||
req.body = { | ||
userId: user._id, | ||
email: user.email, | ||
permissionLevel: user.permissionLevel, | ||
provider: 'email', | ||
name: `${user.firstName} ${user.lastName}`, | ||
}; | ||
return next(); | ||
} else { | ||
return res.status(400).send({errors: 'Invalid e-mail or password'}); | ||
} | ||
} | ||
}); | ||
}; | ||
|
||
exports.verifyJwtToken = (req, res, next) => { | ||
if (req.headers['authorization']) { | ||
try { | ||
let authorization = req.headers['authorization'].split(' '); | ||
if (authorization[0] !== 'Bearer') { | ||
return res.status(401).send(); | ||
} else { | ||
req.jwt = jwt.verify(authorization[1], process.env.AUTH_SECRET); | ||
return next(); | ||
} | ||
|
||
} catch (err) { | ||
return res.status(403).send(); | ||
} | ||
} else { | ||
return res.status(401).send(); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const {validationResult} = require('express-validator'); | ||
|
||
exports.validateRules = (req, res, next) => { | ||
const errors = validationResult(req); | ||
if (errors.isEmpty()) { | ||
return next(); | ||
} | ||
|
||
const extractedErrors = []; | ||
errors.array().map(err => extractedErrors.push({[err.param]: err.msg})); | ||
|
||
return res.status(400).json({ | ||
errors: extractedErrors, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
const mongoose = require('../services/db.service').mongoose; | ||
const UserModel = require('../models/users.model'); | ||
|
||
const {check} = require('express-validator'); | ||
|
||
exports.registrationFieldValidationRules = () => { | ||
return [ | ||
// firstName should not be empty | ||
check('firstName', 'firstName empty').notEmpty(), | ||
// lastName should not be empty | ||
check('lastName', 'lastName empty').notEmpty(), | ||
// email should not be empty | ||
check('email', 'email empty').notEmpty(), | ||
// email must be valid | ||
check('email', 'email is not valid').isEmail().normalizeEmail(), | ||
// password should not be empty | ||
check('password', 'password empty').notEmpty(), | ||
// password must be at least 8 chars long | ||
check('password', 'password must be at least 8 chars long').isLength({min: 8}) | ||
] | ||
}; | ||
|
||
exports.isEmailAlreadyExists = (req, res, next) => { | ||
UserModel.findByEmail(req.body.email) | ||
.then((result) => { | ||
if (result) { | ||
return res.status(409).json({message: 'Email already in use.'}); | ||
} else { | ||
return next(); | ||
} | ||
}).catch(err => res.status(500).json({errors: err})); | ||
}; | ||
|
||
exports.verifyUserId = (req, res, next) => { | ||
if (req.params.userId && mongoose.Types.ObjectId.isValid(req.params.userId)) { | ||
return next(); | ||
} | ||
|
||
return res.sendStatus(404); | ||
}; | ||
|
||
exports.updatePasswordValidationRules = () => { | ||
return [ | ||
check('email', 'email empty').notEmpty(), | ||
// email must be valid | ||
check('email', 'email is not valid').isEmail().normalizeEmail(), | ||
// password should not be empty | ||
check('password', 'password empty').notEmpty(), | ||
// password must be at least 8 chars long | ||
check('password', 'password must be at least 8 chars long').isLength({min: 8}) | ||
] | ||
}; | ||
|
Oops, something went wrong.