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

mvp #64

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

mvp #64

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
55 changes: 51 additions & 4 deletions api/auth/auth-router.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
const secrets = require('../config/secrets.js');
const jwt = require('jsonwebtoken');
const router = require('express').Router();
const Users = require("../users/user-model");
const bcrypt = require('bcryptjs');
const { checkPayload, isUsernameUnique, validateLogin,} = require('../middleware/auth-middleware');

router.post('/register', (req, res) => {
router.post('/register', isUsernameUnique , checkPayload,(req, res, next) => {
res.end('implement register, please!');

const { username, password } = req.body

const hash = bcrypt.hashSync(password, 8);
Users.add({ username, password: hash })
.then(newUser => {
res.status(200).json(newUser)
})
.catch(next)
});




/*
IMPLEMENT
You are welcome to build additional middlewares to help with the endpoint's functionality.
Expand All @@ -27,10 +46,27 @@ router.post('/register', (req, res) => {
4- On FAILED registration due to the `username` being taken,
the response body should include a string exactly as follows: "username taken".
*/
});

router.post('/login', (req, res) => {

router.post('/login' , validateLogin , checkPayload,(req, res, next) => {
res.end('implement login, please!');
const { username, password } = req.body

Users.findByUsername(username)
.then(([user]) => {
if (user && bcrypt.compareSync(password, user.password)) {
const token = createToken(user)
res.status(200).json({
message: `hello ${username}`,
token
})
} else {
next({ status:401, message: 'invalid credentials' })
}
})
.catch(next)

});
/*
IMPLEMENT
You are welcome to build additional middlewares to help with the endpoint's functionality.
Expand All @@ -54,6 +90,17 @@ router.post('/login', (req, res) => {
4- On FAILED login due to `username` not existing in the db, or `password` being incorrect,
the response body should include a string exactly as follows: "invalid credentials".
*/
});
function createToken(user) {
const payload = {
subject: user.id,
username: user.username,

};

const options = {
expiresIn: '1d',
};
return jwt.sign(payload, secrets.jwtSecret, options);
}

module.exports = router;
3 changes: 3 additions & 0 deletions api/config/secrets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
jwtSecret: process.env.JWT_SECRET || 'its a secret'
};
4 changes: 2 additions & 2 deletions api/jokes/jokes-router.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// do not make changes to this file
const router = require('express').Router();
const jokes = require('./jokes-data');

router.get('/', (req, res) => {
const restricted = require('../middleware/restricted.js');
router.get('/', restricted, (req, res) => {
res.status(200).json(jokes);
});

Expand Down
47 changes: 47 additions & 0 deletions api/middleware/auth-middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const Users = require('../users/user-model')

const checkPayload = (req, res, next) => {
try {
const { username, password } = req.body
if (!username || !password) {
res.status(404).json({message: 'A username and password is required'})
} else {
req.username = username
req.password = password
next()
}
} catch (err) {
next(err)
}}


const isUsernameUnique = async (req, res, next) => {
try {
const existingUsername = await Users.findByUsername(req.body.username)
if (!existingUsername.length) {
next()
} else {
next({ status: 401, message: 'this username is already taken' })
}
} catch (err) {
next(err)
}}


const validateLogin = async (req, res, next) => {
try {
const user = await Users.findByUsername(req.body.username)
const password = await Users.validatePassword(req.body.password)
if (!user || !password) {
next({ status: 400, message: 'invalid credentials' })
} else {
next()
}
} catch (err) {
next(err)
}}

module.exports = { checkPayload,
isUsernameUnique,
validateLogin,
};
18 changes: 16 additions & 2 deletions api/middleware/restricted.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
const jwt = require('jsonwebtoken');
const { JWT_SECRET } = require('../config/secrets');


module.exports = (req, res, next) => {
next();
const token = req.headers.authorization;
if (token) { jwt.verify(token, JWT_SECRET, (error, decoded) => {
if (error) {
next({ status: 401, message: 'token invalid' });
}
else {req.decodedJwt = decoded;
next();
}
});
} else {next({ status: 401, message: 'token required' });
}};
/*
IMPLEMENT

Expand All @@ -11,4 +25,4 @@ module.exports = (req, res, next) => {
3- On invalid or expired token in the Authorization header,
the response body should include a string exactly as follows: "token invalid".
*/
};

10 changes: 8 additions & 2 deletions api/server.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-unused-vars */
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
Expand All @@ -12,8 +13,13 @@ const server = express();
server.use(helmet());
server.use(cors());
server.use(express.json());

server.use((err, req, res, next) => {
res.status(err.status || 500).json({
message: err.message,
stack: err.stack,
})
})
server.use('/api/auth', authRouter);
server.use('/api/jokes', restrict, jokesRouter); // only logged-in users should have access!

server.get('/', (req, res) => {res.send('Hello there traveler')})
module.exports = server;
43 changes: 40 additions & 3 deletions api/server.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,41 @@
// Write your tests here
test('sanity', () => {
expect(true).toBe(false)
const request = require('supertest');
const server = require('./server');

test('environment', () => {
expect(process.env.NODE_ENV).toBe('testing')})


describe('[POST] /register', () => { test('responds with error when no username', async () => {

const res = await request(server).post('/api/auth/register').send({
username: '',
password: 'password',
})
expect(res.body).toMatchObject({message: 'username and password required'})
})
test('responds with error when no password', async () => {

const res = await request(server).post('/api/auth/register').send({
username: 'sakura',
password: '',
})
expect(res.body).toMatchObject({message: 'username and password required'})
})
})

describe('[POST] /login', () => { test('responds with error when no username', async () => {

const res = await request(server).post('/login').send({
username: '',
password: 'username'
})
expect(res.status).toBe(404)
})
test('responds with error when no password', async () => {

const res = await request(server).post('/api/auth/login').send({
username: 'MightGuy',
password: '',
})
expect(res.body).toMatchObject({message: 'username and password required'})
})})
33 changes: 33 additions & 0 deletions api/users/user-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const db = require('../../data/dbConfig');

function find() {
return db('users')
}

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

function findByUsername(username) {
return db('users')
.where('username', username)
}

function validatePassword(password) {
return db('users')
.where('password', password)
}

async function add(user) {
const id = await db('users').insert(user)
return findById(id)
}

module.exports = { find,
findById,
findByUsername,
validatePassword,
add,
};
11 changes: 11 additions & 0 deletions data/seeds/1-users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
exports.seed = function(knex,) {
return knex('users')
.truncate()
.then(function() {
return knex('users').insert([
{ username: 'naruto', password: 'password87'},
{ username: 'luffy', password: '00pirateking00'},
{ username: 'ichigo', password: 'number1bankai'},
]);
});
}