Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update #10

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ 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 that store the user's data and remains in memory until the instance is deleted. With tokens the data is stored and passed back and forth. This is best suited for communication between trusted devices.

2. What does `bcrypt` do to help us store passwords in a secure manner.
bcrypt provides an efficent way for us to hash our passwords.

3. How are unit tests different from integration and end-to-end testing.
Unit test only focus on a relativley small piece of the code. Intergration tests focus on two "layers" of code and how well they communicate with each other. End-to-end testing focuses on the functionality of the entire program.

4. How _Test Driven Development_ changes the way we write applications and tests.
TDD makes you more mindful of how clean code should be written and how each piece works together before you begin writing the program.

You are expected to be able to answer questions in these areas. Your responses contribute to your Sprint Challenge grade.

Expand Down
86 changes: 86 additions & 0 deletions api/server..spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
const request = require('supertest')
const db = require('../database/dbConfig');
const server = require('./server');

describe('end point tests', function() {
describe('POST /register and POST /login', function() {
beforeAll(async() => {
await db('users').truncate();
})

//#1 should return status 201
it('POST /auth/register', function() {
return request(server)
.post('/api/auth/register')
.send({ username: "test", password: "1234567" })
.then(res => {
console.log(res.body)
expect(res.status).toBe(201)
expect(res.body.data.username).toBe(user.username)
})
})

//#2 should give 400 error for invalid credentials'
it(' POST /auth/register', function() {
return request(server)
.post('/api/auth/register')
.send({ username: "nope" , password: "nope" })
.then(res => {
console.log(res.status)
console.log(res.body)
expect(res.status).toBe(400);
expect(res.body).toEqual({ message: 'incorrect username/password' })
})
})

//#3 should return status 200
it('POST /auth/login', function() {
return request(server)
.post('/api/auth/login')
.send({ username: 'test', password: '1234567' })
.then(res => {
const token = res.data.token
return request(server)
.get('/api/jokes/')
.set({token})
.then(res => {
expect(res.status).toBe(200);
})
})
})

//#4 res.type should match json
it(' POST /auth/login"', function() {
return request(server)
.post('/api/auth/login')
.send({ username: "test", password: "1234567" })
.then(res => {
const token = res.data.token
return request(server)
.get('/api/jokes/')
.set({token})
.then(res => {
expect(res.type).toMatch(/json/i);
})
})
})

//#5 res.type should match json
it(' GET /jokes/', function() {
return request(server)
.get('/api/jokes/')
.then(res => {
expect(res.type).toMatch(/json/i);
})
})

//#6 should return a response
it(' GET /jokes/', function() {
return request(server)
.get('/api/jokes/')
.then(res => {
expect(res.body).toBeTruthy();
})
})
})
})
14 changes: 14 additions & 0 deletions api/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,17 @@ server.use('/api/auth', authRouter);
server.use('/api/jokes', authenticate, jokesRouter);

module.exports = server;

// function checkRole(user) {
// return (req, res, next) => {
// if (
// req.decodedToken &&
// req.decodedToken.role &&
// req.decodedToken.role.toLowerCase() === user
// ) {
// next()
// } else {
// res.status(403).json({ message: 'Must be logged in' })
// }
// }
// }
14 changes: 14 additions & 0 deletions auth/Token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const jwt = require('jsonwebtoken');
const { jwtSecret } = require('../secrets/authSecret');

function Token(username) {
const payload = {
subject: username.id,
username: username.username,
role: username.role || 'user',
};

return jwt.sign(payload, jwtSecret);
}

module.exports = Token;
38 changes: 36 additions & 2 deletions auth/auth-router.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,45 @@
const router = require('express').Router();
const bcrypt = require('bcryptjs');

const Users = require('../users/model');
const newToken = require('./Token');
const { validateUser } = require('../users/validation');

router.post('/register', (req, res) => {
// implement registration
let user = req.body
const validateResult = validateUser(user);
if (validateResult.isSuccessful === true) {
const hash = bcrypt.hashSync(user.password, 10);
user.password = hash;
Users.add(user)
.then(saved => {
const token = newToken(saved);
res.status(201).json(token);
})
.catch(err => {
res.status(500).json({ message: 'Error', err })
})
} else {
res.status(400).json({ Message: 'invalid', errors: validateUser(user) })
}
});

