Fixes according to issue #21 (#35)

This commit is contained in:
Oliver Windall Juhl
2020-04-14 21:44:05 +02:00
committed by GitHub
parent 20735de62d
commit e3cdde3c9e
4 changed files with 126 additions and 42 deletions

View File

@@ -0,0 +1,32 @@
import bcrypt from "bcrypt"
export const users = {
user1: {
email: "oliver@test.dk",
password_hash: "123456789",
api_token: "123456789",
},
}
export const UserServiceMock = {
retrieveByApiToken: jest.fn().mockImplementation(token => {
if (token === "123456789") {
return Promise.resolve(users.user1)
}
return Promise.resolve(undefined)
}),
retrieveByEmail: jest.fn().mockImplementation(email => {
if (email === "oliver@test.dk") {
return bcrypt
.hash("123456789", 10)
.then(hash => ({ email, password_hash: hash }))
}
return Promise.resolve(undefined)
}),
}
const mock = jest.fn().mockImplementation(() => {
return UserServiceMock
})
export default mock

View File

@@ -1,44 +1,49 @@
import bcrypt from "bcrypt"
import AuthService from "../auth"
const UserModelMock = {
findOne: opt => {
return bcrypt
.hash("123456", 10)
.then(hash => ({ email: "email@mail.com", passwordHash: hash }))
},
}
import { users, UserServiceMock } from "../__mocks__/user"
describe("AuthService", () => {
describe("constructor", () => {
let authService
beforeAll(() => {
authService = new AuthService({ userModel: UserModelMock })
})
it("assigns userModel", () => {
expect(authService.userModel_).toEqual(UserModelMock)
})
})
describe("authenticate", () => {
let authService
authService = new AuthService({ userService: UserServiceMock })
beforeEach(() => {
authService = new AuthService({ userModel: UserModelMock })
jest.clearAllMocks()
})
it("returns success when passwords match", async () => {
const result = await authService.authenticate("email@mail.com", "123456")
it("returns success and user when passwords match", async () => {
const result = await authService.authenticate(
"oliver@test.dk",
"123456789"
)
expect(result.success).toEqual(true)
expect(result.user.email).toEqual("email@mail.com")
expect(result.user.email).toEqual("oliver@test.dk")
})
it("returns failure when passwords don't match", async () => {
const result = await authService.authenticate("email@mail.com", "not")
const result = await authService.authenticate(
"oliver@test.dk",
"invalid-password"
)
expect(result.success).toEqual(false)
expect(result.error).toEqual("Invalid email or password")
expect(result.user).toEqual(undefined)
})
})
describe("authenticateAPIToken", () => {
let authService
authService = new AuthService({ userService: UserServiceMock })
beforeEach(() => {
jest.clearAllMocks()
})
it("returns success and user when passwords match", async () => {
const result = await authService.authenticateAPIToken("123456789")
expect(result.success).toEqual(true)
expect(result.user).toEqual(users.user1)
})
})
})

View File

@@ -6,11 +6,10 @@ import { BaseService } from "medusa-interfaces"
* @implements BaseService
*/
class AuthService extends BaseService {
/** @param { userModel: (UserModel) } */
constructor({ userModel }) {
constructor({ userService }) {
super()
/** @private @const {UserModel} */
this.userModel_ = userModel
/** @private @const {UserService} */
this.userService_ = userService
}
/**
@@ -26,14 +25,13 @@ class AuthService extends BaseService {
* error: a string with the error message
*/
async authenticateAPIToken(token) {
const user = await this.userModel_.findOne({ api_token: token })
if (user) {
try {
const user = await this.userService_.retrieveByApiToken(token)
return {
success: true,
user,
}
} else {
} catch (error) {
return {
success: false,
error: "Invalid API Token",
@@ -48,19 +46,27 @@ class AuthService extends BaseService {
* @return {{ success: (bool), user: (object | undefined) }}
* success: whether authentication succeeded
* user: the user document if authentication succeded
* error: a string with the error message
*/
async authenticate(email, password) {
const user = await this.userModel_.findOne({ email })
const passwordsMatch = await bcrypt.compare(password, user.passwordHash)
if (passwordsMatch) {
return {
success: true,
user,
try {
const user = await this.userService_.retrieveByEmail(email)
const passwordsMatch = await bcrypt.compare(password, user.password_hash)
if (passwordsMatch) {
return {
success: true,
user,
}
} else {
return {
success: false,
error: "Invalid email or password",
}
}
} else {
} catch (error) {
return {
success: false,
error: "Invalid email or password",
}
}
}

View File

@@ -1,4 +1,3 @@
import mongoose from "mongoose"
import _ from "lodash"
import bcrypt from "bcrypt"
import jwt from "jsonwebtoken"
@@ -83,7 +82,49 @@ class UserService extends BaseService {
if (!user) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`User with ${userId} was not found`
`User with id: ${userId} was not found`
)
}
return user
}
/**
* Gets a user by api token.
* Throws in case of DB Error and if user was not found.
* @param {string} apiToken - the token of the user to get.
* @return {Promise<User>} the user document.
*/
async retrieveByApiToken(apiToken) {
const user = await this.userModel_
.findOne({ api_token: apiToken })
.catch(err => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
if (!user) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`User with api token: ${apiToken} was not found`
)
}
return user
}
/**
* Gets a user by email.
* Throws in case of DB Error and if user was not found.
* @param {string} email - the email of the user to get.
* @return {Promise<User>} the user document.
*/
async retrieveByEmail(email) {
const user = await this.userModel_.findOne({ email }).catch(err => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
if (!user) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`User with email: ${email} was not found`
)
}
return user