useLoginTwoFactor.spec.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { createTestingPinia } from '@pinia/testing'
  3. import { EnumTwoFactorAuthenticationMethod } from '#shared/graphql/types.ts'
  4. import { useApplicationStore } from '#shared/stores/application.ts'
  5. import useLoginTwoFactor from '../authentication/useLoginTwoFactor.ts'
  6. describe('useLoginTwoFactor', () => {
  7. createTestingPinia({ createSpy: vi.fn })
  8. it('can update login state', () => {
  9. const clearErrors = vi.fn()
  10. const { loginFlow, updateState } = useLoginTwoFactor(clearErrors)
  11. updateState('2fa')
  12. expect(clearErrors).toHaveBeenCalledOnce()
  13. expect(loginFlow.state).toBe('2fa')
  14. })
  15. it('can update second factor', () => {
  16. const clearErrors = vi.fn()
  17. const { loginFlow, updateSecondFactor } = useLoginTwoFactor(clearErrors)
  18. updateSecondFactor(EnumTwoFactorAuthenticationMethod.SecurityKeys)
  19. expect(clearErrors).toHaveBeenCalledOnce()
  20. expect(loginFlow.twoFactor).toBe(
  21. EnumTwoFactorAuthenticationMethod.SecurityKeys,
  22. )
  23. expect(loginFlow.state).toBe('2fa')
  24. })
  25. it('can ask for two-factor authentication', () => {
  26. const clearErrors = vi.fn()
  27. const { loginFlow, askTwoFactor } = useLoginTwoFactor(clearErrors)
  28. const testAllowedMethods = [
  29. EnumTwoFactorAuthenticationMethod.AuthenticatorApp,
  30. EnumTwoFactorAuthenticationMethod.SecurityKeys,
  31. ]
  32. const testDefaultMethod = EnumTwoFactorAuthenticationMethod.SecurityKeys
  33. const testCredentials = {
  34. login: 'foo',
  35. password: 'bar',
  36. rememberMe: true,
  37. }
  38. askTwoFactor(
  39. {
  40. availableTwoFactorAuthenticationMethods: testAllowedMethods,
  41. defaultTwoFactorAuthenticationMethod: testDefaultMethod,
  42. recoveryCodesAvailable: true,
  43. },
  44. testCredentials,
  45. )
  46. expect(clearErrors).toHaveBeenCalledOnce()
  47. expect(loginFlow.credentials).toEqual(testCredentials)
  48. expect(loginFlow.recoveryCodesAvailable).toBe(true)
  49. expect(loginFlow.allowedMethods).toEqual(testAllowedMethods)
  50. expect(loginFlow.defaultMethod).toEqual(testDefaultMethod)
  51. expect(loginFlow.twoFactor).toBe(testDefaultMethod)
  52. expect(loginFlow.state).toBe('2fa')
  53. })
  54. it('can filter for allowed two-factor methods', () => {
  55. const clearErrors = vi.fn()
  56. const { loginFlow, twoFactorAllowedMethods } =
  57. useLoginTwoFactor(clearErrors)
  58. loginFlow.allowedMethods = [
  59. EnumTwoFactorAuthenticationMethod.AuthenticatorApp,
  60. 'foobar' as EnumTwoFactorAuthenticationMethod,
  61. ]
  62. expect(twoFactorAllowedMethods.value).toEqual(
  63. expect.arrayContaining([
  64. expect.objectContaining({
  65. name: EnumTwoFactorAuthenticationMethod.AuthenticatorApp,
  66. }),
  67. ]),
  68. )
  69. expect(twoFactorAllowedMethods.value).toEqual(
  70. expect.not.arrayContaining([
  71. expect.objectContaining({
  72. name: EnumTwoFactorAuthenticationMethod.SecurityKeys,
  73. }),
  74. ]),
  75. )
  76. expect(twoFactorAllowedMethods.value).toEqual(
  77. expect.not.arrayContaining([
  78. expect.objectContaining({
  79. name: 'foobar',
  80. }),
  81. ]),
  82. )
  83. })
  84. it('can return current two-factor method plugin', () => {
  85. const clearErrors = vi.fn()
  86. const { loginFlow, twoFactorPlugin } = useLoginTwoFactor(clearErrors)
  87. loginFlow.twoFactor = EnumTwoFactorAuthenticationMethod.SecurityKeys
  88. expect(twoFactorPlugin.value).toEqual(
  89. expect.objectContaining({
  90. name: EnumTwoFactorAuthenticationMethod.SecurityKeys,
  91. }),
  92. )
  93. })
  94. it('can tell if there is an alternative login method', () => {
  95. const clearErrors = vi.fn()
  96. const { loginFlow, hasAlternativeLoginMethod } =
  97. useLoginTwoFactor(clearErrors)
  98. loginFlow.allowedMethods = [
  99. EnumTwoFactorAuthenticationMethod.AuthenticatorApp,
  100. EnumTwoFactorAuthenticationMethod.SecurityKeys,
  101. ]
  102. expect(hasAlternativeLoginMethod.value).toBe(true)
  103. })
  104. it('can go back to previous state in the flow', () => {
  105. const clearErrors = vi.fn()
  106. const { loginFlow, goBack } = useLoginTwoFactor(clearErrors)
  107. loginFlow.state = '2fa-select'
  108. goBack()
  109. expect(loginFlow.state).toBe('2fa')
  110. })
  111. it('can cancel login and go back to initial step', () => {
  112. const clearErrors = vi.fn()
  113. const { loginFlow, cancelAndGoBack } = useLoginTwoFactor(clearErrors)
  114. cancelAndGoBack()
  115. expect(loginFlow.state).toBe('credentials')
  116. expect(loginFlow.credentials).toBeUndefined()
  117. })
  118. it('can return current page title', () => {
  119. const clearErrors = vi.fn()
  120. useApplicationStore().config.product_name = 'Zammad'
  121. const { loginFlow, loginPageTitle } = useLoginTwoFactor(clearErrors)
  122. expect(loginPageTitle.value).toBe('Zammad')
  123. loginFlow.state = 'recovery-code'
  124. expect(loginPageTitle.value).toBe('Recovery Code')
  125. loginFlow.twoFactor = EnumTwoFactorAuthenticationMethod.AuthenticatorApp
  126. loginFlow.state = '2fa'
  127. expect(loginPageTitle.value).toBe('Authenticator App')
  128. loginFlow.state = '2fa-select'
  129. expect(loginPageTitle.value).toBe('Try Another Method')
  130. })
  131. })