router.post('/login', (req, res) => {
// implement login
let { username, password } = req.body;
Users.findBy({ username })
.first()
.then(user => {
if (user && bcrypt.compareSync(password, user.password)) {
const token = newToken(user);
res.status(200).json({ Message: `Welcome ${user.username}`, token });
} else {
res.status(401).json({ Message: 'Credentials invalid' });
}
})
.catch(err => {
res.status(500).json({ Message: 'Error' })
})
});


module.exports = router;
35 changes: 35 additions & 0 deletions auth/auth.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
let supertest = require('supertest');
let server = require('../api/server');

let authRouter = require('./auth-router');
let db = require('../database/dbConfig');


describe("create user", () => {
it('should register new user', async () => {
const res = await supertest(server)
.post("/api/auth/register")
.send({
username: "Reggie",
password: "321cba"
})
expect(res.statusCode).toBe(201)
expect(res.type).toBe("application/json")
})

it("Should return 200 status", async() => {
let user = {
username: "Reggie",
password: "321cba"
}

return await supertest(server)
.post('/api/auth/login')
.send(user)
.then(res => {
expect(res.status).toBe(200)
expect(res.body.message).toEqual("Welcome Reggie!" )

})
})
})
42 changes: 34 additions & 8 deletions auth/authenticate-middleware.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
/*
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!' });
};
const jwt = require('jsonwebtoken');
// const { jwtSecret } = require('../secrets/authSecret');


function restrict() {
return async (req, res, next) => {
const authError = {err: 'invalid credentials'}
try{
const token = req.headers.authorization
if(!token) {return res.status(401).json(authError)}
jwt.verify(token, 'safe', (err, decoded) => {
if(err) {return res.status(401).json(authError)}
next()
})
}
catch(err) {next(err)}
}
}


module.exports = restrict

// = req.headers;
// if (authorization) {
// jwt.verify(authorization, jwtSecret, (err, decodedToken) => {
// if (err) {
// res.status(401).json({ message: "Invalid credentials" });
// } else {
// req.decodedToken = decodedToken;
// next();
// }
// });
// } else {
// res.status(400).json({ message: "Please enter credentials" });
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const server = require('./api/server.js');

const PORT = process.env.PORT || 3300;
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`\n=== Server listening on port ${PORT} ===\n`);
});
14 changes: 13 additions & 1 deletion jokes/jokes-router.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const axios = require('axios');
const Users = require('../users/model')
const restricted = require('../auth/authenticate-middleware')

const router = require('express').Router();

router.get('/', (req, res) => {
router.get('/', restricted(), (req, res) => {
const requestOptions = {
headers: { accept: 'application/json' },
};
Expand All @@ -17,4 +19,14 @@ router.get('/', (req, res) => {
});
});

router.get('/user', restricted(), (req, res) => {
Users.find()
.then(param => {
res.status(200).json(param)
})
.catch(err => {
res.status(500).json(err)
})
})

module.exports = router;
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"description": "Authentication Sprint Challenge",
"main": "index.js",
"scripts": {
"server": "nodemon index.js"
"server": "nodemon index.js",
"test": "jest --watchAll"
},
"repository": {
"type": "git",
Expand All @@ -19,13 +20,21 @@
"homepage": "https://github.com/LambdaSchool/Sprint-Challenge-Authentication#readme",
"dependencies": {
"axios": "^0.19.2",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"helmet": "^3.22.0",
"jsonwebtoken": "^8.5.1",
"knex": "^0.21.0",
"sqlite3": "^4.1.1"
},
"devDependencies": {
"nodemon": "^2.0.3"
"cross-env": "^7.0.2",
"jest": "^26.4.2",
"knex-cleaner": "^1.3.1",
"nodemon": "^2.0.3",
"supertest": "^4.0.2"
}
}
5 changes: 5 additions & 0 deletions secrets/authSecret.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {

jwtSecret: process.env.JWT_SECRET || 'secret',

}
24 changes: 24 additions & 0 deletions users/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const db = require('../database/dbConfig');
module.exports = {
add,
find,
findBy,
findById
}

function find() {
return db('users').select('id', 'username', 'password');
}

function findBy(filter) {
return db('users').where(filter);
}

function findById(id) {
return db('users').where({ id }).first();
}

async function add(user) {
const [id] = await db('users').insert(user);
return findById(id);
}
16 changes: 16 additions & 0 deletions users/validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function validateUser(user) {
let errors = [];

if (!user.username || user.username.length >= 7) {
errors.push('Username must have at least seven characters');
}
if (!user.password || user.password.length >= 7) {
errors.push('Password must be at least seven characters')
}
return {
isSuccessful: errors.length > 0 ? false : true,
errors,
}
}

module.exports = { validateUser }