Files
standardnotes-server/packages/auth/src/Infra/InversifyExpressUtils/InversifyExpressUsersController.spec.ts
T

424 lines
14 KiB
TypeScript

import 'reflect-metadata'
import * as express from 'express'
import { InversifyExpressUsersController } from './InversifyExpressUsersController'
import { results } from 'inversify-express-utils'
import { Username } from '@standardnotes/domain-core'
import { DeleteAccount } from '../../Domain/UseCase/DeleteAccount/DeleteAccount'
import { ChangeCredentials } from '../../Domain/UseCase/ChangeCredentials/ChangeCredentials'
import { ClearLoginAttempts } from '../../Domain/UseCase/ClearLoginAttempts'
import { GetUserKeyParams } from '../../Domain/UseCase/GetUserKeyParams/GetUserKeyParams'
import { GetUserSubscription } from '../../Domain/UseCase/GetUserSubscription/GetUserSubscription'
import { IncreaseLoginAttempts } from '../../Domain/UseCase/IncreaseLoginAttempts'
import { InviteToSharedSubscription } from '../../Domain/UseCase/InviteToSharedSubscription/InviteToSharedSubscription'
import { UpdateUser } from '../../Domain/UseCase/UpdateUser'
import { User } from '../../Domain/User/User'
describe('InversifyExpressUsersController', () => {
let updateUser: UpdateUser
let deleteAccount: DeleteAccount
let getUserKeyParams: GetUserKeyParams
let getUserSubscription: GetUserSubscription
let clearLoginAttempts: ClearLoginAttempts
let increaseLoginAttempts: IncreaseLoginAttempts
let changeCredentials: ChangeCredentials
let inviteToSharedSubscription: InviteToSharedSubscription
let request: express.Request
let response: express.Response
let user: User
const createController = () =>
new InversifyExpressUsersController(
updateUser,
getUserKeyParams,
deleteAccount,
getUserSubscription,
clearLoginAttempts,
increaseLoginAttempts,
changeCredentials,
)
beforeEach(() => {
updateUser = {} as jest.Mocked<UpdateUser>
updateUser.execute = jest.fn()
deleteAccount = {} as jest.Mocked<DeleteAccount>
deleteAccount.execute = jest.fn().mockReturnValue({ success: true, message: 'A OK', responseCode: 200 })
user = {} as jest.Mocked<User>
user.uuid = '123'
user.email = '[email protected]'
getUserKeyParams = {} as jest.Mocked<GetUserKeyParams>
getUserKeyParams.execute = jest.fn()
getUserSubscription = {} as jest.Mocked<GetUserSubscription>
getUserSubscription.execute = jest.fn()
changeCredentials = {} as jest.Mocked<ChangeCredentials>
changeCredentials.execute = jest.fn()
clearLoginAttempts = {} as jest.Mocked<ClearLoginAttempts>
clearLoginAttempts.execute = jest.fn()
increaseLoginAttempts = {} as jest.Mocked<IncreaseLoginAttempts>
increaseLoginAttempts.execute = jest.fn()
inviteToSharedSubscription = {} as jest.Mocked<InviteToSharedSubscription>
inviteToSharedSubscription.execute = jest.fn()
request = {
headers: {},
body: {},
params: {},
} as jest.Mocked<express.Request>
response = {
locals: {},
} as jest.Mocked<express.Response>
response.status = jest.fn().mockReturnThis()
response.setHeader = jest.fn()
response.send = jest.fn()
})
it('should update user', async () => {
request.body.version = '002'
request.body.api = '20190520'
request.body.origination = 'test'
request.params.userId = '123'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
updateUser.execute = jest.fn().mockReturnValue({ success: true, authResponse: { foo: 'bar' } })
const httpResponse = <results.JsonResult>await createController().update(request, response)
const result = await httpResponse.executeAsync()
expect(updateUser.execute).toHaveBeenCalledWith({
apiVersion: '20190520',
updatedWithUserAgent: 'Google Chrome',
user: {
uuid: '123',
email: '[email protected]',
},
})
expect(await result.content.readAsStringAsync()).toEqual('{"foo":"bar"}')
})
it('should not update user if session has read only access', async () => {
request.body.version = '002'
request.body.api = '20190520'
request.body.origination = 'test'
request.params.userId = '123'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
response.locals.readOnlyAccess = true
const httpResponse = <results.JsonResult>await createController().update(request, response)
const result = await httpResponse.executeAsync()
expect(updateUser.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(401)
})
it('should not update a user if the procedure fails', async () => {
request.body.version = '002'
request.body.api = '20190520'
request.body.origination = 'test'
request.params.userId = '123'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
updateUser.execute = jest.fn().mockReturnValue({ success: false })
const httpResponse = <results.JsonResult>await createController().update(request, response)
const result = await httpResponse.executeAsync()
expect(updateUser.execute).toHaveBeenCalledWith({
apiVersion: '20190520',
updatedWithUserAgent: 'Google Chrome',
user: {
uuid: '123',
email: '[email protected]',
},
})
expect(result.statusCode).toEqual(400)
expect(await result.content.readAsStringAsync()).toEqual('{"error":{"message":"Could not update user."}}')
})
it('should not update a user if it is not the same as logged in user', async () => {
request.body.version = '002'
request.body.api = '20190520'
request.body.origination = 'test'
request.params.userId = '234'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
const httpResponse = <results.JsonResult>await createController().update(request, response)
const result = await httpResponse.executeAsync()
expect(updateUser.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(401)
expect(await result.content.readAsStringAsync()).toEqual('{"error":{"message":"Operation not allowed."}}')
})
it('should delete user', async () => {
request.params.email = '[email protected]'
const httpResponse = <results.JsonResult>await createController().deleteAccount(request)
const result = await httpResponse.executeAsync()
expect(deleteAccount.execute).toHaveBeenCalledWith({ email: '[email protected]' })
expect(result.statusCode).toEqual(200)
expect(await result.content.readAsStringAsync()).toEqual('{"message":"A OK"}')
})
it('should get user key params', async () => {
request.query = {
email: '[email protected]',
uuid: '1-2-3',
}
getUserKeyParams.execute = jest.fn().mockReturnValue({ foo: 'bar' })
const httpResponse = <results.JsonResult>await createController().keyParams(request)
const result = await httpResponse.executeAsync()
expect(getUserKeyParams.execute).toHaveBeenCalledWith({
email: '[email protected]',
userUuid: '1-2-3',
authenticated: false,
})
expect(result.statusCode).toEqual(200)
})
it('should get authenticated user key params', async () => {
request.query = {
email: '[email protected]',
uuid: '1-2-3',
authenticated: 'true',
}
getUserKeyParams.execute = jest.fn().mockReturnValue({ foo: 'bar' })
const httpResponse = <results.JsonResult>await createController().keyParams(request)
const result = await httpResponse.executeAsync()
expect(getUserKeyParams.execute).toHaveBeenCalledWith({
email: '[email protected]',
userUuid: '1-2-3',
authenticated: true,
})
expect(result.statusCode).toEqual(200)
})
it('should not get user key params if email and user uuid is missing', async () => {
request.query = {}
getUserKeyParams.execute = jest.fn().mockReturnValue({ foo: 'bar' })
const httpResponse = <results.JsonResult>await createController().keyParams(request)
const result = await httpResponse.executeAsync()
expect(getUserKeyParams.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(400)
})
it('should get user subscription', async () => {
request.params.userUuid = '1-2-3'
response.locals.user = {
uuid: '1-2-3',
}
getUserSubscription.execute = jest.fn().mockReturnValue({
success: true,
})
const httpResponse = <results.JsonResult>await createController().getSubscription(request, response)
const result = await httpResponse.executeAsync()
expect(getUserSubscription.execute).toHaveBeenCalledWith({
userUuid: '1-2-3',
})
expect(result.statusCode).toEqual(200)
})
it('should not get user subscription if the user with provided uuid does not exist', async () => {
request.params.userUuid = '1-2-3'
response.locals.user = {
uuid: '1-2-3',
}
getUserSubscription.execute = jest.fn().mockReturnValue({
success: false,
})
const httpResponse = <results.JsonResult>await createController().getSubscription(request, response)
const result = await httpResponse.executeAsync()
expect(getUserSubscription.execute).toHaveBeenCalledWith({ userUuid: '1-2-3' })
expect(result.statusCode).toEqual(400)
})
it('should not get user subscription if not allowed', async () => {
request.params.userUuid = '1-2-3'
response.locals.user = {
uuid: '2-3-4',
}
getUserSubscription.execute = jest.fn()
const httpResponse = <results.JsonResult>await createController().getSubscription(request, response)
const result = await httpResponse.executeAsync()
expect(getUserSubscription.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(401)
})
it('should change a password', async () => {
request.body.version = '004'
request.body.api = '20190520'
request.body.current_password = 'test123'
request.body.new_password = 'test234'
request.body.pw_nonce = 'asdzxc'
request.body.origination = 'change-password'
request.body.created = '123'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
changeCredentials.execute = jest.fn().mockReturnValue({ success: true, authResponse: { foo: 'bar' } })
const httpResponse = <results.JsonResult>await createController().changeCredentials(request, response)
const result = await httpResponse.executeAsync()
expect(changeCredentials.execute).toHaveBeenCalledWith({
apiVersion: '20190520',
updatedWithUserAgent: 'Google Chrome',
currentPassword: 'test123',
newPassword: 'test234',
kpCreated: '123',
kpOrigination: 'change-password',
pwNonce: 'asdzxc',
protocolVersion: '004',
username: Username.create('[email protected]').getValue(),
})
expect(clearLoginAttempts.execute).toHaveBeenCalled()
expect(await result.content.readAsStringAsync()).toEqual('{"foo":"bar"}')
})
it('should not change a password if session has read only access', async () => {
request.body.version = '004'
request.body.api = '20190520'
request.body.current_password = 'test123'
request.body.new_password = 'test234'
request.body.pw_nonce = 'asdzxc'
request.body.origination = 'change-password'
request.body.created = '123'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
response.locals.readOnlyAccess = true
const httpResponse = <results.JsonResult>await createController().changeCredentials(request, response)
const result = await httpResponse.executeAsync()
expect(changeCredentials.execute).not.toHaveBeenCalled()
expect(clearLoginAttempts.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(401)
})
it('should indicate if changing a password fails', async () => {
request.body.version = '004'
request.body.api = '20190520'
request.body.current_password = 'test123'
request.body.new_password = 'test234'
request.body.pw_nonce = 'asdzxc'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
changeCredentials.execute = jest.fn().mockReturnValue({ success: false, errorMessage: 'Something bad happened' })
const httpResponse = <results.JsonResult>await createController().changeCredentials(request, response)
const result = await httpResponse.executeAsync()
expect(increaseLoginAttempts.execute).toHaveBeenCalled()
expect(result.statusCode).toEqual(401)
expect(await result.content.readAsStringAsync()).toEqual('{"error":{"message":"Something bad happened"}}')
})
it('should not change a password if current password is missing', async () => {
request.body.version = '004'
request.body.api = '20190520'
request.body.new_password = 'test234'
request.body.pw_nonce = 'asdzxc'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
const httpResponse = <results.JsonResult>await createController().changeCredentials(request, response)
const result = await httpResponse.executeAsync()
expect(changeCredentials.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(400)
expect(await result.content.readAsStringAsync()).toEqual(
'{"error":{"message":"Your current password is required to change your password. Please update your application if you do not see this option."}}',
)
})
it('should not change a password if new password is missing', async () => {
request.body.version = '004'
request.body.api = '20190520'
request.body.current_password = 'test123'
request.body.pw_nonce = 'asdzxc'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
const httpResponse = <results.JsonResult>await createController().changeCredentials(request, response)
const result = await httpResponse.executeAsync()
expect(changeCredentials.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(400)
expect(await result.content.readAsStringAsync()).toEqual(
'{"error":{"message":"Your new password is required to change your password. Please try again."}}',
)
})
it('should not change a password if password nonce is missing', async () => {
request.body.version = '004'
request.body.api = '20190520'
request.body.current_password = 'test123'
request.body.new_password = 'test234'
request.headers['user-agent'] = 'Google Chrome'
response.locals.user = user
const httpResponse = <results.JsonResult>await createController().changeCredentials(request, response)
const result = await httpResponse.executeAsync()
expect(changeCredentials.execute).not.toHaveBeenCalled()
expect(result.statusCode).toEqual(400)
expect(await result.content.readAsStringAsync()).toEqual(
'{"error":{"message":"The change password request is missing new auth parameters. Please try again."}}',
)
})
})