committed by
GitHub
parent
20735de62d
commit
e3cdde3c9e
32
packages/medusa/src/services/__mocks__/user.js
Normal file
32
packages/medusa/src/services/__mocks__/user.js
Normal 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
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user