LoginTwoFactor.vue 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <!-- Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { useNotifications } from '#shared/components/CommonNotifications/useNotifications.ts'
  4. import Form from '#shared/components/Form/Form.vue'
  5. import type { FormData, FormSchemaNode } from '#shared/components/Form/types.ts'
  6. import type { TwoFactorPlugin } from '#shared/entities/two-factor/types.ts'
  7. import UserError from '#shared/errors/UserError.ts'
  8. import { useAuthenticationStore } from '#shared/stores/authentication.ts'
  9. import { computed } from 'vue'
  10. import type { LoginFormData, TwoFactorFormData } from '../types/login.ts'
  11. const props = defineProps<{
  12. credentials: FormData<LoginFormData>
  13. twoFactor: TwoFactorPlugin
  14. }>()
  15. const emit = defineEmits<{
  16. (e: 'finish'): void
  17. (e: 'error', error: UserError): void
  18. }>()
  19. // TODO: this should be configurable by two factor plugin
  20. const schema: FormSchemaNode[] = [
  21. {
  22. isLayout: true,
  23. component: 'FormGroup',
  24. props: {
  25. help: computed(() => props.twoFactor.helpMessage),
  26. },
  27. children: [
  28. {
  29. type: 'text',
  30. name: 'code',
  31. label: __('Security Code'),
  32. required: true,
  33. props: {
  34. autocomplete: 'one-time-code',
  35. autofocus: true,
  36. inputmode: 'numeric',
  37. pattern: '[0-9]*',
  38. },
  39. },
  40. ],
  41. },
  42. ]
  43. const { clearAllNotifications } = useNotifications()
  44. const authentication = useAuthenticationStore()
  45. const confirmTwoFactor = (formData: FormData<TwoFactorFormData>) => {
  46. // Clear notifications to avoid duplicated error messages.
  47. clearAllNotifications()
  48. const { login, password, rememberMe } = props.credentials
  49. return authentication
  50. .login(login, password, rememberMe, {
  51. payload: formData.code,
  52. method: props.twoFactor.name,
  53. })
  54. .then(() => {
  55. emit('finish')
  56. })
  57. .catch((error: UserError) => {
  58. if (error instanceof UserError) {
  59. emit('error', error)
  60. }
  61. })
  62. }
  63. </script>
  64. <template>
  65. <Form
  66. :schema="schema"
  67. @submit="confirmTwoFactor($event as FormData<TwoFactorFormData>)"
  68. >
  69. <template #after-fields>
  70. <FormKit
  71. wrapper-class="mt-6 flex grow justify-center items-center"
  72. input-class="py-2 px-4 w-full h-14 text-xl rounded-xl select-none"
  73. variant="submit"
  74. type="submit"
  75. >
  76. {{ $t('Sign in') }}
  77. </FormKit>
  78. </template>
  79. </Form>
  80. </template>