Skip to content

Commit

Permalink
add authenticate logic, handler and tests; update index with that cha…
Browse files Browse the repository at this point in the history
…nges b00tc4mp#407
  • Loading branch information
berlem authored and berlem committed Feb 22, 2024
1 parent ef6a196 commit a308169
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 3 deletions.
37 changes: 37 additions & 0 deletions staff/belen-ivars/project/api/handlers/authenticateUserHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import jwt from 'jsonwebtoken'
import logic from '../logic/index.js'
import { errors } from 'com'

const { ContentError, TokenError, CredentialsError, NotFoundError } = errors

export default (req, res) => {
const { email, password } = req.body

try {
logic.authenticateUser(email, password)

.then(userId => {
const token = jwt.sign({ sub: userId }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXP })

res.json(token)
})
.catch(error => {

let status = 500
if (error instanceof NotFoundError)
status = 404

else if (error instanceof CredentialsError)
status = 401

res.status(status).json({ error: error.constructor.name, message: error.message })
})

} catch (error) {
let status = 500
if (error instanceof ContentError || error instanceof TypeError)

status = 406
res.status(status).json({ error: error.constructor.name, message: error.message })
}
}
4 changes: 3 additions & 1 deletion staff/belen-ivars/project/api/handlers/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import registerUserHandler from './registerUserHandler.js'
import authenticateUserHandler from './authenticateUserHandler.js'

export {
registerUserHandler
registerUserHandler,
authenticateUserHandler
}
6 changes: 5 additions & 1 deletion staff/belen-ivars/project/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import express from 'express'
import cors from 'cors'

import {
registerUserHandler
registerUserHandler,
authenticateUserHandler

} from './handlers/index.js'

mongoose.connect(process.env.MONGODB_URL)
Expand All @@ -21,6 +23,8 @@ mongoose.connect(process.env.MONGODB_URL)

server.post('/users', jsonBodyParser, registerUserHandler)

server.post('/users/auth', jsonBodyParser, authenticateUserHandler)

server.listen(process.env.PORT, () => console.log(`server running on port ${process.env.PORT}`))
})

Expand Down
39 changes: 39 additions & 0 deletions staff/belen-ivars/project/api/logic/authenticateUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import bcrypt from 'bcryptjs'
import { validate, errors } from 'com'
import { User } from '../data/models.js'

const { SystemError, CredentialsError, NotFoundError } = errors

function authenticateUser(email, password) {
validate.email(email, 'email')
validate.password(password, 'password')

return (async () => {

let user
try {
user = await User.findOne({ email })
} catch (error) {

throw new SystemError(error.message)
}

if (!user)
throw new NotFoundError('user not found')

let match
try {
match = await bcrypt.compare(password, user.password)
} catch (error) {
throw new SystemError(error.message)
}

if (!match)
throw new CredentialsError('wrong password')

return user.id

})()
}

export default authenticateUser
66 changes: 66 additions & 0 deletions staff/belen-ivars/project/api/logic/authenticateUser.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import dotenv from 'dotenv'
dotenv.config()

import mongoose, { mongo } from 'mongoose'

import { expect } from 'chai'
import bcrypt from 'bcryptjs'
import random from './helpers/random.js'
import authenticateUser from './authenticateUser.js'
import { errors } from 'com'
import { User } from '../data/models.js'

const { NotFoundError, CredentialsError } = errors

describe('authenticateUser', () => {
before(async () => await mongoose.connect(process.env.TEST_MONGODB_URL))
beforeEach(async () => await User.deleteMany())

it('succeds on correct credentials', async () => {
const name = random.name()
const email = random.email()
const password = random.password()

const hash = await bcrypt.hash(password, 8)
const user = await User.create({ name, email, password: hash })

const userId = await authenticateUser(email, password)


expect(userId).to.be.a('string')
expect(userId).to.have.lengthOf(24)
expect(userId).to.equal(user.id)

})

it('fails on wrong email', async () => {
const email = random.email()
const password = random.password()

try {
await authenticateUser(email, password)
throw new Error('should not reach this point')
} catch (error) {
expect(error).to.be.instanceOf(NotFoundError)
expect(error.message).to.equal('user not found')
}
})

it('fails on wrong password', async () => {
const name = random.name()
const email = random.email()
const password = random.password()

const user = await User.create({ name, email, password })

try {
await authenticateUser(email, password + 'wrong')
throw new Error('should not reach this point')
} catch (error) {
expect(error).to.be.instanceOf(CredentialsError)
expect(error.message).to.equal('wrong password')
}
})

after(async () => await mongoose.disconnect())
})
15 changes: 15 additions & 0 deletions staff/belen-ivars/project/api/logic/authenticateUser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import dotenv from 'dotenv'
dotenv.config()
import mongoose from 'mongoose'

