From 36a9ef41f4e2171a1835ae096c3bd45e3f442a0c Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 19 Jun 2020 11:12:47 -0400 Subject: [PATCH 1/6] init push, created new branch --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 71eb93186..f54afeb86 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,12 @@ You are expected to be able to answer questions in these areas. Your responses c ### Task 1: Project Set Up -- [ ] Create a forked copy of this project -- [ ] Add your team lead as collaborator on Github -- [ ] Clone your OWN version of the repository (Not Lambda's by mistake!) -- [ ] Create a new branch: git checkout -b ``. -- [ ] Implement the project on your newly created `` branch, committing changes regularly -- [ ] Push commits: git push origin `` +- [+] Create a forked copy of this project +- [+] Add your team lead as collaborator on Github +- [+] Clone your OWN version of the repository (Not Lambda's by mistake!) +- [+] Create a new branch: git checkout -b ``. +- [+] Implement the project on your newly created `` branch, committing changes regularly +- [+] Push commits: git push origin `` ### Task 2: Project Requirements From a68e98dee518f0b6c20e938793de0f974d0ceeab Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 19 Jun 2020 13:34:16 -0400 Subject: [PATCH 2/6] create auth reg/log, added validation --- api/server.js | 2 ++ auth/auth-router.js | 48 ++++++++++++++++++++++++++++++++++++++++++ database/auth.db3 | Bin 24576 -> 24576 bytes package.json | 2 ++ users/users-model.js | 28 ++++++++++++++++++++++++ users/users-router.js | 9 ++++++++ utils/constants.js | 3 +++ utils/methods.js | 21 ++++++++++++++++++ utils/validate.js | 7 ++++++ 9 files changed, 120 insertions(+) create mode 100644 users/users-model.js create mode 100644 users/users-router.js create mode 100644 utils/constants.js create mode 100644 utils/methods.js create mode 100644 utils/validate.js diff --git a/api/server.js b/api/server.js index c8acc0eb4..7b431e422 100644 --- a/api/server.js +++ b/api/server.js @@ -5,6 +5,7 @@ const helmet = require('helmet'); const authenticate = require('../auth/authenticate-middleware.js'); const authRouter = require('../auth/auth-router.js'); const jokesRouter = require('../jokes/jokes-router.js'); +let userRouter = require('../users/users-router'); const server = express(); @@ -14,5 +15,6 @@ server.use(express.json()); server.use('/api/auth', authRouter); server.use('/api/jokes', authenticate, jokesRouter); +server.use('/api/user', authenticate, userRouter); module.exports = server; diff --git a/auth/auth-router.js b/auth/auth-router.js index 2fa2c9766..984dc7f36 100644 --- a/auth/auth-router.js +++ b/auth/auth-router.js @@ -1,11 +1,59 @@ const router = require('express').Router(); +let Users = require('../users/users-model'); + +let encrypt = require('bcryptjs'); +// let jwt = require('jsonwebtoken'); +let isValid = require('../utils/validate'); +const { createToken } = require('../utils/methods'); + router.post('/register', (req, res) => { // implement registration + let creds = req.body; + + if(isValid.isValid (creds)) { + let rounds = process.env.BCRYPT_ROUNDS || 8; // defaults to 8 on dev env + + let hash = encrypt.hashSync(creds.password, rounds) //takes pw from body and hashes it 8 times(dev) + + creds.password = hash; // sets original pw from body to newly hashed pw + + Users.create(creds) + .then(user => { + res.status(201).json({ data: user }) + }) + .catch(err => { + res.status(500).json({ error: "Could not create user"}) + }) + } else { + res.status(400).json({ message: "Provide a username and password" }); + } + }); router.post('/login', (req, res) => { // implement login + + let { username, password } = req.body; // extracting from body + + if(isValid.isValid(req.body)) { + Users.findBy({ username }) + .then(([ user ]) => { + if(user && encrypt.compareSync(password, user.password)) { + let token = createToken(user); // creates a token with payload + res.status(200).json({ token, message: "Login success" }) + } else { + res.status(401).json({ error: "Either username or password do not match in our records" }); + } + }) + .catch(err => { + res.status(500).json("Could not process request") + }) + } else { + res.status(400).json({ message: "Please provide a valid username and password"}) + } + + }); module.exports = router; diff --git a/database/auth.db3 b/database/auth.db3 index cc6ee6d93c913bdd08a9c0d42269f9e4d30d7d0d..c92c0286d976849fda5f8fa1f12374f990c99af5 100644 GIT binary patch delta 257 zcmZoTz}Rqrae_1>`$QRMR(1wG`ie3R z`I`Eqd8cOR=NDS&8KwB9M+Up(M7ZQ6TZR_-goKppB^EgwdwXQ)o9Gw1GlC8BNli~o zh8dLWT^W!Ynp2^l?&6t~Qkvyk7LXWT>X;H5k(uWgURafyD4&^G=#r%$S?HLO?d0KZ p5mFH7&BegLz{LNWf&Ux->&=1&_xVM+m?aq@E@a|lmgI!k0RW;iOJ@K8 delta 68 zcmZoTz}Rqrae_1>%S0JxRu%?5oq&xg3* { + res.status(200).json({ message: "Hello user" }) +}) + +module.exports = router; \ No newline at end of file diff --git a/utils/constants.js b/utils/constants.js new file mode 100644 index 000000000..f17445d7e --- /dev/null +++ b/utils/constants.js @@ -0,0 +1,3 @@ +module.exports = { + jwtSecret: process.env.JWT_SECRET || "real safe, real safe", +} \ No newline at end of file diff --git a/utils/methods.js b/utils/methods.js new file mode 100644 index 000000000..d856c4790 --- /dev/null +++ b/utils/methods.js @@ -0,0 +1,21 @@ +let jwt = require('jsonwebtoken'); +let constants = require('./constants') +module.exports = { + createToken, +} + +function createToken(user) { + let payload = { // returning parameter + subject: user.id, + username: user.username, + }; + + let secret = constants.jwtSecret; // returning parameter + + let options = { // returning parameter + //takes milliseconds but you can do '1d' etc + expiresIn: "1d" + } + + return jwt.sign(payload, secret, options) + } \ No newline at end of file diff --git a/utils/validate.js b/utils/validate.js new file mode 100644 index 000000000..91ce4fab7 --- /dev/null +++ b/utils/validate.js @@ -0,0 +1,7 @@ +module.exports = { + isValid, +} + +function isValid(user) { + return Boolean(user.username && user.password && typeof user.password === "string"); + }// checks to see if username and password exist, and if password is a valid alpha numerical string From cdd8da055e662319deb865fbae1828e0b39d6734 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 19 Jun 2020 13:53:51 -0400 Subject: [PATCH 3/6] middleware added --- auth/authenticate-middleware.js | 22 +++++++++++++++++++++- database/auth.db3 | Bin 24576 -> 24576 bytes 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/auth/authenticate-middleware.js b/auth/authenticate-middleware.js index 6ca61d0cd..df4df3bf8 100644 --- a/auth/authenticate-middleware.js +++ b/auth/authenticate-middleware.js @@ -1,8 +1,28 @@ +let jwt = require('jsonwebtoken'); +let constants = require('../utils/constants'); +const { jwtSecret } = require('../utils/constants'); + /* complete the middleware code to check if the user is logged in before granting access to the next middleware/route handler */ module.exports = (req, res, next) => { - res.status(401).json({ you: 'shall not pass!' }); + let token = req.headers.authorization; // grabs token from request headers property + let secret = constants.jwtSecret; + + if(token) { + jwt.verify(token, secret, (err, decodedToken) => { + if(err) { + res.status(401).json({ message: "Invalid token" }); + } else { + req.decodedToken = decodedToken; // creates a decoded token inside req + next(); + } + }) + } else { + res.status(401).json({ message: "valid credentials required" }); + } + + // res.status(401).json({ you: 'shall not pass!' }); }; diff --git a/database/auth.db3 b/database/auth.db3 index c92c0286d976849fda5f8fa1f12374f990c99af5..cb7de7d089f8428afa28b9b839397cdd6e1a272c 100644 GIT binary patch delta 173 zcmZoTz}Rqrae_1>=R_H2M$U~175a?Kn{VoC3ve;>D>LwK=g;F;-Yh5}%J1#T%*r6! z$m*6_l$V&7lCNTvsA6ED;^iD#5a{6+VU!u_XcSgZ=$%*)X<1s5nv#~`>*1RcmRlH* zVwoIK995uK>5^~ZZt0qrm^(Soe;UyIdkp;d_`mVL-YjTvfnSM-S(XuII5QWsB%^O? TPJT)y6DPAIr%!5nVsa$_+?X=j delta 80 zcmZoTz}Rqrae_1>`$QRMM)r*f75a=!n{VoC3ve*;=P~ea=g-?LD3HWIInRF@P~ Date: Fri, 19 Jun 2020 14:02:29 -0400 Subject: [PATCH 4/6] 2/4 questions --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index f54afeb86..f9f29affd 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,15 @@ Commit your code regularly and meaningfully. This helps both you (in case you ev Be prepared to demonstrate your understanding of this week's concepts by answering questions on the following topics. You might prepare by writing down your own answers before hand. 1. Differences between using _sessions_ or _JSON Web Tokens_ for authentication. + Sessions use cookies to create instances('sessions') which stores user information + that remains peristed until deleted. JWT store user information on generated token + that is a string of data holding user information. 2. What does `bcrypt` do to help us store passwords in a secure manner. + bcrypt secures passwords by hashing them, essentially scrambling the password + and breaking it down into layers of strings, this can be increased depending on the + amount of time the hash is set to happen. For dev. puposes, its around 8 and for + any production hashes, it is increased, varying on servers, and how much it can handle as it slows down the process a lot. 3. How are unit tests different from integration and end-to-end testing. From 714b2b19a7096260fe3d27f6f42ab019a3cb41f0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 19 Jun 2020 18:04:57 -0400 Subject: [PATCH 5/6] mvp --- api/server.js | 5 ++ api/server.spec.js | 15 +++++ auth/auth-router.spec.js | 131 +++++++++++++++++++++++++++++++++++++++ database/auth.db3 | Bin 24576 -> 24576 bytes package.json | 11 +++- users/users-router.js | 2 - 6 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 api/server.spec.js create mode 100644 auth/auth-router.spec.js diff --git a/api/server.js b/api/server.js index 7b431e422..e2043a26f 100644 --- a/api/server.js +++ b/api/server.js @@ -16,5 +16,10 @@ server.use(express.json()); server.use('/api/auth', authRouter); server.use('/api/jokes', authenticate, jokesRouter); server.use('/api/user', authenticate, userRouter); +// server.use('/api/user', userRouter); +server.get('/', (req, res) => { + res.status(200).json({ api: "up" }) +}) + module.exports = server; diff --git a/api/server.spec.js b/api/server.spec.js new file mode 100644 index 000000000..e0f9a8f7e --- /dev/null +++ b/api/server.spec.js @@ -0,0 +1,15 @@ +let supertest = require('supertest'); + +let server = require('./server'); + +describe("read server.js", () => { + describe("GET /", () => { + it("should return 200 OK status", () => { + return supertest(server) + .get("/") + .then(res => { + expect(res.status).toBe(200); + }) + }) + }) +}) \ No newline at end of file diff --git a/auth/auth-router.spec.js b/auth/auth-router.spec.js new file mode 100644 index 000000000..e5882fcaf --- /dev/null +++ b/auth/auth-router.spec.js @@ -0,0 +1,131 @@ +let server = require('../api/server'); + +let supertest = require('supertest'); + +let authRouter = require('./auth-router'); +let db = require('../database/dbConfig'); + + + describe("POST /login flow", () => { + it('should return status 200 OK', async () => { + let user = { + username: "legacy", + password: "mypw" + } + return await supertest(server) + .post('/api/auth/register') + .send(user) + .then(res => { + // console.log(res.body, 'asdfasdf') + // console.log(res.status) + expect(res.status).toBe(201); + // expect(res.body.data.username).toBe(user.username) + }) + }) + + it("Should succesfully give 200 status, succesful message", async() => { + let user = { + username: "legacy", + password: "mypw" + } + + return await supertest(server) + .post('/api/auth/login') + .send(user) + .then(res => { + console.log(res.status, "from login") + console.log(res.body, 'from login flow') + expect(res.status).toBe(200) + expect(res.body.message).toEqual("Login success" ) + + }) + }) + }) + +describe("auth-router.js", () => { + beforeEach(async () => { + await db("users").truncate(); + }) + + describe("POST /register", () => { + it('should return status 201 OK', async () => { + let user = { + username: "legacy", + password: "mypw" + } + return await supertest(server) + .post('/api/auth/register') + .send(user) + .then(res => { + console.log(res.body) + expect(res.status).toBe(201); + expect(res.body.data.username).toBe(user.username) + }) + }) + + it('should give 400 error for no username or password', async () => { + let user = { + username: "Bass", + password: null + } + + return await supertest(server) + .post('/api/auth/register') + .send(user) + .then(res => { + console.log(res.status) + console.log(res.body) + expect(res.status).toBe(400); + expect(res.body).toEqual({ message: 'Provide a username and password' }) + }) + }) + }) + + describe("POST /login", () => { + it("should return status 401", async () => { + let user = { + username: "legacy", + password: "mypw" + } + return await supertest(server) + .post('/api/auth/login') + .send(user) + .then(res => { + console.log(res.status, 'fail login') + expect(res.status).toBe(401) // no record on server + }) + }) + }) + + // describe("POST /login flow", () => { + // it('should return status 200 OK', async () => { + // let user = { + // username: "legacy", + // password: "mypw" + // } + // return await supertest(server) + // .post('/api/auth/register') + // .send(user) + // .then(res => { + // // console.log(res.body, 'asdfasdf') + // // console.log(res.status) + // expect(res.status).toBe(201); + // // expect(res.body.data.username).toBe(user.username) + // }) + // }) + + // it("Should succesfully give 200 status, succesful message", async() => { + // let user = { + // username: "legacy", + // password: "mypw" + // } + + // return await supertest(server) + // .post('/api/auth/login') + // .send(user) + // .then(res => { + // console.log(res.status, "from login") + // }) + // }) + // }) +}) \ No newline at end of file diff --git a/database/auth.db3 b/database/auth.db3 index cb7de7d089f8428afa28b9b839397cdd6e1a272c..d74d2b10fe6a4403fd6a4c1b006e622987f5f45d 100644 GIT binary patch delta 167 zcmZoTz}Rqrae@>RquE3mCm^{oVTn8!6aP&H{#X1r`Oj|_6ga}q&c#_;oLW@8`KG?M z02hM*0|Wnd{yctVprk1OWM%)^0XeDZiOH2JMu{p07Ahf@g(i6c1|IJD`tCmYhIx4v z28P9{W`*V671R1Ls5;Cm^{oVTn8!GygdT{#X1r`Oj?@6ga@o&B@Fx&RANUT2#!u z`KG?M08oK41OImZJbq=M0#W|S%Kozhd{WaBlPgt>5>*T=RC2v519C%iD)iG`JabY? zvwX_}62nU!Q$iy$^ZddKt5Op)GYeg^^dk!$Q?i{r+$};10=>By7#NuO?=kS- { From 3967642d06668990ce3b2ec117bb087ce25c57d8 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 19 Jun 2020 18:33:36 -0400 Subject: [PATCH 6/6] readme with answers to questions --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f9f29affd..5ffc23100 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,11 @@ Be prepared to demonstrate your understanding of this week's concepts by answeri any production hashes, it is increased, varying on servers, and how much it can handle as it slows down the process a lot. 3. How are unit tests different from integration and end-to-end testing. + - unit testing focuses on individual parts and tests those parts alone, + - integration and end to end focuses on 2 or more working together 4. How _Test Driven Development_ changes the way we write applications and tests. + rigorous testing of application as it develops You are expected to be able to answer questions in these areas. Your responses contribute to your Sprint Challenge grade. @@ -56,10 +59,10 @@ You are expected to be able to answer questions in these areas. Your responses c Your finished project must include all of the following requirements: -- [ ] An authentication workflow with functionality for account creation and login implemented inside `/auth/auth-router.js`. A `user` has `username` and `password`. Both properties are required. -- [ ] Middleware used to restrict access to resources for non authenticated requests. Use the file: `./auth/authenticate-middleware.js` as a starting point. -- [ ] Configuration for running tests using `Jest`. -- [ ] A **minimum o 2 tests** per API endpoint. +- [+] An authentication workflow with functionality for account creation and login implemented inside `/auth/auth-router.js`. A `user` has `username` and `password`. Both properties are required. +- [+] Middleware used to restrict access to resources for non authenticated requests. Use the file: `./auth/authenticate-middleware.js` as a starting point. +- [+] Configuration for running tests using `Jest`. +- [+] A **minimum o 2 tests** per API endpoint. **Note**: the database already has the users table, but if you run into issues, the migrations are available.