useLoginTwoFactor.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { computed, ref, reactive } from 'vue'
  3. import { useTwoFactorPlugins } from '#shared/entities/two-factor/composables/useTwoFactorPlugins.ts'
  4. import type {
  5. LoginFlow,
  6. LoginCredentials,
  7. } from '#shared/entities/two-factor/types.ts'
  8. import type {
  9. EnumTwoFactorAuthenticationMethod,
  10. UserLoginTwoFactorMethods,
  11. } from '#shared/graphql/types.ts'
  12. import { useApplicationStore } from '#shared/stores/application.ts'
  13. const { twoFactorMethodLookup, twoFactorMethods } = useTwoFactorPlugins()
  14. const useLoginTwoFactor = (clearErrors: () => void) => {
  15. const application = useApplicationStore()
  16. const loginFlow = reactive<LoginFlow>({
  17. state: 'credentials',
  18. allowedMethods: [],
  19. defaultMethod: undefined,
  20. recoveryCodesAvailable: false,
  21. })
  22. const states = ref<LoginFlow['state'][]>([loginFlow.state])
  23. const updateState = (state: LoginFlow['state'], skipClearErrors = false) => {
  24. if (!skipClearErrors) clearErrors()
  25. states.value.push(state)
  26. loginFlow.state = state
  27. }
  28. const updateSecondFactor = (
  29. factor: EnumTwoFactorAuthenticationMethod,
  30. skipClearErrors = false,
  31. ) => {
  32. if (!skipClearErrors) clearErrors()
  33. loginFlow.twoFactor = factor
  34. updateState('2fa', true)
  35. }
  36. const askTwoFactor = (
  37. twoFactor: UserLoginTwoFactorMethods,
  38. formData: LoginCredentials,
  39. ) => {
  40. clearErrors()
  41. loginFlow.credentials = formData
  42. loginFlow.recoveryCodesAvailable = twoFactor.recoveryCodesAvailable
  43. loginFlow.allowedMethods = twoFactor.availableTwoFactorAuthenticationMethods
  44. loginFlow.defaultMethod = twoFactor.defaultTwoFactorAuthenticationMethod
  45. updateSecondFactor(
  46. twoFactor.defaultTwoFactorAuthenticationMethod as EnumTwoFactorAuthenticationMethod,
  47. true,
  48. )
  49. }
  50. const twoFactorAllowedMethods = computed(() => {
  51. return twoFactorMethods.filter((method) =>
  52. loginFlow.allowedMethods.includes(method.name),
  53. )
  54. })
  55. const twoFactorPlugin = computed(() => {
  56. return loginFlow.twoFactor
  57. ? twoFactorMethodLookup[loginFlow.twoFactor]
  58. : undefined
  59. })
  60. const hasAlternativeLoginMethod = computed(() => {
  61. return (
  62. twoFactorAllowedMethods.value.length > 1 ||
  63. loginFlow.recoveryCodesAvailable
  64. )
  65. })
  66. const statePreviousMap = {
  67. credentials: null,
  68. '2fa': 'credentials',
  69. '2fa-select': '2fa',
  70. 'recovery-code': '2fa-select',
  71. } satisfies Record<string, LoginFlow['state'] | null>
  72. const goBack = () => {
  73. clearErrors()
  74. const previousState = statePreviousMap[loginFlow.state] || 'credentials'
  75. loginFlow.state = previousState
  76. // if we go to the first state, reset credentials
  77. if (previousState === 'credentials') {
  78. loginFlow.credentials = undefined
  79. }
  80. }
  81. const cancelAndGoBack = () => {
  82. clearErrors()
  83. loginFlow.state = 'credentials'
  84. loginFlow.credentials = undefined
  85. }
  86. const loginPageTitle = computed(() => {
  87. const productName = application.config.product_name
  88. if (loginFlow.state === 'credentials') return productName
  89. if (loginFlow.state === 'recovery-code') return __('Recovery Code')
  90. if (loginFlow.state === '2fa') {
  91. return twoFactorPlugin.value?.label ?? productName
  92. }
  93. return __('Try Another Method')
  94. })
  95. return {
  96. loginFlow,
  97. hasAlternativeLoginMethod,
  98. askTwoFactor,
  99. twoFactorPlugin,
  100. twoFactorAllowedMethods,
  101. updateState,
  102. updateSecondFactor,
  103. goBack,
  104. cancelAndGoBack,
  105. statePreviousMap,
  106. loginPageTitle,
  107. }
  108. }
  109. export default useLoginTwoFactor