From 28f0508ba2f949e4853935d2bd1b795e248e23fb Mon Sep 17 00:00:00 2001 From: thiagompc Date: Tue, 23 Mar 2021 21:59:15 -0300 Subject: [PATCH 1/5] feat: fga-eps-mds/2020.2-Lend.it#110 Create login route Co-authored-by: Vinicius Saturnino --- src/controllers/SessionController.js | 30 ++++++++++++++++++++++++++++ src/routes.js | 2 ++ src/routes/session.routes.js | 9 +++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/controllers/SessionController.js create mode 100644 src/routes/session.routes.js diff --git a/src/controllers/SessionController.js b/src/controllers/SessionController.js new file mode 100644 index 0000000..af1ec71 --- /dev/null +++ b/src/controllers/SessionController.js @@ -0,0 +1,30 @@ +import User from '../models/User.js'; +import bcrypt from 'bcrypt'; + +const saltRounds = process.env.SALT_ROUNDS; + +export default { + async create(request, response) { + const { useremail, password } = request.body; + + try { + const user = await User.findOne({ + where: { + useremail, + }, + }); + + if (!user) { + return response.status(404).json({ error: 'Usuário não cadastrado' }); + } + + if(!await bcrypt.compare(password, user.password)){ + return response.status(400).json({ error: 'Senha inválida' }); + } + + return response.status(201).json(user); + } catch (error) { + return response.status(500).json({ error: error.message }); + } + }, +}; diff --git a/src/routes.js b/src/routes.js index df2b6b1..487c1f4 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1,9 +1,11 @@ import { Router } from 'express'; import userRouter from './routes/user.routes.js'; +import sessionRouter from './routes/session.routes.js' const routes = Router(); routes.use('/users', userRouter); +routes.use('/session', sessionRouter); export default routes; diff --git a/src/routes/session.routes.js b/src/routes/session.routes.js new file mode 100644 index 0000000..cac88fe --- /dev/null +++ b/src/routes/session.routes.js @@ -0,0 +1,9 @@ +import { Router } from 'express'; + +import SessionController from '../controllers/SessionController.js'; + +const sessionRouter = Router(); + +sessionRouter.post('/', SessionController.create); + +export default sessionRouter; From 356a27a4c6843439bf9224872fe40cff77faa6cb Mon Sep 17 00:00:00 2001 From: viniciussaturnino Date: Wed, 24 Mar 2021 21:21:10 -0300 Subject: [PATCH 2/5] feat: fga-eps-mds/2020.2-Lend.it#110 Create function to generate token Co-authored-by: Thiago Mesquita --- package-lock.json | 91 ++++++++++++++++++++++++++++ package.json | 1 + src/controllers/SessionController.js | 4 +- src/controllers/UserController.js | 5 +- src/services/auth.js | 9 +++ 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/services/auth.js diff --git a/package-lock.json b/package-lock.json index b328267..bc5ed02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1526,6 +1526,11 @@ "node-int64": "^0.4.0" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -2371,6 +2376,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4538,6 +4551,30 @@ "minimist": "^1.2.5" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4550,6 +4587,25 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", @@ -4650,6 +4706,41 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", diff --git a/package.json b/package.json index 0cf4eca..8cd9566 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "bcrypt": "^5.0.1", "dotenv": "^8.2.0", "express": "^4.17.1", + "jsonwebtoken": "^8.5.1", "pg": "^8.5.1", "pg-hstore": "^2.3.3", "sequelize": "^6.5.0" diff --git a/src/controllers/SessionController.js b/src/controllers/SessionController.js index af1ec71..a886d13 100644 --- a/src/controllers/SessionController.js +++ b/src/controllers/SessionController.js @@ -1,8 +1,6 @@ import User from '../models/User.js'; import bcrypt from 'bcrypt'; -const saltRounds = process.env.SALT_ROUNDS; - export default { async create(request, response) { const { useremail, password } = request.body; @@ -18,7 +16,7 @@ export default { return response.status(404).json({ error: 'Usuário não cadastrado' }); } - if(!await bcrypt.compare(password, user.password)){ + if (!(await bcrypt.compare(password, user.password))) { return response.status(400).json({ error: 'Senha inválida' }); } diff --git a/src/controllers/UserController.js b/src/controllers/UserController.js index 74245ab..3e1e229 100644 --- a/src/controllers/UserController.js +++ b/src/controllers/UserController.js @@ -1,5 +1,6 @@ import User from '../models/User.js'; import bcrypt from 'bcrypt'; +import generateToken from '../services/auth.js'; const saltRounds = process.env.SALT_ROUNDS; @@ -31,7 +32,9 @@ export default { longitude: 0, }); - return response.status(201).json(user); + const token = generateToken({ useremail }); + + return response.status(201).json({ user, token }); } catch (error) { return response.status(500).json({ error: error.message }); } diff --git a/src/services/auth.js b/src/services/auth.js new file mode 100644 index 0000000..702da69 --- /dev/null +++ b/src/services/auth.js @@ -0,0 +1,9 @@ +import jwt from 'jsonwebtoken'; + +function generateToken(params = {}) { + return jwt.sign(params, process.env.SECRET, { + expiresIn: 86400, + }); +} + +export default generateToken; From 547b8a16795eadaee47c08070e481d496811b737 Mon Sep 17 00:00:00 2001 From: viniciussaturnino Date: Wed, 24 Mar 2021 21:49:46 -0300 Subject: [PATCH 3/5] feat: fga-eps-mds/2020.2-Lend.it#110 Generate token in login method and validate token with middleware Co-authored-by: Thiago Mesquita --- src/controllers/SessionController.js | 5 ++++- src/middlewares/auth.js | 32 ++++++++++++++++++++++++++++ src/routes.js | 2 +- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/middlewares/auth.js diff --git a/src/controllers/SessionController.js b/src/controllers/SessionController.js index a886d13..0b6e14c 100644 --- a/src/controllers/SessionController.js +++ b/src/controllers/SessionController.js @@ -1,5 +1,6 @@ import User from '../models/User.js'; import bcrypt from 'bcrypt'; +import generateToken from '../services/auth.js'; export default { async create(request, response) { @@ -20,7 +21,9 @@ export default { return response.status(400).json({ error: 'Senha inválida' }); } - return response.status(201).json(user); + const token = generateToken({ useremail }); + + return response.status(201).json({ user, token }); } catch (error) { return response.status(500).json({ error: error.message }); } diff --git a/src/middlewares/auth.js b/src/middlewares/auth.js new file mode 100644 index 0000000..79e1017 --- /dev/null +++ b/src/middlewares/auth.js @@ -0,0 +1,32 @@ +import jwt from 'jsonwebtoken'; + +function verifyToken(request, response, next) { + const authHeader = request.headers.authorization; + + if (!authHeader) { + return response.status(400).json({ error: 'Token não encontrado' }); + } + + const parts = authHeader.split(' '); + + if (!parts.lenght === 2) { + return response.status(401).json({ error: 'Erro no token' }); + } + + const [scheme, token] = parts; + + if (!/^Bearer$/i.test(scheme)) { + return response.status(401).json({ error: 'Token mal formatado' }); + } + + jwt.verify(token, process.env.SECRET, (err, decoded) => { + if (err) { + return response.status(401).json({ error: 'Token inválido' }); + } + + request.useremail = decoded.useremail; + return next(); + }); +} + +export default verifyToken; diff --git a/src/routes.js b/src/routes.js index 487c1f4..3c74c66 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1,7 +1,7 @@ import { Router } from 'express'; import userRouter from './routes/user.routes.js'; -import sessionRouter from './routes/session.routes.js' +import sessionRouter from './routes/session.routes.js'; const routes = Router(); From 5aaff4405e7e8ccf1221584ca4eab6a7f6be2ed9 Mon Sep 17 00:00:00 2001 From: viniciussaturnino Date: Wed, 24 Mar 2021 21:54:43 -0300 Subject: [PATCH 4/5] chore: fga-eps-mds/2020.2-Lend.it#110 Add secret variable in .env-example Co-authored-by: Thiago Mesquita --- .env-example | 1 + 1 file changed, 1 insertion(+) diff --git a/.env-example b/.env-example index afc167f..79b99c1 100644 --- a/.env-example +++ b/.env-example @@ -1 +1,2 @@ SALT_ROUNDS = +SECRET = From 43e712bb49594924ed8e1b3e4facd039151c2e84 Mon Sep 17 00:00:00 2001 From: viniciussaturnino Date: Fri, 26 Mar 2021 15:39:31 -0300 Subject: [PATCH 5/5] refactor: fga-eps-mds/2020.2-Lend.it#110 Change return of session controller for token Co-authored-by: Thiago Mesquita --- src/controllers/SessionController.js | 10 +++------- src/middlewares/auth.js | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/controllers/SessionController.js b/src/controllers/SessionController.js index 0b6e14c..1cf717a 100644 --- a/src/controllers/SessionController.js +++ b/src/controllers/SessionController.js @@ -13,17 +13,13 @@ export default { }, }); - if (!user) { - return response.status(404).json({ error: 'Usuário não cadastrado' }); - } - - if (!(await bcrypt.compare(password, user.password))) { - return response.status(400).json({ error: 'Senha inválida' }); + if (!user || !(await bcrypt.compare(password, user.password))) { + return response.status(404).json({ error: 'Usuário/Senha inválidos' }); } const token = generateToken({ useremail }); - return response.status(201).json({ user, token }); + return response.status(201).json(token); } catch (error) { return response.status(500).json({ error: error.message }); } diff --git a/src/middlewares/auth.js b/src/middlewares/auth.js index 79e1017..f1da665 100644 --- a/src/middlewares/auth.js +++ b/src/middlewares/auth.js @@ -9,7 +9,7 @@ function verifyToken(request, response, next) { const parts = authHeader.split(' '); - if (!parts.lenght === 2) { + if (!parts.lenght == 2) { return response.status(401).json({ error: 'Erro no token' }); }