authentication.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { useLocalStorage } from '@vueuse/core'
  3. import { defineStore } from 'pinia'
  4. import { ref } from 'vue'
  5. import useFingerprint from '#shared/composables/useFingerprint.ts'
  6. import { useLoginMutation } from '#shared/graphql/mutations/login.api.ts'
  7. import { useLogoutMutation } from '#shared/graphql/mutations/logout.api.ts'
  8. import {
  9. type EnumTwoFactorAuthenticationMethod,
  10. type LoginInput,
  11. } from '#shared/graphql/types.ts'
  12. import { clearApolloClientStore } from '#shared/server/apollo/client.ts'
  13. import { MutationHandler } from '#shared/server/apollo/handler/index.ts'
  14. import testFlags from '#shared/utils/testFlags.ts'
  15. import { useApplicationStore } from './application.ts'
  16. import { resetAndDisposeStores } from './index.ts'
  17. import { useSessionStore } from './session.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 setAuthenticatedSessionId = async (newSessionId: string | null) => {
  65. if (!newSessionId) return false
  66. const session = useSessionStore()
  67. session.id = newSessionId
  68. authenticated.value = true
  69. await refreshAfterAuthentication()
  70. session.initialized = true
  71. return true
  72. }
  73. const login = async ({
  74. login,
  75. password,
  76. rememberMe,
  77. twoFactorAuthentication,
  78. recoveryCode,
  79. }: LoginOptions) => {
  80. const loginInput: LoginInput = {
  81. login,
  82. password,
  83. rememberMe,
  84. }
  85. if (twoFactorAuthentication) {
  86. loginInput.twoFactorAuthentication = {
  87. twoFactorMethod: twoFactorAuthentication.method,
  88. twoFactorPayload: twoFactorAuthentication.payload,
  89. }
  90. } else if (recoveryCode) {
  91. loginInput.twoFactorRecovery = {
  92. recoveryCode,
  93. }
  94. }
  95. const loginMutation = new MutationHandler(
  96. useLoginMutation({
  97. variables: {
  98. input: loginInput,
  99. },
  100. context: {
  101. headers: {
  102. 'X-Browser-Fingerprint': fingerprint.value,
  103. },
  104. },
  105. }),
  106. )
  107. const result = await loginMutation.send()
  108. if (result?.login?.errors || !result) {
  109. return Promise.reject(result?.login?.errors)
  110. }
  111. await setAuthenticatedSessionId(result.login?.session?.id || null)
  112. return {
  113. twoFactor: result.login?.twoFactorRequired,
  114. afterAuth: result.login?.session?.afterAuth,
  115. }
  116. }
  117. return {
  118. authenticated,
  119. externalLogout,
  120. clearAuthentication,
  121. logout,
  122. login,
  123. refreshAfterAuthentication,
  124. setAuthenticatedSessionId,
  125. }
  126. },
  127. {
  128. requiresAuth: false,
  129. },
  130. )