From 111c0f8e2f5d872896200407659cf33f888e357a Mon Sep 17 00:00:00 2001 From: thomas Date: Sat, 14 Mar 2020 23:26:13 +0200 Subject: [PATCH 1/6] change configuration of env variables --- .gitignore | 2 +- config/dbConnection.js | 9 ++++----- package.json | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 40dfe67..e4010aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /node_modules package-lock.json -default.json +.env diff --git a/config/dbConnection.js b/config/dbConnection.js index 1fbc7c1..67f682d 100644 --- a/config/dbConnection.js +++ b/config/dbConnection.js @@ -1,18 +1,17 @@ const mongoose = require('mongoose'); -const config = require('config'); -const db = config.get('mongoURI'); +const dotenv = require('dotenv').config(); const connectDB = async () => { try { - await mongoose.connect(db, { + await mongoose.connect(process.env.mongoURI, { useUnifiedTopology: true, useNewUrlParser: true }); - + console.log('Mongo connected...') } catch (err) { console.log(err.message); } }; -module.exports = connectDB; +module.exports = connectDB; \ No newline at end of file diff --git a/package.json b/package.json index d96088a..c4dcb31 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/thomas367/nodeDemo#readme", "dependencies": { - "config": "^3.3.0", + "dotenv": "^8.2.0", "express": "^4.17.1", "mongoose": "^5.9.4" }, From 36df0e1a6e92868e5e74cb4ecafa0ed14e313ec1 Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 15 Mar 2020 13:36:45 +0200 Subject: [PATCH 2/6] add packages --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index c4dcb31..88b6637 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,12 @@ }, "homepage": "https://github.com/thomas367/nodeDemo#readme", "dependencies": { + "bcryptjs": "^2.4.3", "dotenv": "^8.2.0", "express": "^4.17.1", + "express-validator": "^6.4.0", + "gravatar": "^1.8.0", + "jsonwebtoken": "^8.5.1", "mongoose": "^5.9.4" }, "devDependencies": { From 5ecee5f8098bfc643f11c906a844172b6d0c8ee6 Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 15 Mar 2020 13:37:28 +0200 Subject: [PATCH 3/6] create auth middleware --- config/dbConnection.js | 5 +++-- middleware/auth.js | 18 ++++++++++++++++++ server.js | 3 +++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 middleware/auth.js diff --git a/config/dbConnection.js b/config/dbConnection.js index 67f682d..830e004 100644 --- a/config/dbConnection.js +++ b/config/dbConnection.js @@ -5,7 +5,8 @@ const connectDB = async () => { try { await mongoose.connect(process.env.mongoURI, { useUnifiedTopology: true, - useNewUrlParser: true + useNewUrlParser: true, + useCreateIndex: true }); console.log('Mongo connected...') @@ -14,4 +15,4 @@ const connectDB = async () => { } }; -module.exports = connectDB; \ No newline at end of file +module.exports = connectDB; diff --git a/middleware/auth.js b/middleware/auth.js new file mode 100644 index 0000000..18f773b --- /dev/null +++ b/middleware/auth.js @@ -0,0 +1,18 @@ +const jwt = require('jsonwebtoken'); +const dotenv = require('dotenv').config(); + +module.exports = (req, res, next) => { + const token = req.header('x-auth-token'); + + if (!token) { + return res.status(401).json({ message: 'No token, authorization denied' }); + } + + try { + const decoded = jwt.verify(token, process.env.jwtSecret); + req.user = decoded.user; + next(); + } catch(err) { + res.status(401).json({ message: 'Token is not valid' }); + } +} diff --git a/server.js b/server.js index cde63fe..e9f840e 100644 --- a/server.js +++ b/server.js @@ -5,10 +5,13 @@ const app = express(); connectDB(); +app.use(express.json({ extended: false })); + app.get('/', (req, res) => res.send('API running')); //Access user route app.use('/api/users', require('./routes/api/users')); +app.use('/api/auth', require('./routes/api/auth')); const PORT = process.env.PORT || 5000; From fc43e91986f51e5536e34aeb8a097f78daf78604 Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 15 Mar 2020 13:38:07 +0200 Subject: [PATCH 4/6] register and authenticate user --- routes/api/auth.js | 59 ++++++++++++++++++++++++++++++++++++++ routes/api/users.js | 70 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 routes/api/auth.js diff --git a/routes/api/auth.js b/routes/api/auth.js new file mode 100644 index 0000000..8063ff5 --- /dev/null +++ b/routes/api/auth.js @@ -0,0 +1,59 @@ +const express = require('express'); +const router = express.Router(); +const bcrypt = require('bcryptjs'); +const { check, validationResult } = require('express-validator'); +const jwt = require('jsonwebtoken'); +const dotenv = require('dotenv').config(); + +const User = require('../../models/User'); + +/** + * @route POST api/auth + * @desc Auth user + */ +router.post('/', [ + check('email', 'Please include a valid email').isEmail(), + check('password', 'Passoword id required').exists() +], async (req, res) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + const {email, password } = req.body; + + try { + let user = await User.findOne({ email }); + + if (!user) { + return res.status(400).json({ errors: [{ message: 'Invalid Credentials' }] }); + } + + const isMatched = await bcrypt.compare(password, user.password); + + if (!isMatched) { + return res.status(400).json({ errors: [{ message: 'Invalid Credentials' }] }); + } + + const payload = { + user: { + id: user.id + } + } + + jwt.sign( + payload, + process.env.jwtSecret, + {expiresIn: 36000}, + (err, token) => { + if (err) throw err; + res.json({ token }); + }); + + } catch(err) { + console.log(err.message); + res.status(500).send('Server error'); + } +}); + +module.exports = router; diff --git a/routes/api/users.js b/routes/api/users.js index 7394fc8..f781525 100644 --- a/routes/api/users.js +++ b/routes/api/users.js @@ -1,9 +1,71 @@ const express = require('express'); const router = express.Router(); +const bcrypt = require('bcryptjs'); +const { check, validationResult } = require('express-validator'); +const gravatar = require('gravatar'); +const jwt = require('jsonwebtoken'); +const dotenv = require('dotenv').config(); +const User = require('../../models/User'); -//Test route -// /api/user route -router.get('/', (req, res) => res.send('User route')); +/** + * @route POST api/users + * @desc Register user + */ +router.post('/', [ + check('name', 'Name is required').not().isEmpty(), + check('email', 'Please include a valid email').isEmail(), + check('password', 'Please enter a password with 6 or more characters').isLength({ min: 6 }) +], async (req, res) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } -module.exports = router; + const {name, email, password } = req.body; + + try { + let user = await User.findOne({ email }); + + if (user) { + return res.status(400).json({ errors: [{ message: 'User already exists' }] }); + } + + const avatar = gravatar.url(email, { + s: '200', + r: 'pg', + d: 'mm' + }); + + user = new User({ name, email, avatar, password }); + + const salt = await bcrypt.genSalt(10); + user.password = await bcrypt.hash(password, salt); + + await user.save(); + + const payload = { + user: { + id: user.id + } + } + + jwt.sign( + payload, + process.env.jwtSecret, + {expiresIn: 36000}, + (err, token) => { + if (err) throw err; + res.json({ token }); + }); + + + } catch(err) { + console.log(err.message); + res.status(500).send('Server error'); + } + + +}); + +module.exports = router; \ No newline at end of file From 92f6b4ae74e8b990e7dfb22a5b80199f4a837ff2 Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 15 Mar 2020 16:17:12 +0200 Subject: [PATCH 5/6] change routes structure, move logic to controllers --- .../users.js => controllers/authController.js | 60 ++++++++++++++----- routes/api/auth.js | 59 ------------------ routes/routes.js | 8 +++ server.js | 6 +- 4 files changed, 54 insertions(+), 79 deletions(-) rename routes/api/users.js => controllers/authController.js (54%) delete mode 100644 routes/api/auth.js create mode 100644 routes/routes.js diff --git a/routes/api/users.js b/controllers/authController.js similarity index 54% rename from routes/api/users.js rename to controllers/authController.js index f781525..011f27d 100644 --- a/routes/api/users.js +++ b/controllers/authController.js @@ -1,22 +1,12 @@ const express = require('express'); -const router = express.Router(); const bcrypt = require('bcryptjs'); const { check, validationResult } = require('express-validator'); -const gravatar = require('gravatar'); const jwt = require('jsonwebtoken'); const dotenv = require('dotenv').config(); -const User = require('../../models/User'); - -/** - * @route POST api/users - * @desc Register user - */ -router.post('/', [ - check('name', 'Name is required').not().isEmpty(), - check('email', 'Please include a valid email').isEmail(), - check('password', 'Please enter a password with 6 or more characters').isLength({ min: 6 }) -], async (req, res) => { +const User = require('../models/User'); + +exports.register = async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); @@ -64,8 +54,46 @@ router.post('/', [ console.log(err.message); res.status(500).send('Server error'); } +}; - -}); +exports.login = async (req, res) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + const {email, password } = req.body; + + try { + let user = await User.findOne({ email }); -module.exports = router; \ No newline at end of file + if (!user) { + return res.status(400).json({ errors: [{ message: 'Invalid Credentials' }] }); + } + + const isMatched = await bcrypt.compare(password, user.password); + + if (!isMatched) { + return res.status(400).json({ errors: [{ message: 'Invalid Credentials' }] }); + } + + const payload = { + user: { + id: user.id + } + } + + jwt.sign( + payload, + process.env.jwtSecret, + {expiresIn: 36000}, + (err, token) => { + if (err) throw err; + res.json({ token }); + }); + + } catch(err) { + console.log(err.message); + res.status(500).send('Server error'); + } +}; diff --git a/routes/api/auth.js b/routes/api/auth.js deleted file mode 100644 index 8063ff5..0000000 --- a/routes/api/auth.js +++ /dev/null @@ -1,59 +0,0 @@ -const express = require('express'); -const router = express.Router(); -const bcrypt = require('bcryptjs'); -const { check, validationResult } = require('express-validator'); -const jwt = require('jsonwebtoken'); -const dotenv = require('dotenv').config(); - -const User = require('../../models/User'); - -/** - * @route POST api/auth - * @desc Auth user - */ -router.post('/', [ - check('email', 'Please include a valid email').isEmail(), - check('password', 'Passoword id required').exists() -], async (req, res) => { - const errors = validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - - const {email, password } = req.body; - - try { - let user = await User.findOne({ email }); - - if (!user) { - return res.status(400).json({ errors: [{ message: 'Invalid Credentials' }] }); - } - - const isMatched = await bcrypt.compare(password, user.password); - - if (!isMatched) { - return res.status(400).json({ errors: [{ message: 'Invalid Credentials' }] }); - } - - const payload = { - user: { - id: user.id - } - } - - jwt.sign( - payload, - process.env.jwtSecret, - {expiresIn: 36000}, - (err, token) => { - if (err) throw err; - res.json({ token }); - }); - - } catch(err) { - console.log(err.message); - res.status(500).send('Server error'); - } -}); - -module.exports = router; diff --git a/routes/routes.js b/routes/routes.js new file mode 100644 index 0000000..b4509a5 --- /dev/null +++ b/routes/routes.js @@ -0,0 +1,8 @@ +const express = require('express'); +const router = express.Router(); +const authCtrl = require('../controllers/authController'); + +router.post('/login', authCtrl.login); +router.post('/register', authCtrl.register); + +module.exports = router; \ No newline at end of file diff --git a/server.js b/server.js index e9f840e..bad9b3f 100644 --- a/server.js +++ b/server.js @@ -1,5 +1,6 @@ const express = require('express'); const connectDB = require('./config/dbConnection'); +const routes = require('./routes/routes'); const app = express(); @@ -8,10 +9,7 @@ connectDB(); app.use(express.json({ extended: false })); app.get('/', (req, res) => res.send('API running')); - -//Access user route -app.use('/api/users', require('./routes/api/users')); -app.use('/api/auth', require('./routes/api/auth')); +app.use('/', routes); const PORT = process.env.PORT || 5000; From 84316ada8a196068039cc5e33d60ca8ec608ce1f Mon Sep 17 00:00:00 2001 From: thomas Date: Sun, 15 Mar 2020 18:08:20 +0200 Subject: [PATCH 6/6] move validation to middleware --- controllers/authController.js | 13 +---------- middleware/validations/authValidation.js | 29 ++++++++++++++++++++++++ routes/routes.js | 5 ++-- 3 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 middleware/validations/authValidation.js diff --git a/controllers/authController.js b/controllers/authController.js index 011f27d..4d1f1ad 100644 --- a/controllers/authController.js +++ b/controllers/authController.js @@ -1,17 +1,11 @@ const express = require('express'); const bcrypt = require('bcryptjs'); -const { check, validationResult } = require('express-validator'); const jwt = require('jsonwebtoken'); const dotenv = require('dotenv').config(); const User = require('../models/User'); exports.register = async (req, res) => { - const errors = validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - const {name, email, password } = req.body; try { @@ -57,11 +51,6 @@ exports.register = async (req, res) => { }; exports.login = async (req, res) => { - const errors = validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - const {email, password } = req.body; try { @@ -96,4 +85,4 @@ exports.login = async (req, res) => { console.log(err.message); res.status(500).send('Server error'); } -}; +}; \ No newline at end of file diff --git a/middleware/validations/authValidation.js b/middleware/validations/authValidation.js new file mode 100644 index 0000000..7730de9 --- /dev/null +++ b/middleware/validations/authValidation.js @@ -0,0 +1,29 @@ +const { check, validationResult } = require('express-validator'); + +exports.login = [ + check('email', 'Please include a valid email').isEmail(), + check('password', 'Password id required').exists(), + + function(req, res, next) { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + return next(); + } +]; + +exports.register = [ + check('name', 'Name is required').not().isEmpty(), + check('email', 'Please include a valid email').isEmail(), + check('password', 'Please enter a password with 6 or more characters').isLength({ min: 6 }), + + function(req, res, next) { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + return next(); + } +]; + diff --git a/routes/routes.js b/routes/routes.js index b4509a5..c4b717d 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -1,8 +1,9 @@ const express = require('express'); const router = express.Router(); const authCtrl = require('../controllers/authController'); +const validation = require('../middleware/validations/authValidation'); -router.post('/login', authCtrl.login); -router.post('/register', authCtrl.register); +router.post('/login', validation.login, authCtrl.login); +router.post('/register', validation.register, authCtrl.register); module.exports = router; \ No newline at end of file