1 parent
20735de62d
commit
e3cdde3c9e
4 files changed
+126
-42
No files matched your search
@@ -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 bcrypt from "bcrypt"
|
||||||
import AuthService from "../auth"
|
import AuthService from "../auth"
|
||||||
|
import { users, UserServiceMock } from "../__mocks__/user"
|
||||||
const UserModelMock = {
|
|
||||||
findOne: opt => {
|
|
||||||
return bcrypt
|
|
||||||
.hash("123456", 10)
|
|
||||||
.then(hash => ({ email: "email@mail.com", passwordHash: hash }))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("AuthService", () => {
|
describe("AuthService", () => {
|
||||||
describe("constructor", () => {
|
|
||||||
let authService
|
|
||||||
beforeAll(() => {
|
|
||||||
authService = new AuthService({ userModel: UserModelMock })
|
|
||||||
})
|
|
||||||
|
|
||||||
it("assigns userModel", () => {
|
|
||||||
expect(authService.userModel_).toEqual(UserModelMock)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("authenticate", () => {
|
describe("authenticate", () => {
|
||||||
let authService
|
let authService
|
||||||
|
authService = new AuthService({ userService: UserServiceMock })
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
authService = new AuthService({ userModel: UserModelMock })
|
jest.clearAllMocks()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns success when passwords match", async () => {
|
it("returns success and user when passwords match", async () => {
|
||||||
const result = await authService.authenticate("email@mail.com", "123456")
|
const result = await authService.authenticate(
|
||||||
|
"oliver@test.dk",
|
||||||
|
"123456789"
|
||||||
|
)
|
||||||
|
|
||||||
expect(result.success).toEqual(true)
|
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 () => {
|
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.success).toEqual(false)
|
||||||
|
expect(result.error).toEqual("Invalid email or password")
|
||||||
expect(result.user).toEqual(undefined)
|
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
|
* @implements BaseService
|
||||||
*/
|
*/
|
||||||
class AuthService extends BaseService {
|
class AuthService extends BaseService {
|
||||||
/** @param { userModel: (UserModel) } */
|
constructor({ userService }) {
|
||||||
constructor({ userModel }) {
|
|
||||||
super()
|
super()
|
||||||
/** @private @const {UserModel} */
|
/** @private @const {UserService} */
|
||||||
this.userModel_ = userModel
|
this.userService_ = userService
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,14 +25,13 @@ class AuthService extends BaseService {
|
|||||||
* error: a string with the error message
|
* error: a string with the error message
|
||||||
*/
|
*/
|
||||||
async authenticateAPIToken(token) {
|
async authenticateAPIToken(token) {
|
||||||
const user = await this.userModel_.findOne({ api_token: token })
|
try {
|
||||||
|
const user = await this.userService_.retrieveByApiToken(token)
|
||||||
if (user) {
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
user,
|
user,
|
||||||
}
|
}
|
||||||
} else {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: "Invalid API Token",
|
error: "Invalid API Token",
|
||||||
@@ -48,19 +46,27 @@ class AuthService extends BaseService {
|
|||||||
* @return {{ success: (bool), user: (object | undefined) }}
|
* @return {{ success: (bool), user: (object | undefined) }}
|
||||||
* success: whether authentication succeeded
|
* success: whether authentication succeeded
|
||||||
* user: the user document if authentication succeded
|
* user: the user document if authentication succeded
|
||||||
|
* error: a string with the error message
|
||||||
*/
|
*/
|
||||||
async authenticate(email, password) {
|
async authenticate(email, password) {
|
||||||
const user = await this.userModel_.findOne({ email })
|
try {
|
||||||
const passwordsMatch = await bcrypt.compare(password, user.passwordHash)
|
const user = await this.userService_.retrieveByEmail(email)
|
||||||
|
const passwordsMatch = await bcrypt.compare(password, user.password_hash)
|
||||||
if (passwordsMatch) {
|
if (passwordsMatch) {
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
user,
|
user,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "Invalid email or password",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
|
error: "Invalid email or password",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import mongoose from "mongoose"
|
|
||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import bcrypt from "bcrypt"
|
import bcrypt from "bcrypt"
|
||||||
import jwt from "jsonwebtoken"
|
import jwt from "jsonwebtoken"
|
||||||
@@ -83,7 +82,49 @@ class UserService extends BaseService {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_FOUND,
|
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
|
return user
|
||||||
|
|||||||
Reference in new issue
Block a user