diff --git a/api/controllers/UserController.js b/api/controllers/UserController.js index 4705876..dcd1be3 100644 --- a/api/controllers/UserController.js +++ b/api/controllers/UserController.js @@ -1,6 +1,7 @@ const User = require('../models/User'); const authService = require('../services/auth.service'); const bcryptService = require('../services/bcrypt.service'); +const cryptoService = require('../services/crypto.service'); const UserController = () => { const register = async (req, res) => { @@ -13,8 +14,7 @@ const UserController = () => { password: body.password, }); const token = authService().issue({ id: user.id }); - - return res.status(200).json({ token, user }); + return res.status(200).json({ token, user, refreshToken: user.refreshToken }); } catch (err) { console.log(err); return res.status(500).json({ msg: 'Internal server error' }); @@ -25,35 +25,38 @@ const UserController = () => { }; const login = async (req, res) => { - const { email, password } = req.body; - - if (email && password) { - try { - const user = await User - .findOne({ - where: { - email, - }, - }); - - if (!user) { - return res.status(400).json({ msg: 'Bad Request: User not found' }); + const { email, password, refreshToken } = req.body; + let user; + + if (email) { + if (password || refreshToken) { + try { + user = await User + .findOne({ + where: { + email, + }, + }); + if (!user) { + return res.status(400).json({ msg: 'Bad Request: User not found' }); + } + } catch (err) { + console.log(err); + return res.status(500).json({ msg: 'Internal server error' }); } - if (bcryptService().comparePassword(password, user.password)) { + if ((password && bcryptService().comparePassword(password, user.password)) || + (refreshToken && user.refreshToken === refreshToken) + ) { const token = authService().issue({ id: user.id }); - - return res.status(200).json({ token, user }); + const newRefreshToken = cryptoService().generateRefreshToken(); + user.refreshToken = newRefreshToken; + user.save(); + return res.status(200).json({ token, user, refreshToken: newRefreshToken }); } - - return res.status(401).json({ msg: 'Unauthorized' }); - } catch (err) { - console.log(err); - return res.status(500).json({ msg: 'Internal server error' }); } } - - return res.status(400).json({ msg: 'Bad Request: Email or password is wrong' }); + return res.status(401).json({ msg: 'Unauthorized' }); }; const validate = (req, res) => { diff --git a/api/models/User.js b/api/models/User.js index c5cb863..62dc575 100644 --- a/api/models/User.js +++ b/api/models/User.js @@ -1,6 +1,6 @@ const Sequelize = require('sequelize'); const bcryptService = require('../services/bcrypt.service'); - +const cryptoService = require('../services/crypto.service'); const sequelize = require('../../config/database'); const hooks = { @@ -19,6 +19,10 @@ const User = sequelize.define('User', { password: { type: Sequelize.STRING, }, + refreshToken: { + type: Sequelize.STRING, + defaultValue: () => cryptoService().generateRefreshToken(), + }, }, { hooks, tableName }); // eslint-disable-next-line @@ -26,6 +30,7 @@ User.prototype.toJSON = function () { const values = Object.assign({}, this.get()); delete values.password; + delete values.refreshToken; return values; }; diff --git a/api/services/crypto.service.js b/api/services/crypto.service.js new file mode 100644 index 0000000..7e52cec --- /dev/null +++ b/api/services/crypto.service.js @@ -0,0 +1,11 @@ +const crypto = require('crypto'); + +const cryptoService = () => { + const generateRefreshToken = () => crypto.randomBytes(20).toString('hex'); + + return { + generateRefreshToken, + }; +}; + +module.exports = cryptoService; diff --git a/package.json b/package.json index 7cb29aa..340eec6 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "bcrypt-nodejs": "^0.0.3", "body-parser": "^1.18.2", "cors": "^2.8.4", + "crypto": "^1.0.1", "express": "^4.16.3", "express-routes-mapper": "^1.0.2", "helmet": "^3.12.0", diff --git a/yarn.lock b/yarn.lock index b524abb..d35d61e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1191,6 +1191,11 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +crypto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" + integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== + cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.2" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"