mirror of
https://github.com/standardnotes/server
synced 2026-07-31 14:16:46 -04:00
226 lines
7.8 KiB
TypeScript
226 lines
7.8 KiB
TypeScript
import { Result } from '@standardnotes/domain-core'
|
|
|
|
import { AuthResponse20200115 } from '../../Auth/AuthResponse20200115'
|
|
import { AuthResponseFactory20200115 } from '../../Auth/AuthResponseFactory20200115'
|
|
import { CrypterInterface } from '../../Encryption/CrypterInterface'
|
|
import { Setting } from '../../Setting/Setting'
|
|
import { SettingServiceInterface } from '../../Setting/SettingServiceInterface'
|
|
import { PKCERepositoryInterface } from '../../User/PKCERepositoryInterface'
|
|
import { User } from '../../User/User'
|
|
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
|
import { ClearLoginAttempts } from '../ClearLoginAttempts'
|
|
import { DeleteSetting } from '../DeleteSetting/DeleteSetting'
|
|
import { GenerateRecoveryCodes } from '../GenerateRecoveryCodes/GenerateRecoveryCodes'
|
|
import { IncreaseLoginAttempts } from '../IncreaseLoginAttempts'
|
|
import { SignInWithRecoveryCodes } from './SignInWithRecoveryCodes'
|
|
|
|
describe('SignInWithRecoveryCodes', () => {
|
|
let userRepository: UserRepositoryInterface
|
|
let authResponseFactory: AuthResponseFactory20200115
|
|
let pkceRepository: PKCERepositoryInterface
|
|
let crypter: CrypterInterface
|
|
let settingService: SettingServiceInterface
|
|
let generateRecoveryCodes: GenerateRecoveryCodes
|
|
let increaseLoginAttempts: IncreaseLoginAttempts
|
|
let clearLoginAttempts: ClearLoginAttempts
|
|
let deleteSetting: DeleteSetting
|
|
|
|
const createUseCase = () =>
|
|
new SignInWithRecoveryCodes(
|
|
userRepository,
|
|
authResponseFactory,
|
|
pkceRepository,
|
|
crypter,
|
|
settingService,
|
|
generateRecoveryCodes,
|
|
increaseLoginAttempts,
|
|
clearLoginAttempts,
|
|
deleteSetting,
|
|
)
|
|
|
|
beforeEach(() => {
|
|
userRepository = {} as jest.Mocked<UserRepositoryInterface>
|
|
userRepository.findOneByEmail = jest.fn().mockReturnValue({
|
|
uuid: '1-2-3',
|
|
encryptedPassword: '$2a$11$K3g6XoTau8VmLJcai1bB0eD9/YvBSBRtBhMprJOaVZ0U3SgasZH3a',
|
|
} as jest.Mocked<User>)
|
|
|
|
authResponseFactory = {} as jest.Mocked<AuthResponseFactory20200115>
|
|
authResponseFactory.createResponse = jest.fn().mockReturnValue({} as jest.Mocked<AuthResponse20200115>)
|
|
|
|
pkceRepository = {} as jest.Mocked<PKCERepositoryInterface>
|
|
pkceRepository.removeCodeChallenge = jest.fn().mockReturnValue(true)
|
|
|
|
crypter = {} as jest.Mocked<CrypterInterface>
|
|
crypter.base64URLEncode = jest.fn().mockReturnValue('base64-url-encoded')
|
|
crypter.sha256Hash = jest.fn().mockReturnValue('sha256-hashed')
|
|
|
|
settingService = {} as jest.Mocked<SettingServiceInterface>
|
|
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue({ value: 'foo' } as Setting)
|
|
|
|
generateRecoveryCodes = {} as jest.Mocked<GenerateRecoveryCodes>
|
|
generateRecoveryCodes.execute = jest.fn().mockReturnValue(Result.ok('1234 5678'))
|
|
|
|
increaseLoginAttempts = {} as jest.Mocked<IncreaseLoginAttempts>
|
|
increaseLoginAttempts.execute = jest.fn()
|
|
|
|
clearLoginAttempts = {} as jest.Mocked<ClearLoginAttempts>
|
|
clearLoginAttempts.execute = jest.fn()
|
|
|
|
deleteSetting = {} as jest.Mocked<DeleteSetting>
|
|
deleteSetting.execute = jest.fn()
|
|
})
|
|
|
|
it('should return error if password is not provided', async () => {
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: '',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Empty password')
|
|
})
|
|
|
|
it('should return error if username is not provided', async () => {
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Could not sign in with recovery codes: Username cannot be empty')
|
|
})
|
|
|
|
it('should return error if code verifier is not provided', async () => {
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: 'username',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: '',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Invalid code verifier')
|
|
})
|
|
|
|
it('should return error if recovery codes are not provided', async () => {
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: 'username',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Empty recovery codes')
|
|
})
|
|
|
|
it('should return error if code verifier is invalid', async () => {
|
|
pkceRepository.removeCodeChallenge = jest.fn().mockReturnValue(false)
|
|
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Invalid code verifier')
|
|
})
|
|
|
|
it('should return error if user is not found', async () => {
|
|
userRepository.findOneByEmail = jest.fn().mockReturnValue(undefined)
|
|
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Could not find user')
|
|
})
|
|
|
|
it('should return error if recovery codes are invalid', async () => {
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Invalid recovery codes')
|
|
})
|
|
|
|
it('should return error if password does not match', async () => {
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: 'asdasd123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Invalid password')
|
|
})
|
|
|
|
it('should return error if recovery codes are not generated for user', async () => {
|
|
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
|
|
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: '1234 5678',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('User does not have recovery codes generated')
|
|
})
|
|
|
|
it('should return error if generating new recovery codes fails', async () => {
|
|
generateRecoveryCodes.execute = jest.fn().mockReturnValue(Result.fail('Oops'))
|
|
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: 'foo',
|
|
})
|
|
|
|
expect(result.isFailed()).toBe(true)
|
|
expect(result.getError()).toBe('Could not sign in with recovery codes: Oops')
|
|
})
|
|
|
|
it('should return auth response', async () => {
|
|
const result = await createUseCase().execute({
|
|
userAgent: 'user-agent',
|
|
username: '[email protected]',
|
|
password: 'qweqwe123123',
|
|
codeVerifier: 'code-verifier',
|
|
recoveryCodes: 'foo',
|
|
})
|
|
|
|
expect(clearLoginAttempts.execute).toHaveBeenCalled()
|
|
expect(deleteSetting.execute).toHaveBeenCalled()
|
|
expect(result.isFailed()).toBe(false)
|
|
})
|
|
})
|