From 2bbb831eb09f3427912659b63f85a1db8b5e1f79 Mon Sep 17 00:00:00 2001 From: AwaleRohin Date: Wed, 15 May 2019 17:53:44 +0545 Subject: [PATCH 01/25] login --- config/errorMsg.js | 22 ++++++++ config/secretKey.js | 5 ++ config/statusCode.js | 20 +++++++ index.js | 75 ++++++++++++++------------ models/user.js | 7 ++- package-lock.json | 19 ++++--- package.json | 1 + public/signup.html | 14 ----- routes/signUpRoute.js | 120 +++++++++++++++++++++++++----------------- 9 files changed, 174 insertions(+), 109 deletions(-) create mode 100644 config/errorMsg.js create mode 100644 config/secretKey.js create mode 100644 config/statusCode.js delete mode 100644 public/signup.html diff --git a/config/errorMsg.js b/config/errorMsg.js new file mode 100644 index 0000000..26ad29c --- /dev/null +++ b/config/errorMsg.js @@ -0,0 +1,22 @@ +module.exports={ + user_exists :{ + message : 'User already exists' + }, + auth_fail:{ + message : 'Authentication Failed' + }, + forbidden:{ + message : 'Forbidden' + }, + access_denied:{ + message: 'Access Denied' + }, + invalid :{ + message : 'Invalid Request' + }, + ok : { + message : 'Ok' + } + + +} \ No newline at end of file diff --git a/config/secretKey.js b/config/secretKey.js new file mode 100644 index 0000000..181c693 --- /dev/null +++ b/config/secretKey.js @@ -0,0 +1,5 @@ +module.exports= { + token : { + key : 'secret' + }, +} \ No newline at end of file diff --git a/config/statusCode.js b/config/statusCode.js new file mode 100644 index 0000000..fc09ac4 --- /dev/null +++ b/config/statusCode.js @@ -0,0 +1,20 @@ +module.exports ={ + ok:{ + code : 200 + }, + bad_request : { + code : 400 + }, + unauthorized : { + code : 401 + }, + forbidden : { + code : 403 + }, + not_found : { + code : 404 + }, + internal_server_error : { + code : 500 + }, +} \ No newline at end of file diff --git a/index.js b/index.js index a8ff8a0..16d39e8 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,17 @@ const express = require('express') -const passport = require('passport') -const LinkedInStrategy = require('passport-linkedin').Strategy; +// const passport = require('passport') +// const LinkedInStrategy = require('passport-linkedin').Strategy; const app = express() const signup = require('../mentors/routes/signUpRoute') const bodyParser = require('body-parser') const mongoose = require('mongoose') +const dotenv = require('dotenv') -const url = 'mongodb://localhost/Mentors' +dotenv.config({ + path:'./config/.env' +}) + +const url = process.env.DEVELOPMENT_DB_URL mongoose.connect(url,{ useNewUrlParser: true }); mongoose.set('useCreateIndex', true) app.listen(3000, () => @@ -14,40 +19,40 @@ app.listen(3000, () => ); app.use(bodyParser.json()) -app.use(passport.initialize()) -app.use(passport.session()) +// app.use(passport.initialize()) +// app.use(passport.session()) app.use('/mentors/', signup) // app.use('/mentors/', login) -app.use(require('express-session')({ - secret: 'keyboard cat', - resave: true, - saveUninitialized: true -})); - -passport.use( - new LinkedInStrategy({ - consumerKey: '81v2h99m8u3lpl', - consumerSecret: '1xOrOAQQp3hJhUGZ', - callbackURL: "/auth/linkedin/callback", - profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline'] - }, - function(token, tokenSecret, profile, done) { - process.nextTick( () => { - console.log(profile); - return done(null, profile); - }); - } -)); - -app.get('/auth/linkedin', - passport.authenticate('linkedin', { scope: ['r_basicprofile', 'r_emailaddress'] }) - ); - -app.get('/auth/linkedin/callback', - passport.authenticate('linkedin'), - (req, res) => { - res.send("You are redirected successfully."); - }); +// app.use(require('express-session')({ +// secret: 'keyboard cat', +// resave: true, +// saveUninitialized: true +// })); + +// passport.use( +// new LinkedInStrategy({ +// consumerKey: '81v2h99m8u3lpl', +// consumerSecret: '1xOrOAQQp3hJhUGZ', +// callbackURL: "/auth/linkedin/callback", +// profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline'] +// }, +// function(token, tokenSecret, profile, done) { +// process.nextTick( () => { +// console.log(profile); +// return done(null, profile); +// }); +// } +// )); + +// app.get('/auth/linkedin', +// passport.authenticate('linkedin', { scope: ['r_basicprofile', 'r_emailaddress'] }) +// ); + +// app.get('/auth/linkedin/callback', +// passport.authenticate('linkedin'), +// (req, res) => { +// res.send("You are redirected successfully."); +// }); diff --git a/models/user.js b/models/user.js index 80e6e6a..1e3fc9b 100644 --- a/models/user.js +++ b/models/user.js @@ -1,7 +1,10 @@ const mongoose = require('mongoose') module.exports = mongoose.model('User', mongoose.Schema({ name: {type:String, required:true}, - email: {type:String, required:true, unique:true}, - password : {type:String, required:true} + email: {type:String, required:true, unique:true, + match : /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/}, + password : {type:String, required:true, + match:/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})/}, + refreshToken : {type:Array} })) diff --git a/package-lock.json b/package-lock.json index 24a92fe..90ee24e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -587,6 +587,11 @@ "is-obj": "^1.0.0" } }, + "dotenv": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz", + "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -974,8 +979,7 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", @@ -983,8 +987,7 @@ }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -1087,8 +1090,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -1098,7 +1100,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1210,8 +1211,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -1326,7 +1326,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/package.json b/package.json index dd0fdbb..ad77166 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "bcrypt": "^3.0.6", "body-parser": "^1.19.0", + "dotenv": "^8.0.0", "express": "^4.16.4", "express-session": "^1.16.1", "jsonwebtoken": "^8.5.1", diff --git a/public/signup.html b/public/signup.html deleted file mode 100644 index c507e32..0000000 --- a/public/signup.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - Signup - - -
- Name : - Email : - Password : - -
- - \ No newline at end of file diff --git a/routes/signUpRoute.js b/routes/signUpRoute.js index 1d465cc..bc2a6fd 100644 --- a/routes/signUpRoute.js +++ b/routes/signUpRoute.js @@ -2,41 +2,47 @@ const User = require('../models/user') const router = require('express').Router() const jwt = require('jsonwebtoken') const bcrypt = require('bcrypt') +const secretKey = require('../config/secretKey') +const errorMsg = require('../config/errorMsg') +const statusCode = require('../config/statusCode') const tokenList = {} -router.get('/signup',(req,res) =>{ - res.sendFile('../public/signup.html') -}); - -router.post('/signup', (req,res)=>{ - const user = User.findOne({email:req.body.email}) - if(user.length>=1) { - return res.status(403).json('User Already exists') +router.post('/signup', async(req,res)=>{ + const user = await User.findOne({email:req.body.email}) + if(user) { + return res.status(statusCode.forbidden.code).json(errorMsg.user_exists.message) } else{ //hash with salting add random string - bcrypt.hash(req.body.password, 10, (err,hash) =>{ + bcrypt.hash(req.body.password, 10, async(err,hash) =>{ if(err){ - return res.status(500).json({ - error:err + return res.status(statusCode.forbidden.code).json({ + error:errorMsg.forbidden.message }); } else{ - const user = new User({ - name: req.body.name, - email: req.body.email, - password: hash - }); - user.save() - const token = jwt.sign({user : user}, 'secretkey', { expiresIn: '24h' }) - const refreshToken = jwt.sign({user:user},'secretkey123',{expiresIn: '30d'}) - const response = { - "status": "Logged in", - "token": token, - "refreshToken": refreshToken, + const token = jwt.sign({name : req.body.name, email: req.body.email}, secretKey.token.key, { expiresIn: '24h' }) + const refreshToken = await jwt.sign({name : req.body.name, email: req.body.email},secretKey.token.key,{expiresIn: '30d'}) + try{ + const user = new User({ + name: req.body.name, + email: req.body.email, + password: hash, + refreshToken : refreshToken + }) + user.save() + const response = { + "status": "Logged in", + "token": token, + "refreshToken": refreshToken, + } + tokenList[refreshToken] = response + res.status(statusCode.ok.code).json({data : user, tokenResponse: response}) + } + catch(err){ + next(err) + res.json(err) } - tokenList[refreshToken] = response - res.json({data : user, tokenResponse: response}) } }) } @@ -45,8 +51,8 @@ router.post('/signup', (req,res)=>{ router.post('/users', verifyToken, (req,res)=>{ const bearerHeader = req.headers['authorization']; - jwt.verify(req.token,'secretkey', (err,authData)=>{ - if(err) res.status(403).json(err) + jwt.verify(req.token,secretKey.token.key, (err,authData)=>{ + if(err) res.status(statusCode.forbidden.code).json(errorMsg.forbidden.message) else{ res.json({ message: 'OK good', @@ -59,43 +65,61 @@ router.post('/users', verifyToken, (req,res)=>{ router.post('/login',async(req,res) => { let user = await User.findOne({email: req.body.email}) - if(!user) res.json({message:'Auth failed'}) - bcrypt.compare(req.body.password, user.password ,(err,result)=>{ - if(err) { - res.status(403).json({message:'Auth failed'}) + if(!user) res.json({message:errorMsg.auth_fail}) + var result = await bcrypt.compare(req.body.password, user.password) + if(!result) { + return res.status(statusCode.forbidden.code).json({message:errorMsg.forbidden.message}) + } + if(result) { + const token = jwt.sign({name : req.body.name, email: req.body.email}, secretKey.token.key, { expiresIn: '24h' }) + const refreshToken = jwt.sign({name : req.body.name, email: req.body.email},secretKey.token.key,{expiresIn: '30d'}) + const response = { + "status": "Logged in", + "token": token, + "refreshToken": refreshToken, } - if(result) { - const token = jwt.sign({user : user}, 'secretkey', { expiresIn: '24h' }) - const refreshToken = jwt.sign({user:user},'secretkey123',{expiresIn: '30d'}) - const response = { - "status": "Logged in", - "token": token, - "refreshToken": refreshToken, - } - tokenList[refreshToken] = response - res.json(response); + await User.updateOne({'email' : req.body.email }, + { $push: { 'refreshToken' : refreshToken } }) + tokenList[refreshToken] = response + res.status(statusCode.ok.code).json(response); + } +}) + + +router.post('/logout', verifyToken, async(req,res)=>{ + let user = await User.findOne({refreshToken:req.header}) + jwt.verify(req.token,secretKey.token.key, async(err,authData)=>{ + if(err){ + res.status(statusCode.forbidden.code).json(errorMsg.forbidden.message) + } + else{ + await User.updateOne({refreshToken : req.body.refreshToken }, + { $pull: { 'refreshToken' : req.body.refreshToken } }) + res.status(statusCode.ok.code).json({message : errorMsg.ok.message}) + } }) }) + router.post('/token', async (req,res) => { // refresh the token let user = await User.findOne({email: req.body.email}) - if(!user) res.json({message:'Auth failed'}) + if(!user) res.json({message:errorMsg.user_exists.message}) bcrypt.compare(req.body.password, user.password ,(err,result)=>{ - if(err) { - res.status(403).json({message:'Auth failed'}) + if(!result) { + res.status(statusCode.forbidden.code).json({message:errorMsg.forbidden.message}) } if(result) { // if refresh token exists if((req.body.refreshToken) && (req.body.refreshToken in tokenList)) { - const token = jwt.sign({user: user}, 'secretkey', { expiresIn: '24h'}) + const token = jwt.sign({name : req.body.name, email: req.body.email}, secretKey.token.key, { expiresIn: '24h'}) // update the token in the list tokenList[req.body.refreshToken].token = token - res.json({token:token}); + res.status(statusCode.ok.code).json({token:token}); } else { - res.json('Invalid request') + res.json(errorMsg.invalid.message) } } }) @@ -116,7 +140,7 @@ function verifyToken(req,res,next){ next(); } else{ - res.sendStatus(403); + res.sendStatus(statusCode.forbidden.code); } } From ab2367efebef8b69dd8fcab62c8b20eb1fc51d32 Mon Sep 17 00:00:00 2001 From: AwaleRohin Date: Thu, 16 May 2019 10:28:14 +0545 Subject: [PATCH 02/25] some changes --- config/errorMsg.js | 7 ++-- index.js | 38 +-------------------- routes/signUpRoute.js | 78 +++++++++++-------------------------------- 3 files changed, 24 insertions(+), 99 deletions(-) diff --git a/config/errorMsg.js b/config/errorMsg.js index 26ad29c..310d856 100644 --- a/config/errorMsg.js +++ b/config/errorMsg.js @@ -16,7 +16,8 @@ module.exports={ }, ok : { message : 'Ok' - } - - + }, + ref_token : { + message : 'Invalid Refresh Token' + }, } \ No newline at end of file diff --git a/index.js b/index.js index 16d39e8..6147e11 100644 --- a/index.js +++ b/index.js @@ -19,40 +19,4 @@ app.listen(3000, () => ); app.use(bodyParser.json()) -// app.use(passport.initialize()) -// app.use(passport.session()) -app.use('/mentors/', signup) -// app.use('/mentors/', login) - - - -// app.use(require('express-session')({ -// secret: 'keyboard cat', -// resave: true, -// saveUninitialized: true -// })); - -// passport.use( -// new LinkedInStrategy({ -// consumerKey: '81v2h99m8u3lpl', -// consumerSecret: '1xOrOAQQp3hJhUGZ', -// callbackURL: "/auth/linkedin/callback", -// profileFields: ['id', 'first-name', 'last-name', 'email-address', 'headline'] -// }, -// function(token, tokenSecret, profile, done) { -// process.nextTick( () => { -// console.log(profile); -// return done(null, profile); -// }); -// } -// )); - -// app.get('/auth/linkedin', -// passport.authenticate('linkedin', { scope: ['r_basicprofile', 'r_emailaddress'] }) -// ); - -// app.get('/auth/linkedin/callback', -// passport.authenticate('linkedin'), -// (req, res) => { -// res.send("You are redirected successfully."); -// }); +app.use('/mentors/', signup) \ No newline at end of file diff --git a/routes/signUpRoute.js b/routes/signUpRoute.js index bc2a6fd..b554577 100644 --- a/routes/signUpRoute.js +++ b/routes/signUpRoute.js @@ -5,7 +5,6 @@ const bcrypt = require('bcrypt') const secretKey = require('../config/secretKey') const errorMsg = require('../config/errorMsg') const statusCode = require('../config/statusCode') -const tokenList = {} router.post('/signup', async(req,res)=>{ const user = await User.findOne({email:req.body.email}) @@ -62,67 +61,28 @@ router.post('/users', verifyToken, (req,res)=>{ }) }) - -router.post('/login',async(req,res) => { - let user = await User.findOne({email: req.body.email}) - if(!user) res.json({message:errorMsg.auth_fail}) - var result = await bcrypt.compare(req.body.password, user.password) - if(!result) { - return res.status(statusCode.forbidden.code).json({message:errorMsg.forbidden.message}) - } - if(result) { - const token = jwt.sign({name : req.body.name, email: req.body.email}, secretKey.token.key, { expiresIn: '24h' }) - const refreshToken = jwt.sign({name : req.body.name, email: req.body.email},secretKey.token.key,{expiresIn: '30d'}) - const response = { - "status": "Logged in", - "token": token, - "refreshToken": refreshToken, - } - await User.updateOne({'email' : req.body.email }, - { $push: { 'refreshToken' : refreshToken } }) - tokenList[refreshToken] = response - res.status(statusCode.ok.code).json(response); - } -}) - - -router.post('/logout', verifyToken, async(req,res)=>{ - let user = await User.findOne({refreshToken:req.header}) - jwt.verify(req.token,secretKey.token.key, async(err,authData)=>{ - if(err){ - res.status(statusCode.forbidden.code).json(errorMsg.forbidden.message) - } - else{ - await User.updateOne({refreshToken : req.body.refreshToken }, - { $pull: { 'refreshToken' : req.body.refreshToken } }) - res.status(statusCode.ok.code).json({message : errorMsg.ok.message}) - - } - }) -}) - - router.post('/token', async (req,res) => { // refresh the token - let user = await User.findOne({email: req.body.email}) - if(!user) res.json({message:errorMsg.user_exists.message}) - bcrypt.compare(req.body.password, user.password ,(err,result)=>{ - if(!result) { - res.status(statusCode.forbidden.code).json({message:errorMsg.forbidden.message}) - } - if(result) { - // if refresh token exists - if((req.body.refreshToken) && (req.body.refreshToken in tokenList)) { - const token = jwt.sign({name : req.body.name, email: req.body.email}, secretKey.token.key, { expiresIn: '24h'}) - // update the token in the list - tokenList[req.body.refreshToken].token = token - res.status(statusCode.ok.code).json({token:token}); - } - else { - res.json(errorMsg.invalid.message) + let user = await User.findOne({refreshToken: req.body.refreshToken}) + if(!user) res.json({message:errorMsg.ref_token.message}) + if(user){ + bcrypt.compare(req.body.password, user.password ,(err,result)=>{ + if(!result) { + res.status(statusCode.forbidden.code).json({message:errorMsg.forbidden.message}) } - } - }) + if(result) { + // if refresh token exists + if(req.body.refreshToken) { + const token = jwt.sign({name : req.body.name, email: req.body.email}, secretKey.token.key, { expiresIn: '24h'}) + // update the token in the list + res.status(statusCode.ok.code).json({token:token}); + } + else { + res.json(errorMsg.invalid.message) + } + } + }) + } }) function verifyToken(req,res,next){ From e4d254dd32d4fbe1553c7cbf51ddbc5dff942529 Mon Sep 17 00:00:00 2001 From: AwaleRohin Date: Thu, 23 May 2019 11:29:36 +0545 Subject: [PATCH 03/25] fixes: code rendered --- config/secretKey.js | 4 ++ config/statusMsg.js | 19 ++++---- controller/loginController.js | 74 ++++++++++++++++------------- controller/signUpController.js | 86 +++++++++++++++++----------------- models/user.js | 1 + routes/signUpRoute.js | 2 +- 6 files changed, 102 insertions(+), 84 deletions(-) diff --git a/config/secretKey.js b/config/secretKey.js index 181c693..1b65624 100644 --- a/config/secretKey.js +++ b/config/secretKey.js @@ -2,4 +2,8 @@ module.exports= { token : { key : 'secret' }, + facebook : { + APP_ID : '507835646419191', + APP_SECRET : '8467b617c2a28a2f1611f09ba8e1c2da' + }, } \ No newline at end of file diff --git a/config/statusMsg.js b/config/statusMsg.js index 636a12a..315c476 100644 --- a/config/statusMsg.js +++ b/config/statusMsg.js @@ -1,11 +1,14 @@ -module.exports= { - success : { - msg : "Success" +module.exports = { + success: { + msg: "Success" }, - fail : { - msg : "Failure" + fail: { + msg: "Failure" + }, + email: { + msg: "A verification email has been sent to" + }, + token_exp: { + msg: "Token Expired" }, - email :{ - msg: 'A verification email has been sent to ' - } } \ No newline at end of file diff --git a/controller/loginController.js b/controller/loginController.js index 9a3e9b8..1a5074c 100644 --- a/controller/loginController.js +++ b/controller/loginController.js @@ -10,60 +10,68 @@ dotenv.config({ }) exports.login = async (req, res) => { - let user = await User.findOne({ email: req.body.email }) - if (!user) return res.status(http.BAD_REQUEST).json({ "status": http.BAD_REQUEST, "message": http.getStatusText(http.BAD_REQUEST) }) - let result = await bcrypt.compare(req.body.password, user.password) - if (!result) { - return res.status(http.CONFLICT).json({ "status": http.CONFLICT, "message": http.getStatusText(http.CONFLICT) }) - } - if (user.verified_email) { - const access_token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) - const refresh_token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.refresh_token_exp }) - const response = { - "status": statusMsg.success.msg, - "accessToken": access_token, - "refreshToken": refresh_token, - "data": user + try { + let user = await User.findOne({ email: req.body.email }) + if (!user) return res.status(http.BAD_REQUEST).json({ "status": http.BAD_REQUEST, "message": http.getStatusText(http.BAD_REQUEST) }) + let result = await bcrypt.compare(req.body.password, user.password) + if (!result) { + return res.status(http.CONFLICT).json({ "status": http.CONFLICT, "message": http.getStatusText(http.CONFLICT) }) } - try { + if (user.verified_email) { + const access_token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) + const refresh_token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.refresh_token_exp }) + const response = { + "status": statusMsg.success.msg, + "accessToken": access_token, + "refreshToken": refresh_token, + "data": user + } await user.refresh_token.push(refresh_token) await user.save() + res.status(http.OK).json(response); } - catch (err) { - res.status(http.NOT_MODIFIED).json(http.getStatusText(http.NOT_MODIFIED)) + else { + res.status(http.CONFLICT).json({ status: statusMsg.fail.msg, message: http.getStatusText(http.CONFLICT) }) } - res.status(http.OK).json(response); } - else { - res.status(http.CONFLICT).json({ status: statusMsg.fail.msg, message: http.getStatusText(http.CONFLICT) }) + catch (err) { + res.status(http.FORBIDDEN).json({ "message": err.message }) + next(err) } } exports.refreshToken = async (req, res) => { - let user = await User.findOne({ refresh_token: req.body.refresh_token }) - if (!user) return res.json({ message: http.getStatusText(http.UNAUTHORIZED) }) - let result = await bcrypt.compare(req.body.password, user.password) - if (!result) { - return res.status(http.CONFLICT).json({ message: http.getStatusText(http.CONFLICT) }) - } - if (req.body.refresh_token) { - const token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) - res.status(http.OK).json({ status: statusMsg.success.msg, token: token }); + try { + let user = await User.findOne({ refresh_token: req.body.refresh_token }) + if (!user) return res.status(http.UNAUTHORIZED).json({ message: http.getStatusText(http.UNAUTHORIZED) }) + let result = await bcrypt.compare(req.body.password, user.password) + if (!result) { + return res.status(http.CONFLICT).json({ message: http.getStatusText(http.CONFLICT) }) + } + if (req.body.refresh_token) { + const token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) + res.status(http.OK).json({ status: statusMsg.success.msg, token: token }); + } + else { + res.status(http.FORBIDDEN).json({ status: statusMsg.fail.msg, message: http.getStatusText(http.FORBIDDEN) }) + } } - else { - res.status(http.FORBIDDEN).json({ status: statusMsg.fail.msg, message: http.getStatusText(http.FORBIDDEN) }) + catch (err) { + res.status(htpp.FORBIDDEN).json({ "message": err.message }) + next(err) } } exports.logout = async (req, res) => { - let user = await User.findOne({ refresh_token: req.body.refresh_token }) try { + let user = await User.findOne({ refresh_token: req.body.refresh_token }) let decoded = await jwt.verify(req.token, secretKey.token.key) await user.refresh_token.pull(req.body.refresh_token) await user.save() res.status(http.OK).json({ message: http.getStatusText(http.OK) }) } catch (err) { - res.status(http.FORBIDDEN).json(http.getStatusText(http.FORBIDDEN)) + res.status(http.FORBIDDEN).json({ "message": err.message }) + next(err) } } \ No newline at end of file diff --git a/controller/signUpController.js b/controller/signUpController.js index 553ce4d..15567c0 100644 --- a/controller/signUpController.js +++ b/controller/signUpController.js @@ -18,64 +18,66 @@ exports.create = async (req, res, next) => { if (!errors.isEmpty()) { return res.status(http.UNPROCESSABLE_ENTITY).json({ errors: errors.array() }); } - let hash = await bcrypt.hash(req.body.password, SALTING) - const access_token = await jwt.sign({ email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) - const refresh_token = await jwt.sign({ email: req.body.email }, secretKey.token.key, { expiresIn: process.env.refresh_token_exp }) - const user = new User({ - first_name: req.body.first_name, - last_name: req.body.last_name, - email: req.body.email, - password: hash, - refresh_token: refresh_token - }) try { + let hash = await bcrypt.hash(req.body.password, SALTING) + const access_token = await jwt.sign({ email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) + const refresh_token = await jwt.sign({ email: req.body.email }, secretKey.token.key, { expiresIn: process.env.refresh_token_exp }) + const user = new User({ + first_name: req.body.first_name, + last_name: req.body.last_name, + email: req.body.email, + password: hash, + refresh_token: refresh_token + }) await user.save() host = req.get('host') await email_verify.verifyEmail(user.email, host, access_token) + const response = { + "status": statusMsg.success.msg, + "accessToken": access_token, + "data": user, + "message": statusMsg.email.msg + user.email + '.' + } + res.status(http.CREATED).json({ response }) } catch (err) { - console.log(err) - if (err) { return res.status(http.INTERNAL_SERVER_ERROR).send({ msg: http.getStatusText(http.INTERNAL_SERVER_ERROR) }); } - } - const response = { - "status": statusMsg.success.msg, - "accessToken": access_token, - "data": user, - "message": statusMsg.email.msg + user.email + '.' + res.status(http.CONFLICT).json({ "message": err.message }) + next(err) } - res.status(http.CREATED).json({ response }) } exports.confirmation = async (req, res) => { - if (req.query.token) { - try { + try { + if (req.query.token) { decoded = await jwt.verify(req.query.token, secretKey.token.key); - } - catch (e) { - return res.status(http.UNAUTHORIZED).json({ message: http.getStatusText(http.UNAUTHORIZED) }); - } - const email = decoded.email; - let user = await User.findOne({ email: email }) - if (!user) return res.status(http.BAD_REQUEST).send({ status: statusMsg.fail.msg, msg: http.getStatusText(http.BAD_REQUEST) }); - if (user.verified_email) return res.status(http.CONFLICT).send({ status: statusMsg.fail.msg, msg: http.getStatusText(http.CONFLICT) }); - user.verified_email = true - try { + const email = decoded.email; + let user = await User.findOne({ email: email }) + if (!user) return res.status(http.BAD_REQUEST).send({ status: statusMsg.fail.msg, msg: http.getStatusText(http.BAD_REQUEST) }); + if (user.verified_email) return res.status(http.CONFLICT).send({ status: statusMsg.fail.msg, msg: http.getStatusText(http.CONFLICT) }); + user.verified_email = true await user.save() + res.status(http.OK).send({ status: statusMsg.success.msg, message: http.getStatusText(http.OK) }); } - catch (err) { - if (err) { return res.status(http.INTERNAL_SERVER_ERROR).send({ msg: http.getStatusText(http.INTERNAL_SERVER_ERROR) }); } - } - console.log(user) - res.status(http.OK).send({ status: statusMsg.success.msg, message: http.getStatusText(http.OK) }); } + catch (err) { + res.status(http.UNAUTHORIZED).json({ message: err.message }); + next(err) + } + } exports.resendToken = async (req, res) => { - let user = await User.findOne({ email: req.body.email }) - if (!user) return res.status(http.NOT_FOUND).json({ status: statusMsg.fail.msg, msg: http.getStatusText(http.NOT_FOUND) }); - if (user.verified_email) return res.status(http.BAD_REQUEST).json({ status: statusMsg.fail.msg, msg: http.getStatusText(http.BAD_REQUEST) }); - const token = await jwt.sign({ email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) - host = req.get('host'); - await email_verify.verifyEmail(user.email, host, token) + try { + let user = await User.findOne({ email: req.body.email }) + if (!user) return res.status(http.FORBIDDEN).json({ status: statusMsg.fail.msg, msg: http.getStatusText(http.FORBIDDEN) }); + if (user.verified_email) return res.status(http.BAD_REQUEST).json({ status: statusMsg.fail.msg, msg: http.getStatusText(http.BAD_REQUEST) }); + const token = await jwt.sign({ email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) + host = req.get('host'); + await email_verify.verifyEmail(user.email, host, token) + } + catch (err) { + res.status(http.UNAUTHORIZED).json({ "message": err.message }) + next(err) + } } \ No newline at end of file diff --git a/models/user.js b/models/user.js index a1fc2f7..7dc44b1 100644 --- a/models/user.js +++ b/models/user.js @@ -8,6 +8,7 @@ var schema = mongoose.Schema({ phone : {type:Number}, address : {type:String}, user_role : {type:String}, + social_id : String, verified_email : {type: Boolean, default: false}, refresh_token : {type:Array,required:true}, }) diff --git a/routes/signUpRoute.js b/routes/signUpRoute.js index dce9d84..067af29 100644 --- a/routes/signUpRoute.js +++ b/routes/signUpRoute.js @@ -13,6 +13,6 @@ router.route('/confirmation').get(Register.confirmation) router.route('/resendToken').post(Register.resendToken) router.route('/login').post(Login.login) router.route('/refreshToken').post(Login.refreshToken) -router.route('/logout').post(jwtValidation.verifyToken,Login.logout) +router.route('/logout').post(jwtValidation.verifyToken, Login.logout) module.exports = router; \ No newline at end of file From efd1b2e5bc3ceaf8727da9da23d5a192c897daca Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Thu, 23 May 2019 12:30:22 +0545 Subject: [PATCH 04/25] Route for google auth --- routes/socialAuth.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 routes/socialAuth.js diff --git a/routes/socialAuth.js b/routes/socialAuth.js new file mode 100644 index 0000000..b7fe5ee --- /dev/null +++ b/routes/socialAuth.js @@ -0,0 +1,19 @@ +//Dependencies +require('dotenv').config({ + path: 'variables.env' +}); +const express = require('express'); +const dbQuery = require('./mongoQuery'); +const cors = require('cors'); +const bodyParser = require('body-parser'); + +//Config +const app = express(); +app.use(cors()); + +app.post('/auth/google', (req, res) => { + let userInfo = oauth.getUserInfo(req.body.accessToken); + res.status(200).send('Ok'); +}); + +module.exports = app; From af9e5a813988cb70a77760b0ba13a439aa3fa72c Mon Sep 17 00:00:00 2001 From: AwaleRohin Date: Thu, 23 May 2019 13:21:21 +0545 Subject: [PATCH 05/25] fixes: code rendered --- .gitignore | 2 +- config/secretKey.js | 9 --------- models/user.js | 5 ++--- 3 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 config/secretKey.js diff --git a/.gitignore b/.gitignore index fc7ab7c..0091507 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,4 @@ typings/ # next.js build output .next -secretKey.js \ No newline at end of file +secretKey.js diff --git a/config/secretKey.js b/config/secretKey.js deleted file mode 100644 index 1b65624..0000000 --- a/config/secretKey.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports= { - token : { - key : 'secret' - }, - facebook : { - APP_ID : '507835646419191', - APP_SECRET : '8467b617c2a28a2f1611f09ba8e1c2da' - }, -} \ No newline at end of file diff --git a/models/user.js b/models/user.js index 7dc44b1..d0c62fb 100644 --- a/models/user.js +++ b/models/user.js @@ -8,7 +8,7 @@ var schema = mongoose.Schema({ phone : {type:Number}, address : {type:String}, user_role : {type:String}, - social_id : String, + facebook_id : String, verified_email : {type: Boolean, default: false}, refresh_token : {type:Array,required:true}, }) @@ -18,5 +18,4 @@ schema.methods.toJSON = function () { delete obj.refresh_token return obj } -module.exports = mongoose.model("User", schema) - +module.exports = mongoose.model("User", schema) \ No newline at end of file From f0ec63e5e78f6b289d23edb80a04619c1e0bae95 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Thu, 23 May 2019 14:22:05 +0545 Subject: [PATCH 06/25] getinfo using promises --- controller/oauth.js | 60 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 controller/oauth.js diff --git a/controller/oauth.js b/controller/oauth.js new file mode 100644 index 0000000..50bf336 --- /dev/null +++ b/controller/oauth.js @@ -0,0 +1,60 @@ +require('dotenv').config({ + path: '../config/variables.env' +}); + +const googleOAuth = require('../controller/googleOAuth'); +const mongoose = require('mongoose'); +const User = require('../models/user'); + +const gAuthStatus = (googleToken) => { + googleOAuth.getUserInfo(googleToken) + .then(response => { + userinfo = response.data; + //check if it already exists + User.findOne({ google_id: userinfo.id }, (err, data) => { + if (data === null) { + return 200; + } else { + return 404; + //checkifEmailExists() + } + // //update with the google id, if the the email associated already exists + // } else { + // //create a new record with the new info + // } + }); + }); +}; + +// const checkifEmailExists = (userinfo) { +// User.findOne({ email: userinfo.email }, (err, data) { +// if (data.length) { +// User.findOneAndUpdate({google_id: userinfo.id}, {email: userinfo.email}, {upsert:true}, (err, doc) => { +// // if (err) return res.send(500, { error: err }); +// // return res.send("succesfully saved"); +// // }); +// } else { +// //create a new record with the new info +// } +// }); +// } + + +// user = { +// first_name: userinfo.given_name, +// last_name: +// email: + +// } + + +// User.create((seedData, (error, addedData) => { +// if (error) { +// console.log(error); +// } else { +// console.log("Added new data", addedData); +// } +// }); + + +module.exports.getStatusCode = gAuthStatus; \ No newline at end of file From 055c5c51202afdb65a6c676bdc8b8bbb036b7b2b Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Fri, 24 May 2019 12:52:04 +0545 Subject: [PATCH 07/25] cleaned up --- config/variables.env | 3 + controller/googleOauthHandler.js | 122 +++++++++++++++++++++++++++++++ controller/oauth.js | 60 --------------- index.js | 6 +- middleware/googleOAuthClient.js | 19 +++++ models/user.js | 3 +- routes/socialAuth.js | 16 +++- 7 files changed, 163 insertions(+), 66 deletions(-) create mode 100644 config/variables.env create mode 100644 controller/googleOauthHandler.js delete mode 100644 controller/oauth.js create mode 100644 middleware/googleOAuthClient.js diff --git a/config/variables.env b/config/variables.env new file mode 100644 index 0000000..ea36395 --- /dev/null +++ b/config/variables.env @@ -0,0 +1,3 @@ +GOOGLE_CLIENT_ID = "318441039578-ghflj2cgc1g6aj02gqrg8pgd6mlf0kb2.apps.googleusercontent.com" +GOOGLE_CLIENT_SECRET = "5_j8GvsMB-_rke5x4t1n_3SH" +DEVELOPMENT_DB_URL = "mongodb://mentors:mentors21@ds257838.mlab.com:57838/mentors" \ No newline at end of file diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js new file mode 100644 index 0000000..f05661e --- /dev/null +++ b/controller/googleOauthHandler.js @@ -0,0 +1,122 @@ +require('dotenv').config({ + path: '../config/variables.env' +}); + +const jwt = require('jsonwebtoken'); +const googleOAuth = require('../middleware/googleOAuthClient'); +const User = require('../models/user'); +const secretKey = require('../config/secretKey'); + + + +module.exports.getMessage = async (googleToken) => { + try { + const response = await googleOAuth.getUserInfo(googleToken); + const userInfo = response.data; + + const token = await tokenGenerator.token(userInfo.email); + const refresh_token = await tokenGenerator.refresh_token(userInfo.email); + + try { + //If the google id already exists in the db, store nothing to the db + if (await dbQuery.idExists(userInfo)) { + return { + message: token, + statusCode: 200 + }; + } else { + //if the google email exists in the db but is not linked, link the accoints + if (await dbQuery.emailExists(userInfo)) { + await dbQuery.updateWithId(userInfo); + return { + message: token, + statusCode: 200 + }; + } else { + //otherwise, create a new account + await dbQuery.createAccount(userInfo, refresh_token); + return { + message: token, + statusCode: 201 + }; + } + } + } catch(error) { + console.log(error); + return { message:"Error connecting database", statusCode: 500} + } + } catch(error) { + console.log(error); + return { message: "BAD_REQUEST", statusCode: 400}; + } +}; + + +const tokenGenerator = { + token: async (email) => { + return await jwt.sign({ + email + }, secretKey.token.key, { + expiresIn: '24h' + }); + }, + + refresh_token: async (email) => { + return await jwt.sign({ + email + }, secretKey.token.key, { + expiresIn: `${24*7}h` + }); + } +}; + + + +const dbQuery = { + idExists: async (userInfo) => { + try { + const googleId = await User.findOne({ google_id: userInfo.id }); + if (googleId === null) { + return false; + } else { + return true; + } + } catch(error) { + console.log(error); + } + }, + emailExists: async (userInfo) => { + try { + const googleEmail = await User.findOne({ email: userInfo.email }); + if (googleEmail === null) { + return false; + } else { + return true; + } + } catch(error) { + console.log(error); + } + }, + updateWithId: async (userInfo) => { + try { + await User.findOneAndUpdate({email: userInfo.email}, {google_id: userInfo.id}); + } catch(error) { + console.log(error); + } + }, + createAccount: async (userInfo, refresh_token) => { + user = { + first_name: userInfo.given_name, + last_name : userInfo.family_name, + email: userInfo.email, + google_id: userInfo.id, + verified_email: true, + refresh_token + } + try { + User.create(user); + } catch(error) { + console.log(error); + } + } +}; \ No newline at end of file diff --git a/controller/oauth.js b/controller/oauth.js deleted file mode 100644 index 50bf336..0000000 --- a/controller/oauth.js +++ /dev/null @@ -1,60 +0,0 @@ -require('dotenv').config({ - path: '../config/variables.env' -}); - -const googleOAuth = require('../controller/googleOAuth'); -const mongoose = require('mongoose'); -const User = require('../models/user'); - -const gAuthStatus = (googleToken) => { - googleOAuth.getUserInfo(googleToken) - .then(response => { - userinfo = response.data; - //check if it already exists - User.findOne({ google_id: userinfo.id }, (err, data) => { - if (data === null) { - return 200; - } else { - return 404; - //checkifEmailExists() - } - // //update with the google id, if the the email associated already exists - // } else { - // //create a new record with the new info - // } - }); - }); -}; - -// const checkifEmailExists = (userinfo) { -// User.findOne({ email: userinfo.email }, (err, data) { -// if (data.length) { -// User.findOneAndUpdate({google_id: userinfo.id}, {email: userinfo.email}, {upsert:true}, (err, doc) => { -// // if (err) return res.send(500, { error: err }); -// // return res.send("succesfully saved"); -// // }); -// } else { -// //create a new record with the new info -// } -// }); -// } - - -// user = { -// first_name: userinfo.given_name, -// last_name: -// email: - -// } - - -// User.create((seedData, (error, addedData) => { -// if (error) { -// console.log(error); -// } else { -// console.log("Added new data", addedData); -// } -// }); - - -module.exports.getStatusCode = gAuthStatus; \ No newline at end of file diff --git a/index.js b/index.js index 81c24e3..0da5886 100644 --- a/index.js +++ b/index.js @@ -4,13 +4,16 @@ const signup = require('../mentors/routes/signUpRoute') const bodyParser = require('body-parser') const mongoose = require('mongoose') const dotenv = require('dotenv') +const socialAuth = require('../mentors/routes/socialAuth') dotenv.config({ - path: './config/.env' + path: './config/variables.env' }) const url = process.env.DEVELOPMENT_DB_URL mongoose.connect(url, { useNewUrlParser: true }); + +mongoose.set('useFindAndModify', false); mongoose.set('useCreateIndex', true) app.listen(3000, () => console.log('Hello Mentors'), @@ -20,3 +23,4 @@ app.get('/',(req,res)=>{ app.use(bodyParser.json()) app.use('/mentors/', signup) +app.use('/auth', socialAuth) diff --git a/middleware/googleOAuthClient.js b/middleware/googleOAuthClient.js new file mode 100644 index 0000000..415fca6 --- /dev/null +++ b/middleware/googleOAuthClient.js @@ -0,0 +1,19 @@ +require('dotenv').config({ + path: '../config/variables.env' +}); + +const google = require('googleapis').google; +const oauth2 = google.oauth2('v2'); +const OAuth2 = google.auth.OAuth2; + +const authClient = new OAuth2( + process.env.GOOGLE_CLIENT_ID, + process.env.GOOGLE_CLIENT_SECRET, +); + +module.exports.getUserInfo = async function (accessToken) { + authClient.setCredentials({ + access_token: accessToken + }); + return await oauth2.userinfo.get({ auth: authClient }); +}; diff --git a/models/user.js b/models/user.js index a1fc2f7..feaa1a4 100644 --- a/models/user.js +++ b/models/user.js @@ -3,7 +3,8 @@ var schema = mongoose.Schema({ first_name: {type:String, required:true}, last_name :{type:String,required:true}, email: {type:String, required:true, unique:true}, - password : {type:String, required:true}, + password : String, + google_id: Number, dob : {type:Date}, phone : {type:Number}, address : {type:String}, diff --git a/routes/socialAuth.js b/routes/socialAuth.js index b7fe5ee..af24f44 100644 --- a/routes/socialAuth.js +++ b/routes/socialAuth.js @@ -3,17 +3,25 @@ require('dotenv').config({ path: 'variables.env' }); const express = require('express'); -const dbQuery = require('./mongoQuery'); const cors = require('cors'); const bodyParser = require('body-parser'); +const googleOauthHandler = require('../controller/googleOauthHandler') //Config const app = express(); app.use(cors()); +app.use(bodyParser.json({ type: 'application/*+json' })); -app.post('/auth/google', (req, res) => { - let userInfo = oauth.getUserInfo(req.body.accessToken); - res.status(200).send('Ok'); +//Routes +app.post('/google', async (req, res) => { + try { + let googleAccessToken = req.body.accessToken; + let response = await googleOauthHandler.getMessage(googleAccessToken); + res.status(response.statusCode).send(response.message); + } catch(error) { + res.status(500).send("Internal Server Error"); + console.log("Error calling googleOauthHandler", error); + } }); module.exports = app; From 7b588a52b27fd0f2e76e498ecc4e12db08ceaa31 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Fri, 24 May 2019 13:01:09 +0545 Subject: [PATCH 08/25] Created an external module for Access Token Generator --- .gitignore | 4 ++-- controller/accessTokenGenerator.js | 22 ++++++++++++++++++++++ controller/googleOauthHandler.js | 22 +--------------------- 3 files changed, 25 insertions(+), 23 deletions(-) create mode 100644 controller/accessTokenGenerator.js diff --git a/.gitignore b/.gitignore index fc7ab7c..ba43ec8 100644 --- a/.gitignore +++ b/.gitignore @@ -56,8 +56,8 @@ typings/ # dotenv environment variables file .env - +*.env # next.js build output .next -secretKey.js \ No newline at end of file +secretKey.js diff --git a/controller/accessTokenGenerator.js b/controller/accessTokenGenerator.js new file mode 100644 index 0000000..b23b7e0 --- /dev/null +++ b/controller/accessTokenGenerator.js @@ -0,0 +1,22 @@ +const jwt = require('jsonwebtoken'); +const secretKey = require('../config/secretKey'); + +const token = async (email) => { + return await jwt.sign({ + email + }, secretKey.token.key, { + expiresIn: '24h' + }); +}; + +const refresh_token = async (email) => { + return await jwt.sign({ + email + }, secretKey.token.key, { + expiresIn: `${24*7}h` + }); +}; + +module.exports = { + token, refresh_token +}; \ No newline at end of file diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index f05661e..3400be2 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -2,10 +2,9 @@ require('dotenv').config({ path: '../config/variables.env' }); -const jwt = require('jsonwebtoken'); const googleOAuth = require('../middleware/googleOAuthClient'); const User = require('../models/user'); -const secretKey = require('../config/secretKey'); +const tokenGenerator = require('./accessTokenGenerator'); @@ -52,25 +51,6 @@ module.exports.getMessage = async (googleToken) => { }; -const tokenGenerator = { - token: async (email) => { - return await jwt.sign({ - email - }, secretKey.token.key, { - expiresIn: '24h' - }); - }, - - refresh_token: async (email) => { - return await jwt.sign({ - email - }, secretKey.token.key, { - expiresIn: `${24*7}h` - }); - } -}; - - const dbQuery = { idExists: async (userInfo) => { From 3ca1affb2d13fe5e63d9c1f80b35480ac55bb143 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Fri, 24 May 2019 14:15:41 +0545 Subject: [PATCH 09/25] Added googleapis to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0fcd679..d80bf1f 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "express": "^4.16.4", "express-session": "^1.16.1", "express-validator": "^5.3.1", + "googleapis": "^40.0.0", "http-status-codes": "^1.3.2", "jsonwebtoken": "^8.5.1", "mongo": "^0.1.0", From 5dc58ec542c7454bc3fa5e357ef2d95fd41e88bc Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Sat, 25 May 2019 22:40:29 +0545 Subject: [PATCH 10/25] Added variables.env to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6dc285a..accd1fd 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,8 @@ typings/ # dotenv environment variables file .env *.env +config/variables.env + # next.js build output .next From 9b0b8044544161792e36ddd1eb2e3d578d7eb481 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Sat, 25 May 2019 22:42:01 +0545 Subject: [PATCH 11/25] Removed variables.env --- config/variables.env | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 config/variables.env diff --git a/config/variables.env b/config/variables.env deleted file mode 100644 index ea36395..0000000 --- a/config/variables.env +++ /dev/null @@ -1,3 +0,0 @@ -GOOGLE_CLIENT_ID = "318441039578-ghflj2cgc1g6aj02gqrg8pgd6mlf0kb2.apps.googleusercontent.com" -GOOGLE_CLIENT_SECRET = "5_j8GvsMB-_rke5x4t1n_3SH" -DEVELOPMENT_DB_URL = "mongodb://mentors:mentors21@ds257838.mlab.com:57838/mentors" \ No newline at end of file From c2b0fc7608ee865636b65da879ff65a83bf038e1 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Sat, 25 May 2019 23:05:16 +0545 Subject: [PATCH 12/25] Fixed typos --- controller/googleOauthHandler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index 3400be2..e7aff58 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -24,7 +24,7 @@ module.exports.getMessage = async (googleToken) => { statusCode: 200 }; } else { - //if the google email exists in the db but is not linked, link the accoints + //if the google email exists in the db but is not linked, link the accounts if (await dbQuery.emailExists(userInfo)) { await dbQuery.updateWithId(userInfo); return { @@ -85,7 +85,7 @@ const dbQuery = { } }, createAccount: async (userInfo, refresh_token) => { - user = { + let user = { first_name: userInfo.given_name, last_name : userInfo.family_name, email: userInfo.email, From cdb0fa1450ac72c8c99561549857cd646225f525 Mon Sep 17 00:00:00 2001 From: AwaleRohin Date: Sun, 26 May 2019 10:35:22 +0545 Subject: [PATCH 13/25] fixes:error handler created --- .gitignore | 2 +- config/secretKey.js.example | 5 +++ config/statusMsg.js | 21 ++++++++++-- controller/emailVerify.js | 6 ++-- controller/loginController.js | 60 ++++++++++++++++++++++++---------- controller/signUpController.js | 58 ++++++++++++++++++++------------ email/mentors/html.pug | 14 ++++++-- index.js | 3 ++ middleware/errorHandler.js | 55 +++++++++++++++++++++++++++++++ routes/signUpRoute.js | 2 +- 10 files changed, 178 insertions(+), 48 deletions(-) create mode 100644 config/secretKey.js.example create mode 100644 middleware/errorHandler.js diff --git a/.gitignore b/.gitignore index 0091507..fc7ab7c 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,4 @@ typings/ # next.js build output .next -secretKey.js +secretKey.js \ No newline at end of file diff --git a/config/secretKey.js.example b/config/secretKey.js.example new file mode 100644 index 0000000..1f957bd --- /dev/null +++ b/config/secretKey.js.example @@ -0,0 +1,5 @@ +module.exports= { + token : { + key : 'keys' + }, +} \ No newline at end of file diff --git a/config/statusMsg.js b/config/statusMsg.js index 315c476..7bf5db5 100644 --- a/config/statusMsg.js +++ b/config/statusMsg.js @@ -1,14 +1,29 @@ module.exports = { success: { - msg: "Success" + msg: "true" }, fail: { - msg: "Failure" + msg: "false" }, email: { - msg: "A verification email has been sent to" + msg: "A verification email has been sent to " }, token_exp: { msg: "Token Expired" }, + no_user:{ + msg: "User not found" + }, + not_verified: { + msg: "User is not verified" + }, + password_not_match: { + msg: "Invalid Password" + }, + error: { + msg: "Some error" + }, + email_verfied: { + msg: "Email already verified" + }, } \ No newline at end of file diff --git a/controller/emailVerify.js b/controller/emailVerify.js index 63d6eba..b086cb0 100644 --- a/controller/emailVerify.js +++ b/controller/emailVerify.js @@ -1,7 +1,7 @@ const nodemailer = require('nodemailer') const path = require('path'); var EmailTemplate = require('email-templates'); -exports.verifyEmail = async (email, host, token) => { +exports.verifyEmail = async (email, name, host, token) => { let transporter = nodemailer.createTransport({ service: process.env.GMAIL_SERVICE, port: process.env.PORT, @@ -19,9 +19,11 @@ exports.verifyEmail = async (email, host, token) => { emails.send({ template: path.join(__dirname, '..', 'email', 'mentors'), message: { - to: email + to: email, + subject: "Account Verification" }, locals: { + name: name, host: host, token: token } diff --git a/controller/loginController.js b/controller/loginController.js index 1a5074c..6da682d 100644 --- a/controller/loginController.js +++ b/controller/loginController.js @@ -9,69 +9,93 @@ dotenv.config({ path: './config/.env' }) -exports.login = async (req, res) => { +exports.login = async (req, res, next) => { try { let user = await User.findOne({ email: req.body.email }) - if (!user) return res.status(http.BAD_REQUEST).json({ "status": http.BAD_REQUEST, "message": http.getStatusText(http.BAD_REQUEST) }) + console.log(user) + if (!user) { + let err = new Error() + err.status = http.BAD_REQUEST + return next(err) + } let result = await bcrypt.compare(req.body.password, user.password) if (!result) { - return res.status(http.CONFLICT).json({ "status": http.CONFLICT, "message": http.getStatusText(http.CONFLICT) }) + return res.status(http.CONFLICT).json({ + "success": statusMsg.fail.msg, + "payload": { email: req.body.email }, + "error": { + "code": http.CONFLICT, + "message": statusMsg.password_not_match.msg + } + }) } if (user.verified_email) { const access_token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) const refresh_token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.refresh_token_exp }) const response = { - "status": statusMsg.success.msg, "accessToken": access_token, "refreshToken": refresh_token, "data": user } await user.refresh_token.push(refresh_token) await user.save() - res.status(http.OK).json(response); + res.status(http.OK).json({ + "success": statusMsg.success.msg, + "payload": response + }) } else { - res.status(http.CONFLICT).json({ status: statusMsg.fail.msg, message: http.getStatusText(http.CONFLICT) }) + let err =new Error() + err.status= http.CONFLICT + return next(err) } } catch (err) { - res.status(http.FORBIDDEN).json({ "message": err.message }) + err.status = http.FORBIDDEN next(err) } } -exports.refreshToken = async (req, res) => { +exports.refreshToken = async (req, res, next) => { try { let user = await User.findOne({ refresh_token: req.body.refresh_token }) - if (!user) return res.status(http.UNAUTHORIZED).json({ message: http.getStatusText(http.UNAUTHORIZED) }) - let result = await bcrypt.compare(req.body.password, user.password) - if (!result) { - return res.status(http.CONFLICT).json({ message: http.getStatusText(http.CONFLICT) }) + if (!user) { + let err = new Error() + err.status = http.BAD_REQUEST + return next(err) } if (req.body.refresh_token) { const token = await jwt.sign({ name: req.body.name, email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) - res.status(http.OK).json({ status: statusMsg.success.msg, token: token }); + res.status(http.OK).json({ + "success": statusMsg.success.msg, + "payload": token + }) } else { - res.status(http.FORBIDDEN).json({ status: statusMsg.fail.msg, message: http.getStatusText(http.FORBIDDEN) }) + let err = new Error() + err.status = http.FORBIDDEN + return next(err) } } catch (err) { - res.status(htpp.FORBIDDEN).json({ "message": err.message }) + err.status = http.FORBIDDEN next(err) } } -exports.logout = async (req, res) => { +exports.logout = async (req, res, next) => { try { let user = await User.findOne({ refresh_token: req.body.refresh_token }) let decoded = await jwt.verify(req.token, secretKey.token.key) await user.refresh_token.pull(req.body.refresh_token) await user.save() - res.status(http.OK).json({ message: http.getStatusText(http.OK) }) + res.status(http.OK).json({ + "success": statusMsg.success.msg, + "payload": "" + }) } catch (err) { - res.status(http.FORBIDDEN).json({ "message": err.message }) + err.status = http.FORBIDDEN next(err) } } \ No newline at end of file diff --git a/controller/signUpController.js b/controller/signUpController.js index 15567c0..1acadd1 100644 --- a/controller/signUpController.js +++ b/controller/signUpController.js @@ -14,9 +14,16 @@ dotenv.config({ }) exports.create = async (req, res, next) => { - const errors = validationResult(req); + const errors = validationResult(req) if (!errors.isEmpty()) { - return res.status(http.UNPROCESSABLE_ENTITY).json({ errors: errors.array() }); + return res.status(http.UNPROCESSABLE_ENTITY).json({ + "success": statusMsg.fail.msg, + "payload": "", + "error": { + "code": http.UNPROCESSABLE_ENTITY, + "message": errors.array() + } + }) } try { let hash = await bcrypt.hash(req.body.password, SALTING) @@ -31,53 +38,62 @@ exports.create = async (req, res, next) => { }) await user.save() host = req.get('host') - await email_verify.verifyEmail(user.email, host, access_token) + await email_verify.verifyEmail(user.email, user.first_name, host, access_token) const response = { - "status": statusMsg.success.msg, "accessToken": access_token, "data": user, "message": statusMsg.email.msg + user.email + '.' } - res.status(http.CREATED).json({ response }) + res.status(http.CREATED).json({ + "success": statusMsg.success.msg, + "payload": response + }) } catch (err) { - res.status(http.CONFLICT).json({ "message": err.message }) + err.status = http.CONFLICT next(err) } } -exports.confirmation = async (req, res) => { +exports.confirmation = async (req, res,next) => { try { if (req.query.token) { - decoded = await jwt.verify(req.query.token, secretKey.token.key); - const email = decoded.email; + decoded = await jwt.verify(req.query.token, secretKey.token.key) + const email = decoded.email let user = await User.findOne({ email: email }) - if (!user) return res.status(http.BAD_REQUEST).send({ status: statusMsg.fail.msg, msg: http.getStatusText(http.BAD_REQUEST) }); - if (user.verified_email) return res.status(http.CONFLICT).send({ status: statusMsg.fail.msg, msg: http.getStatusText(http.CONFLICT) }); + if (!user) next(err.status = http.BAD_REQUEST) + if (user.verified_email) return res.status(http.CONFLICT).json({ + "success": statusMsg.success.msg, + "message": statusMsg.email_verfied.msg + }) user.verified_email = true await user.save() - res.status(http.OK).send({ status: statusMsg.success.msg, message: http.getStatusText(http.OK) }); + res.status(http.OK).json({ + "success": statusMsg.success.msg, + "message": http.getStatusText(http.OK) + }) } } catch (err) { - res.status(http.UNAUTHORIZED).json({ message: err.message }); + err.status = http.UNAUTHORIZED next(err) } - } -exports.resendToken = async (req, res) => { +exports.resendVerification = async (req, res, next) => { try { let user = await User.findOne({ email: req.body.email }) - if (!user) return res.status(http.FORBIDDEN).json({ status: statusMsg.fail.msg, msg: http.getStatusText(http.FORBIDDEN) }); - if (user.verified_email) return res.status(http.BAD_REQUEST).json({ status: statusMsg.fail.msg, msg: http.getStatusText(http.BAD_REQUEST) }); + if (!user) next(err.status = http.FORBIDDEN) + if (user.verified_email) return res.status(http.BAD_REQUEST).json({ + "success": statusMsg.success.msg, + "message": statusMsg.email_verfied.msg + }) const token = await jwt.sign({ email: req.body.email }, secretKey.token.key, { expiresIn: process.env.access_token_exp }) - host = req.get('host'); - await email_verify.verifyEmail(user.email, host, token) + host = req.get('host') + await email_verify.verifyEmail(user.email, user.first_name, host, token) } catch (err) { - res.status(http.UNAUTHORIZED).json({ "message": err.message }) + err.status = http.UNAUTHORIZED next(err) } - } \ No newline at end of file diff --git a/email/mentors/html.pug b/email/mentors/html.pug index 813af88..8e78a71 100644 --- a/email/mentors/html.pug +++ b/email/mentors/html.pug @@ -1,5 +1,15 @@ doctype html html body - p Hello, Please verify your account by clicking the link: - a(href = `http://${host}/mentors/confirmation/?token=${token}`) Verify \ No newline at end of file + p Hello #{name} , + p You have registered in Mentors. Please verify your email + a(href = `http://${host}/mentors/confirmation/?token=${token}`) + button(type="button") Verify + br + P Note: This verification link expires soon. Please verify soon. Thank You, + br + br + p Mentors. + p Arun Thapa Chowk, Jhamsikhel, + p Nepal. + p 5555987, 6584658 \ No newline at end of file diff --git a/index.js b/index.js index 1b8c047..b3cad6a 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ const mongoose = require('mongoose') const dotenv = require('dotenv') const cors = require('cors') const morgan = require('morgan') +const errorHandler = require('./middleware/errorHandler') dotenv.config({ path: './config/.env' @@ -21,7 +22,9 @@ app.get('/', (req, res) => { res.json({ msg: "HELLO MENTORS" }) }) + app.use(bodyParser.json()) app.use(cors()) app.use(morgan('combined')) app.use('/mentors/', signup) +app.use(errorHandler.errorHandler) diff --git a/middleware/errorHandler.js b/middleware/errorHandler.js new file mode 100644 index 0000000..f30d12e --- /dev/null +++ b/middleware/errorHandler.js @@ -0,0 +1,55 @@ +const statusMsg = require('../config/statusMsg') +const http = require('http-status-codes') + +exports.errorHandler = (err, req, res, next) => { + if (err.status == http.UNAUTHORIZED) { + return res.status(http.UNAUTHORIZED).json({ + "success": statusMsg.fail.msg, + "payload": "", + "error": { + "code": http.UNAUTHORIZED, + "message": http.getStatusText(http.UNAUTHORIZED) + } + }) + } + else if (err.status == http.CONFLICT) { + return res.status(http.CONFLICT).json({ + "success": statusMsg.fail.msg, + "payload": "", + "error": { + "code": http.CONFLICT, + "message": http.getStatusText(http.CONFLICT) + } + }) + } + else if (err.status == http.BAD_REQUEST) { + return res.status(http.BAD_REQUEST).json({ + "success": statusMsg.fail.msg, + "payload": "", + "error": { + "code": http.BAD_REQUEST, + "message": statusMsg.no_user.msg + } + }) + } + else if (err.status == http.FORBIDDEN) { + return res.status(http.FORBIDDEN).json({ + "success": statusMsg.fail.msg, + "payload": "", + "error": { + "code": http.FORBIDDEN, + "message": statusMsg.error.msg + } + }) + } + else{ + return res.status(http.INTERNAL_SERVER_ERROR).json({ + "success": statusMsg.fail.msg, + "payload": "", + "error": { + "code": http.INTERNAL_SERVER_ERROR, + "message": statusMsg.error.msg + } + }) + } +} \ No newline at end of file diff --git a/routes/signUpRoute.js b/routes/signUpRoute.js index 067af29..30e980e 100644 --- a/routes/signUpRoute.js +++ b/routes/signUpRoute.js @@ -10,7 +10,7 @@ app.use(expressValidator()) router.route('/signup').post(signupValidation.validate('createUser'), Register.create) router.route('/confirmation').get(Register.confirmation) -router.route('/resendToken').post(Register.resendToken) +router.route('/resendVerification').post(Register.resendVerification ) router.route('/login').post(Login.login) router.route('/refreshToken').post(Login.refreshToken) router.route('/logout').post(jwtValidation.verifyToken, Login.logout) From b07fb91122f9bbaf591fe16cd995b5be629d65f7 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 13:32:55 +0545 Subject: [PATCH 14/25] Used http-status-code library for status code --- ...okenGenerator.js => authTokenGenerator.js} | 6 +-- controller/googleOauthHandler.js | 27 +++++++----- package-lock.json | 41 ++++++++++++++----- 3 files changed, 50 insertions(+), 24 deletions(-) rename controller/{accessTokenGenerator.js => authTokenGenerator.js} (76%) diff --git a/controller/accessTokenGenerator.js b/controller/authTokenGenerator.js similarity index 76% rename from controller/accessTokenGenerator.js rename to controller/authTokenGenerator.js index b23b7e0..54cd0fe 100644 --- a/controller/accessTokenGenerator.js +++ b/controller/authTokenGenerator.js @@ -1,7 +1,7 @@ const jwt = require('jsonwebtoken'); const secretKey = require('../config/secretKey'); -const token = async (email) => { +const access_token = async (email) => { return await jwt.sign({ email }, secretKey.token.key, { @@ -13,10 +13,10 @@ const refresh_token = async (email) => { return await jwt.sign({ email }, secretKey.token.key, { - expiresIn: `${24*7}h` + expiresIn: `${24*30}h` }); }; module.exports = { - token, refresh_token + access_token, refresh_token }; \ No newline at end of file diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index e7aff58..2717f00 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -2,9 +2,10 @@ require('dotenv').config({ path: '../config/variables.env' }); +const httpStatus = require('http-status-codes'); const googleOAuth = require('../middleware/googleOAuthClient'); const User = require('../models/user'); -const tokenGenerator = require('./accessTokenGenerator'); +const tokenGenerator = require('./authTokenGenerator'); @@ -13,40 +14,46 @@ module.exports.getMessage = async (googleToken) => { const response = await googleOAuth.getUserInfo(googleToken); const userInfo = response.data; - const token = await tokenGenerator.token(userInfo.email); + const access_token = await tokenGenerator.access_token(userInfo.email); const refresh_token = await tokenGenerator.refresh_token(userInfo.email); try { //If the google id already exists in the db, store nothing to the db if (await dbQuery.idExists(userInfo)) { return { - message: token, - statusCode: 200 + message: access_token, + statusCode: httpStatus.OK }; } else { //if the google email exists in the db but is not linked, link the accounts if (await dbQuery.emailExists(userInfo)) { await dbQuery.updateWithId(userInfo); return { - message: token, - statusCode: 200 + message: access_token, + statusCode: httpStatus.OK }; } else { //otherwise, create a new account await dbQuery.createAccount(userInfo, refresh_token); return { - message: token, - statusCode: 201 + message: access_token, + statusCode: httpStatus.CREATED }; } } } catch(error) { console.log(error); - return { message:"Error connecting database", statusCode: 500} + return { + message: httpStatus.getStatusText(httpStatus.INTERNAL_SERVER_ERROR), + statusCode: httpStatus.INTERNAL_SERVER_ERROR + } } } catch(error) { console.log(error); - return { message: "BAD_REQUEST", statusCode: 400}; + return { + message: httpStatus.getStatusText(httpStatus.BAD_REQUEST), + statusCode: httpStatus.BAD_REQUEST + }; } }; diff --git a/package-lock.json b/package-lock.json index e38f1e3..c29e341 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1580,7 +1580,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1598,11 +1599,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1615,15 +1618,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1726,7 +1732,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1736,6 +1743,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1748,17 +1756,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1775,6 +1786,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1847,7 +1859,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1857,6 +1870,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -1932,7 +1946,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -1962,6 +1977,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1979,6 +1995,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2017,11 +2034,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, From cb2170757ee34b3a94ef3b7492a30f7fd7ddf573 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 14:26:43 +0545 Subject: [PATCH 15/25] Removed redundent try catch blocks --- controller/googleOauthHandler.js | 37 +----- package-lock.json | 218 +++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+), 30 deletions(-) diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index 2717f00..f2c3a21 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -13,6 +13,7 @@ module.exports.getMessage = async (googleToken) => { try { const response = await googleOAuth.getUserInfo(googleToken); const userInfo = response.data; + console.log(response); const access_token = await tokenGenerator.access_token(userInfo.email); const refresh_token = await tokenGenerator.refresh_token(userInfo.email); @@ -61,35 +62,15 @@ module.exports.getMessage = async (googleToken) => { const dbQuery = { idExists: async (userInfo) => { - try { - const googleId = await User.findOne({ google_id: userInfo.id }); - if (googleId === null) { - return false; - } else { - return true; - } - } catch(error) { - console.log(error); - } + const googleId = await User.findOne({ google_id: userInfo.id }); + return googleId; }, emailExists: async (userInfo) => { - try { - const googleEmail = await User.findOne({ email: userInfo.email }); - if (googleEmail === null) { - return false; - } else { - return true; - } - } catch(error) { - console.log(error); - } + const googleEmail = await User.findOne({ email: userInfo.email }); + return googleEmail; }, updateWithId: async (userInfo) => { - try { - await User.findOneAndUpdate({email: userInfo.email}, {google_id: userInfo.id}); - } catch(error) { - console.log(error); - } + await User.findOneAndUpdate({email: userInfo.email}, {google_id: userInfo.id, refresh_token}); }, createAccount: async (userInfo, refresh_token) => { let user = { @@ -100,10 +81,6 @@ const dbQuery = { verified_email: true, refresh_token } - try { - User.create(user); - } catch(error) { - console.log(error); - } + User.create(user); } }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c29e341..da4c3c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,14 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -89,6 +97,14 @@ } } }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, "ajv": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", @@ -229,6 +245,11 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -373,6 +394,11 @@ } } }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + }, "base64url": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", @@ -403,6 +429,11 @@ "tweetnacl": "^0.14.3" } }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -1162,6 +1193,19 @@ } } }, + "es6-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1182,6 +1226,11 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, "execa": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", @@ -1467,6 +1516,11 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -2097,6 +2151,26 @@ } } }, + "gaxios": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.0.1.tgz", + "integrity": "sha512-c1NXovTxkgRJTIgB2FrFmOFg4YIV6N/bAa4f/FZ4jIw13Ql9ya/82x69CswvotJhbV3DiGnlTZwoq2NVXk2Irg==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-2.0.0.tgz", + "integrity": "sha512-BN6KUUWo6WLkDRst+Y7bqpXq1PYMrKUecNLRdZESp7oYtMjWcZdAM0UYvcip8wb0GXNO/j8Z8HTccK4iYtMvyQ==", + "requires": { + "gaxios": "^2.0.0", + "json-bigint": "^0.3.0" + } + }, "get-paths": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/get-paths/-/get-paths-0.0.4.tgz", @@ -2164,6 +2238,79 @@ "ini": "^1.3.4" } }, + "google-auth-library": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-4.0.0.tgz", + "integrity": "sha512-yyxl74G16GjKLevccXK3/DYEXphtI9Q2Qw3Eh7y8scjBKNL0IbAZF1mi999gC0tkfG6J23sCbd9tMEbNYeWfJQ==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.0.0", + "gcp-metadata": "^2.0.0", + "gtoken": "^3.0.0", + "jws": "^3.1.5", + "lru-cache": "^5.0.0", + "semver": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.0.tgz", + "integrity": "sha512-kCqEOOHoBcFs/2Ccuk4Xarm/KiWRSLEX9CAZF8xkJ6ZPlIoTZ8V5f7J16vYLJqDbR7KrxTJpR2lqjIEm2Qx9cQ==" + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + } + } + }, + "google-p12-pem": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.0.tgz", + "integrity": "sha512-n8eGSKzWOb9/EmSBIh81sPvsQM939QlpHMXahTZDzuRIpCu09x3Oaqz+mXGjL4TeCvSbcnOC0YZRvjkJ9s9lnA==", + "requires": { + "node-forge": "^0.8.0" + } + }, + "googleapis": { + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-40.0.0.tgz", + "integrity": "sha512-G4iUF6V141mbgbXmbXQDYP0pOYJAONvA8m+RzYfuVBcwfKm7Pn6Aes9LT0a6ddmW9CmydHmHdOgKZuWwkXueXg==", + "requires": { + "google-auth-library": "^4.0.0", + "googleapis-common": "^2.0.0" + } + }, + "googleapis-common": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-2.0.0.tgz", + "integrity": "sha512-RyUkadTbrTWOCMnKYVYg1pxeH6oFKDr8WHOesbjsgPY1tS10q8Wdmf3VUKL3MMqNEM5ue2IxdfM2FzpYUGHaxA==", + "requires": { + "gaxios": "^2.0.0", + "google-auth-library": "^4.0.0", + "pify": "^4.0.0", + "qs": "^6.5.2", + "url-template": "^2.0.8", + "uuid": "^3.2.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + } + } + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -2187,6 +2334,30 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, + "gtoken": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-3.0.0.tgz", + "integrity": "sha512-IY9HVi78D4ykVHn+ThI7rlcpdFtKyo9e9YLim9S9T3rp6fEnfeTexcrqzSpExVshPofsdauLKIa8dEnzX7ZLfQ==", + "requires": { + "gaxios": "^2.0.0", + "google-p12-pem": "^2.0.0", + "jws": "^3.1.5", + "mime": "^2.2.0", + "pify": "^4.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.3.tgz", + "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + } + } + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -2335,6 +2506,30 @@ "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-1.3.2.tgz", "integrity": "sha512-nDUtj0ltIt08tGi2VWSpSzNNFye0v3YSe9lX3lIqLTuVvvRiYCvs4QQBSHo0eomFYw1wlUuofurUAlTm+vHnXg==" }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "i18n": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/i18n/-/i18n-0.8.3.tgz", @@ -2666,6 +2861,14 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "json-bigint": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", + "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", + "requires": { + "bignumber.js": "^7.0.0" + } + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -3335,6 +3538,16 @@ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "node-forge": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.4.tgz", + "integrity": "sha512-UOfdpxivIYY4g5tqp5FNRNgROVNxRACUxxJREntJLFaJr1E0UEqFtUIk0F/jYx/E+Y6sVXd0KDi/m5My0yGCVw==" + }, "node-pre-gyp": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", @@ -4810,6 +5023,11 @@ "prepend-http": "^1.0.1" } }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", From 39de10e85e765cbac990fb69bce74a909153151e Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 14:55:52 +0545 Subject: [PATCH 16/25] Save refresh token --- controller/googleOauthHandler.js | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index f2c3a21..5ab1c0b 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -13,7 +13,6 @@ module.exports.getMessage = async (googleToken) => { try { const response = await googleOAuth.getUserInfo(googleToken); const userInfo = response.data; - console.log(response); const access_token = await tokenGenerator.access_token(userInfo.email); const refresh_token = await tokenGenerator.refresh_token(userInfo.email); @@ -25,22 +24,20 @@ module.exports.getMessage = async (googleToken) => { message: access_token, statusCode: httpStatus.OK }; + //if the google email exists in the db, link the accounts + } else if (await dbQuery.emailExists(userInfo)) { + await dbQuery.updateWithId(userInfo, refresh_token); + return { + message: access_token, + statusCode: httpStatus.OK + }; } else { - //if the google email exists in the db but is not linked, link the accounts - if (await dbQuery.emailExists(userInfo)) { - await dbQuery.updateWithId(userInfo); - return { - message: access_token, - statusCode: httpStatus.OK - }; - } else { - //otherwise, create a new account - await dbQuery.createAccount(userInfo, refresh_token); - return { - message: access_token, - statusCode: httpStatus.CREATED - }; - } + //otherwise, create a new account + await dbQuery.createAccount(userInfo, refresh_token); + return { + message: access_token, + statusCode: httpStatus.CREATED + }; } } catch(error) { console.log(error); @@ -61,15 +58,19 @@ module.exports.getMessage = async (googleToken) => { const dbQuery = { - idExists: async (userInfo) => { + idExists: async (userInfo, refresh_token) => { const googleId = await User.findOne({ google_id: userInfo.id }); + if (googleId) { + await googleId.refresh_token.push(refresh_token); + await googleId.save(); + } return googleId; }, emailExists: async (userInfo) => { const googleEmail = await User.findOne({ email: userInfo.email }); return googleEmail; }, - updateWithId: async (userInfo) => { + updateWithId: async (userInfo, refresh_token) => { await User.findOneAndUpdate({email: userInfo.email}, {google_id: userInfo.id, refresh_token}); }, createAccount: async (userInfo, refresh_token) => { From f2e0baf8dd4f793ae14533e1396b215c9542529e Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 15:21:22 +0545 Subject: [PATCH 17/25] added expiry time in schema for refresh token --- models/user.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/models/user.js b/models/user.js index feaa1a4..a7c601c 100644 --- a/models/user.js +++ b/models/user.js @@ -1,4 +1,8 @@ -const mongoose = require('mongoose') +const mongoose = require('mongoose'); +require('dotenv').config({ + path: './config/.env' +}); + var schema = mongoose.Schema({ first_name: {type:String, required:true}, last_name :{type:String,required:true}, @@ -10,7 +14,7 @@ var schema = mongoose.Schema({ address : {type:String}, user_role : {type:String}, verified_email : {type: Boolean, default: false}, - refresh_token : {type:Array,required:true}, + refresh_token : {type:Array,required:true, expires: process.env.refresh_token_exp }, }) schema.methods.toJSON = function () { var obj = this.toObject() From 8f1e0bc4fd892c705cebd729b3835b155c9e269e Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 15:41:26 +0545 Subject: [PATCH 18/25] Used router() instead of app() in socialAuth.js --- controller/googleOauthHandler.js | 2 +- routes/socialAuth.js | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index 5ab1c0b..98ee3b9 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -82,6 +82,6 @@ const dbQuery = { verified_email: true, refresh_token } - User.create(user); + await User.create(user); } }; \ No newline at end of file diff --git a/routes/socialAuth.js b/routes/socialAuth.js index af24f44..50a8e99 100644 --- a/routes/socialAuth.js +++ b/routes/socialAuth.js @@ -1,27 +1,22 @@ -//Dependencies require('dotenv').config({ path: 'variables.env' }); -const express = require('express'); -const cors = require('cors'); -const bodyParser = require('body-parser'); +const router = require('express').Router(); const googleOauthHandler = require('../controller/googleOauthHandler') -//Config -const app = express(); -app.use(cors()); -app.use(bodyParser.json({ type: 'application/*+json' })); -//Routes -app.post('/google', async (req, res) => { +router.route('/google').post(async (req, res) => { try { let googleAccessToken = req.body.accessToken; let response = await googleOauthHandler.getMessage(googleAccessToken); res.status(response.statusCode).send(response.message); } catch(error) { + + + res.status(500).send("Internal Server Error"); console.log("Error calling googleOauthHandler", error); } }); -module.exports = app; +module.exports = router; From ca5bfd97aa729e6413c12c0422cb761806cac845 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 17:18:08 +0545 Subject: [PATCH 19/25] Changed response to standard JSON response format --- config/statusMsg.js | 35 ++++++++++++++++---- controller/googleOauthHandler.js | 55 ++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/config/statusMsg.js b/config/statusMsg.js index 636a12a..c9262a4 100644 --- a/config/statusMsg.js +++ b/config/statusMsg.js @@ -1,11 +1,32 @@ -module.exports= { - success : { - msg : "Success" +module.exports = { + success: { + msg: "true" }, - fail : { - msg : "Failure" + fail: { + msg: "false" }, - email :{ - msg: 'A verification email has been sent to ' + email: { + msg: "A verification email has been sent to " + }, + token_exp: { + msg: "Token Expired" + }, + no_user: { + msg: "User not found" + }, + not_verified: { + msg: "User is not verified" + }, + password_not_match: { + msg: "Invalid Password" + }, + error: { + msg: "Some error" + }, + email_verfied: { + msg: "Email already verified" + }, + database_error: { + msg: "Database Error" } } \ No newline at end of file diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index 98ee3b9..e8a9b48 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -17,41 +17,56 @@ module.exports.getMessage = async (googleToken) => { const access_token = await tokenGenerator.access_token(userInfo.email); const refresh_token = await tokenGenerator.refresh_token(userInfo.email); + const payload = { + access_token, + refresh_token, + data: userInfo + }; + try { //If the google id already exists in the db, store nothing to the db if (await dbQuery.idExists(userInfo)) { - return { - message: access_token, - statusCode: httpStatus.OK - }; + return res.status(httpStatus.OK).json({ + "success": statusMsg.success.msg, + "payload": payload + }); + //if the google email exists in the db, link the accounts } else if (await dbQuery.emailExists(userInfo)) { await dbQuery.updateWithId(userInfo, refresh_token); - return { - message: access_token, - statusCode: httpStatus.OK - }; + return res.status(httpStatus.OK).json({ + "success": statusMsg.success.msg, + "payload": payload + }); } else { //otherwise, create a new account await dbQuery.createAccount(userInfo, refresh_token); - return { - message: access_token, - statusCode: httpStatus.CREATED - }; + return res.status(httpStatus.CREATED).json({ + "success": statusMsg.success.msg, + "payload": payload + }); } } catch(error) { console.log(error); - return { - message: httpStatus.getStatusText(httpStatus.INTERNAL_SERVER_ERROR), - statusCode: httpStatus.INTERNAL_SERVER_ERROR - } + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + "success": statusMsg.fail.msg, + "payload": {}, + "error": { + "code": httpStatus.INTERNAL_SERVER_ERROR, + "message": statusMsg.database_error.msg + } + }); } } catch(error) { console.log(error); - return { - message: httpStatus.getStatusText(httpStatus.BAD_REQUEST), - statusCode: httpStatus.BAD_REQUEST - }; + return res.status(httpStatus.BAD_REQUEST).json({ + "success": statusMsg.fail.msg, + "payload": {}, + "error": { + "code": httpStatus.BAD_REQUEST, + "message": statusMsg.token_exp.msg + } + }); } }; From 7722f41112dd3fa63d9518908cf3c6a97ca4f302 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 17:44:22 +0545 Subject: [PATCH 20/25] Moved all response logic to googleOauthHandler --- controller/googleOauthHandler.js | 25 ++++++++++++------------- routes/socialAuth.js | 18 ++++-------------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index e8a9b48..88b78c4 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -6,12 +6,13 @@ const httpStatus = require('http-status-codes'); const googleOAuth = require('../middleware/googleOAuthClient'); const User = require('../models/user'); const tokenGenerator = require('./authTokenGenerator'); +const statusMsg = require('../config/statusMsg') - -module.exports.getMessage = async (googleToken) => { +module.exports.oauthHandler = async (req, res) => { + let googleAuthToken = req.body.accessToken; try { - const response = await googleOAuth.getUserInfo(googleToken); + const response = await googleOAuth.getUserInfo(googleAuthToken); const userInfo = response.data; const access_token = await tokenGenerator.access_token(userInfo.email); @@ -24,22 +25,21 @@ module.exports.getMessage = async (googleToken) => { }; try { - //If the google id already exists in the db, store nothing to the db - if (await dbQuery.idExists(userInfo)) { + //If the google id already exists in the db, store only refresh token in the db + if (await dbQuery.idExists(userInfo.id)) { return res.status(httpStatus.OK).json({ "success": statusMsg.success.msg, "payload": payload }); - //if the google email exists in the db, link the accounts - } else if (await dbQuery.emailExists(userInfo)) { + } else if (await dbQuery.emailExists(userInfo.email)) { await dbQuery.updateWithId(userInfo, refresh_token); return res.status(httpStatus.OK).json({ "success": statusMsg.success.msg, "payload": payload }); + //otherwise, create a new account } else { - //otherwise, create a new account await dbQuery.createAccount(userInfo, refresh_token); return res.status(httpStatus.CREATED).json({ "success": statusMsg.success.msg, @@ -73,17 +73,16 @@ module.exports.getMessage = async (googleToken) => { const dbQuery = { - idExists: async (userInfo, refresh_token) => { - const googleId = await User.findOne({ google_id: userInfo.id }); + idExists: async (id, refresh_token) => { + const googleId = await User.findOne({ google_id: id }); if (googleId) { await googleId.refresh_token.push(refresh_token); await googleId.save(); } return googleId; }, - emailExists: async (userInfo) => { - const googleEmail = await User.findOne({ email: userInfo.email }); - return googleEmail; + emailExists: async (email) => { + return await User.findOne({ email }); }, updateWithId: async (userInfo, refresh_token) => { await User.findOneAndUpdate({email: userInfo.email}, {google_id: userInfo.id, refresh_token}); diff --git a/routes/socialAuth.js b/routes/socialAuth.js index 50a8e99..526b41f 100644 --- a/routes/socialAuth.js +++ b/routes/socialAuth.js @@ -2,21 +2,11 @@ require('dotenv').config({ path: 'variables.env' }); const router = require('express').Router(); -const googleOauthHandler = require('../controller/googleOauthHandler') +const google = require('../controller/googleOauthHandler') -router.route('/google').post(async (req, res) => { - try { - let googleAccessToken = req.body.accessToken; - let response = await googleOauthHandler.getMessage(googleAccessToken); - res.status(response.statusCode).send(response.message); - } catch(error) { - - - - res.status(500).send("Internal Server Error"); - console.log("Error calling googleOauthHandler", error); - } -}); +router.route('/google').post( + google.oauthHandler +); module.exports = router; From cbe46c201954cf3846669557462d30e2998f32d2 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 17:48:30 +0545 Subject: [PATCH 21/25] Added API version to routes --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 1dea7ec..49835ba 100644 --- a/index.js +++ b/index.js @@ -27,5 +27,5 @@ app.get('/', (req, res) => { app.use(bodyParser.json()) app.use(cors()) app.use(morgan('combined')) -app.use('/mentors/', signup) -app.use('/auth', socialAuth) +app.use('v1/mentors/', signup) +app.use('v1/auth', socialAuth) From 70b99819e97bec8d9daff11c6fcccda9dd4a4c32 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Mon, 27 May 2019 18:00:31 +0545 Subject: [PATCH 22/25] authTokenGenerator now uses .env file instead of hard coded expiry time --- controller/authTokenGenerator.js | 7 +++++-- controller/googleOauthHandler.js | 4 ++-- index.js | 2 +- middleware/googleOAuthClient.js | 2 +- routes/socialAuth.js | 3 --- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/controller/authTokenGenerator.js b/controller/authTokenGenerator.js index 54cd0fe..85e43b5 100644 --- a/controller/authTokenGenerator.js +++ b/controller/authTokenGenerator.js @@ -1,3 +1,6 @@ +dotenv.config({ + path: './config/.env' +}) const jwt = require('jsonwebtoken'); const secretKey = require('../config/secretKey'); @@ -5,7 +8,7 @@ const access_token = async (email) => { return await jwt.sign({ email }, secretKey.token.key, { - expiresIn: '24h' + expiresIn: process.env.access_token_exp }); }; @@ -13,7 +16,7 @@ const refresh_token = async (email) => { return await jwt.sign({ email }, secretKey.token.key, { - expiresIn: `${24*30}h` + expiresIn: process.env.refresh_token_exp }); }; diff --git a/controller/googleOauthHandler.js b/controller/googleOauthHandler.js index 88b78c4..e56c713 100644 --- a/controller/googleOauthHandler.js +++ b/controller/googleOauthHandler.js @@ -1,5 +1,5 @@ require('dotenv').config({ - path: '../config/variables.env' + path: '../config/.env' }); const httpStatus = require('http-status-codes'); @@ -25,7 +25,7 @@ module.exports.oauthHandler = async (req, res) => { }; try { - //If the google id already exists in the db, store only refresh token in the db + //If the google id already exists in the db, update refresh token in the db if (await dbQuery.idExists(userInfo.id)) { return res.status(httpStatus.OK).json({ "success": statusMsg.success.msg, diff --git a/index.js b/index.js index 49835ba..91852fb 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const cors = require('cors') const morgan = require('morgan') dotenv.config({ - path: './config/variables.env' + path: './config/.env' }) const url = process.env.DEVELOPMENT_DB_URL diff --git a/middleware/googleOAuthClient.js b/middleware/googleOAuthClient.js index 415fca6..900b198 100644 --- a/middleware/googleOAuthClient.js +++ b/middleware/googleOAuthClient.js @@ -1,5 +1,5 @@ require('dotenv').config({ - path: '../config/variables.env' + path: '../config/.env' }); const google = require('googleapis').google; diff --git a/routes/socialAuth.js b/routes/socialAuth.js index 526b41f..4451a4c 100644 --- a/routes/socialAuth.js +++ b/routes/socialAuth.js @@ -1,6 +1,3 @@ -require('dotenv').config({ - path: 'variables.env' -}); const router = require('express').Router(); const google = require('../controller/googleOauthHandler') From 1c69c155d94b12dc02242c8a210be9f04d17ca91 Mon Sep 17 00:00:00 2001 From: AwaleRohin Date: Tue, 28 May 2019 10:46:09 +0545 Subject: [PATCH 23/25] bug:signup with email after facebook signup fixed --- controller/signUpController.js | 57 ++++++++++++++++++++++------------ middleware/signupValidation.js | 6 ++-- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/controller/signUpController.js b/controller/signUpController.js index 48caee7..ea51e2c 100644 --- a/controller/signUpController.js +++ b/controller/signUpController.js @@ -33,28 +33,47 @@ exports.create = async (req, res, next) => { let hash = await bcrypt.hash(req.body.password, SALTING) const access_token = await tokenGenerator.access_token(req.body.email) const refresh_token = await tokenGenerator.refresh_token(req.body.email) - const user = new User({ - first_name: req.body.first_name, - last_name: req.body.last_name, - email: req.body.email, - user_role: role, - password: hash, - refresh_token: refresh_token - }) - await user.save() - host = req.get('host') - await email_verify.verifyEmail(user.email, user.first_name, host, access_token) - const response = { - "accessToken": access_token, - "data": user, - "message": statusMsg.email.msg + user.email + '.' + let email = await User.findOne({ email: req.body.email }) + if (email) { + if (typeof email.password === 'undefined') { + email.password = hash + await email.save() + } + const response = { + "accessToken": access_token, + "data": email + } + res.status(http.CREATED).json({ + "success": statusMsg.success.msg, + "payload": response + }) } - res.status(http.CREATED).json({ - "success": statusMsg.success.msg, - "payload": response - }) + else if (!email) { + const user = new User({ + first_name: req.body.first_name, + last_name: req.body.last_name, + email: req.body.email, + user_role: role, + password: hash, + refresh_token: refresh_token + }) + await user.save() + host = req.get('host') + await email_verify.verifyEmail(user.email, user.first_name, host, access_token) + const response = { + "accessToken": access_token, + "data": user, + "message": statusMsg.email.msg + user.email + '.' + } + res.status(http.CREATED).json({ + "success": statusMsg.success.msg, + "payload": response + }) + } + } catch (err) { + console.log(err) err.status = http.CONFLICT next(err) } diff --git a/middleware/signupValidation.js b/middleware/signupValidation.js index 950b403..e0a7aa2 100644 --- a/middleware/signupValidation.js +++ b/middleware/signupValidation.js @@ -7,8 +7,10 @@ exports.validate = (method) => { return [ body('email').custom(async (value, { req }) => { let user = await User.findOne({ email: req.body.email }) - if (user) { - throw new Error('Email already exists'); + if(user){ + if (typeof user.password !== 'undefined') { + throw new Error('Email already exists'); + } } return true; }), From dd1522b37f69843fe3dc27511ca9217ea38676fb Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Tue, 28 May 2019 14:39:42 +0545 Subject: [PATCH 24/25] Fixed merge conflict for User model --- models/user.js | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/models/user.js b/models/user.js index 8c4e5b5..9e8ed6c 100644 --- a/models/user.js +++ b/models/user.js @@ -1,22 +1,3 @@ -<<<<<<< HEAD -const mongoose = require('mongoose'); -require('dotenv').config({ - path: './config/.env' -}); - -var schema = mongoose.Schema({ - first_name: {type:String, required:true}, - last_name :{type:String,required:true}, - email: {type:String, required:true, unique:true}, - password : String, - google_id: Number, - dob : {type:Date}, - phone : {type:Number}, - address : {type:String}, - user_role : {type:String}, - verified_email : {type: Boolean, default: false}, - refresh_token : {type:Array,required:true, expires: process.env.refresh_token_exp }, -======= const mongoose = require('mongoose') const dotenv = require('dotenv') dotenv.config({ @@ -31,10 +12,10 @@ var schema = mongoose.Schema({ phone: { type: Number }, address: { type: String }, user_role: { type: String }, + google_id: Number, facebook_id: { type: String }, verified_email: { type: Boolean, default: false }, refresh_token: { type: Array, required: true, expires: process.env.refresh_token_exp }, ->>>>>>> feature/facebook_signup }) schema.methods.toJSON = function () { var obj = this.toObject() From a82fddcd125786f8f3bbeb19574acec4d653ec14 Mon Sep 17 00:00:00 2001 From: Vipul Chaudhary Date: Wed, 29 May 2019 17:41:40 +0545 Subject: [PATCH 25/25] google controller now pushes refresh token to the array instead of replacing them --- controller/googleController.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/controller/googleController.js b/controller/googleController.js index 18ba473..e38f562 100644 --- a/controller/googleController.js +++ b/controller/googleController.js @@ -85,7 +85,12 @@ const dbQuery = { return await User.findOne({ email }); }, updateWithId: async (userInfo, refresh_token) => { - await User.findOneAndUpdate({email: userInfo.email}, {google_id: userInfo.id, refresh_token}); + let google = await User.findOne({ + email: userInfo.email + }); + google.google_id = userInfo.id; + await google.refresh_token.push(refresh_token); + await google.save(); }, createAccount: async (userInfo, refresh_token) => { let user = {