import authenticateUser from './authenticateUser.js'

(async () => {
await mongoose.connect(process.env.MONGODB_URL)
try {
await authenticateUser('[email protected]', '123123123')
console.log('user authenticated')
} catch (error) {
console.log(error)
}
})()
4 changes: 3 additions & 1 deletion staff/belen-ivars/project/api/logic/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import registerUser from './registerUser.js'
import authenticateUser from './authenticateUser.js'

const logic = {
registerUser
registerUser,
authenticateUser
}

export default logic
86 changes: 86 additions & 0 deletions staff/belen-ivars/project/api/test/authenticate-user.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
source pepetest.sh

TEST 'authenticate-user'

CASE 'success on correct credentials'

curl 'http://localhost:9000/users/auth' \
-H 'Content-Type: application/json' \
-d '{"email": "[email protected]", "password": "123123123"}' \
-v

# > POST /users/auth HTTP/1.1
# > Host: localhost:9000
# > User-Agent: curl/8.4.0
# > Accept: */*
# > Content-Type: application/json
# > Content-Length: 51
# >
# < HTTP/1.1 200 OK
# < X-Powered-By: Express
# < Access-Control-Allow-Origin: *
# < Content-Type: application/json; charset=utf-8
# < Content-Length: 174
# < ETag: W/"ae-xoMjJkMAcoU50Y0NdIBS6tqorMI"
# < Date: Thu, 22 Feb 2024 17:37:25 GMT
# < Connection: keep-alive
# < Keep-Alive: timeout=5
# <
# * Connection #0 to host localhost left intact
# "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NWQ2NTZlYWE5MmU4NWM5ZjlmYTZkNzEiLCJpYXQiOjE3MDg2MjM0NDUsImV4cCI6MTcwODYyNzA0NX0.k6C_Yv259KFl4Mx0QyPcuuW3FfwrM6scbbJ_VxLk65s"

CASE "fail on wrong email"

curl 'http://localhost:9000/users/auth' \
-H 'Content-Type: application/json' \
-d '{ "email": "[email protected]", "password": "123123123"
}' \
-v

# > POST /users/auth HTTP/1.1
# > Host: localhost:9000
# > User-Agent: curl/8.4.0
# > Accept: */*
# > Content-Type: application/json
# > Content-Length: 77
# >
# < HTTP/1.1 404 Not Found
# < X-Powered-By: Express
# < Access-Control-Allow-Origin: *
# < Content-Type: application/json; charset=utf-8
# < Content-Length: 52
# < ETag: W/"34-Cs2INrsYwSHLSHCKVUFPEWh9NjI"
# < Date: Thu, 22 Feb 2024 17:37:25 GMT
# < Connection: keep-alive
# < Keep-Alive: timeout=5
# <
# * Connection #0 to host localhost left intact
# {"error":"NotFoundError","message":"user not found"}

CASE "fail on wrong password"

curl 'http://localhost:9000/users/auth' \
-H 'Content-Type: application/json' \
-d '{ "email": "[email protected]", "password": "123123124"
}' \
-v

# > POST /users/auth HTTP/1.1
# > Host: localhost:9000
# > User-Agent: curl/8.4.0
# > Accept: */*
# > Content-Type: application/json
# > Content-Length: 54
# >
# < HTTP/1.1 401 Unauthorized
# < X-Powered-By: Express
# < Access-Control-Allow-Origin: *
# < Content-Type: application/json; charset=utf-8
# < Content-Length: 55
# < ETag: W/"37-3mBc0WtcQO2Ze4UXSt4AJH7BRe8"
# < Date: Thu, 22 Feb 2024 17:49:59 GMT
# < Connection: keep-alive
# < Keep-Alive: timeout=5
# <
# * Connection #0 to host localhost left intact
# {"error":"CredentialsError","message":"wrong password"}%

0 comments on commit a308169

Please sign in to comment.