authentication.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. import { ref } from 'vue'
  3. import { defineStore } from 'pinia'
  4. import { useLocalStorage } from '@vueuse/core'
  5. import { MutationHandler } from '#shared/server/apollo/handler/index.ts'
  6. import { useLoginMutation } from '#shared/graphql/mutations/login.api.ts'
  7. import { useLogoutMutation } from '#shared/graphql/mutations/logout.api.ts'
  8. import { clearApolloClientStore } from '#shared/server/apollo/client.ts'
  9. import useFingerprint from '#shared/composables/useFingerprint.ts'
  10. import testFlags from '#shared/utils/testFlags.ts'
  11. import {
  12. type EnumTwoFactorAuthenticationMethod,
  13. type LoginInput,
  14. } from '#shared/graphql/types.ts'
  15. import { useSessionStore } from './session.ts'
  16. import { useApplicationStore } from './application.ts'
  17. import { resetAndDisposeStores } from './index.ts'
  18. interface LoginOptions {
  19. login: string
  20. password: string
  21. rememberMe: boolean
  22. twoFactorAuthentication?: {
  23. method: EnumTwoFactorAuthenticationMethod
  24. payload: unknown
  25. }
  26. recoveryCode?: string
  27. }
  28. export const useAuthenticationStore = defineStore(
  29. 'authentication',
  30. () => {
  31. const authenticated = useLocalStorage<boolean>('authenticated', false)
  32. const externalLogout = ref(false)
  33. const { fingerprint } = useFingerprint()
  34. const clearAuthentication = async (): Promise<void> => {
  35. await clearApolloClientStore()
  36. const session = useSessionStore()
  37. session.resetCurrentSession()
  38. authenticated.value = false
  39. resetAndDisposeStores(true)
  40. // Refresh the config after logout, to have only the non authenticated version.
  41. await useApplicationStore().resetAndGetConfig()
  42. session.initialized = false
  43. }
  44. const refreshAfterAuthentication = async (): Promise<void> => {
  45. await Promise.all([
  46. useApplicationStore().getConfig(),
  47. useSessionStore().getCurrentUser(),
  48. ])
  49. }
  50. const logout = async (): Promise<void> => {
  51. const logoutMutation = new MutationHandler(useLogoutMutation())
  52. const result = await logoutMutation.send()
  53. if (result?.logout?.success) {
  54. if (result.logout.externalLogoutUrl) {
  55. externalLogout.value = true
  56. authenticated.value = false
  57. window.location.href = result.logout.externalLogoutUrl
  58. return
  59. }
  60. await clearAuthentication()
  61. testFlags.set('logout.success')
  62. }
  63. }
  64. const login = async ({
  65. login,
  66. password,
  67. rememberMe,
  68. twoFactorAuthentication,
  69. recoveryCode,
  70. }: LoginOptions) => {
  71. const loginInput: LoginInput = {
  72. login,
  73. password,
  74. rememberMe,
  75. }
  76. if (twoFactorAuthentication) {
  77. loginInput.twoFactorAuthentication = {
  78. twoFactorMethod: twoFactorAuthentication.method,
  79. twoFactorPayload: twoFactorAuthentication.payload,
  80. }
  81. } else if (recoveryCode) {
  82. loginInput.twoFactorRecovery = {
  83. recoveryCode,
  84. }
  85. }
  86. const loginMutation = new MutationHandler(
  87. useLoginMutation({
  88. variables: {
  89. input: loginInput,
  90. },
  91. context: {
  92. headers: {
  93. 'X-Browser-Fingerprint': fingerprint.value,
  94. },
  95. },
  96. }),
  97. )
  98. const result = await loginMutation.send()
  99. if (result?.login?.errors || !result) {
  100. return Promise.reject(result?.login?.errors)
  101. }
  102. const newSessionId = result.login?.session?.id || null
  103. if (newSessionId) {
  104. const session = useSessionStore()
  105. session.id = newSessionId
  106. authenticated.value = true
  107. await refreshAfterAuthentication()
  108. session.initialized = true
  109. }
  110. return {
  111. twoFactor: result.login?.twoFactorRequired,
  112. afterAuth: result.login?.session?.afterAuth,
  113. }
  114. }
  115. return {
  116. authenticated,
  117. externalLogout,
  118. clearAuthentication,
  119. logout,
  120. login,
  121. refreshAfterAuthentication,
  122. }
  123. },
  124. {
  125. requiresAuth: false,
  126. },
  127. )