Files
paskia/frontend/src/stores/auth.js
T

178 lines
4.9 KiB
JavaScript

import { defineStore } from 'pinia'
import { register, authenticate } from '@/utils/passkey'
import { getSettings } from '@/utils/settings'
export const useAuthStore = defineStore('auth', {
state: () => ({
// Auth State
userInfo: null, // Contains the full user info response: {user, credentials, aaguid_info}
isLoading: false,
// Settings
settings: null,
// UI State
currentView: 'login',
status: {
message: '',
type: 'info',
show: false
},
}),
getters: {
},
actions: {
setLoading(flag) {
this.isLoading = !!flag
},
showMessage(message, type = 'info', duration = 3000) {
this.status = {
message,
type,
show: true
}
if (duration > 0) {
setTimeout(() => {
this.status.show = false
}, duration)
}
},
async setSessionCookie(sessionToken) {
const response = await fetch('/auth/api/set-session', {
method: 'POST',
headers: {'Authorization': `Bearer ${sessionToken}`},
})
const result = await response.json()
if (result.detail) {
throw new Error(result.detail)
}
return result
},
async register() {
this.isLoading = true
try {
const result = await register()
await this.setSessionCookie(result.session_token)
await this.loadUserInfo()
this.selectView()
return result
} finally {
this.isLoading = false
}
},
async authenticate() {
this.isLoading = true
try {
const result = await authenticate()
await this.setSessionCookie(result.session_token)
await this.loadUserInfo()
this.selectView()
return result
} finally {
this.isLoading = false
}
},
selectView() {
if (!this.userInfo) this.currentView = 'login'
else this.currentView = 'profile'
},
async loadSettings() {
this.settings = await getSettings()
},
async loadUserInfo() {
const response = await fetch('/auth/api/user-info', { method: 'POST' })
let result = null
try {
result = await response.json()
} catch (_) {
// ignore JSON parse errors (unlikely)
}
if (response.status === 401 && result?.detail) {
this.showMessage(result.detail, 'error', 5000)
throw new Error(result.detail)
}
if (result?.detail) {
// Other error style
this.showMessage(result.detail, 'error', 5000)
throw new Error(result.detail)
}
this.userInfo = result
console.log('User info loaded:', result)
},
async deleteCredential(uuid) {
const response = await fetch(`/auth/api/user/credential/${uuid}`, {method: 'Delete'})
const result = await response.json()
if (result.detail) throw new Error(`Server: ${result.detail}`)
await this.loadUserInfo()
},
async terminateSession(sessionId) {
try {
const res = await fetch(`/auth/api/user/session/${sessionId}`, { method: 'DELETE' })
let payload = null
try {
payload = await res.json()
} catch (_) {
// ignore JSON parse errors
}
if (!res.ok || payload?.detail) {
const message = payload?.detail || 'Failed to terminate session'
throw new Error(message)
}
if (payload?.current_session_terminated) {
sessionStorage.clear()
location.reload()
return
}
await this.loadUserInfo()
this.showMessage('Session terminated', 'success', 2500)
} catch (error) {
console.error('Terminate session error:', error)
throw error
}
},
async logout() {
try {
const res = await fetch('/auth/api/logout', {method: 'POST'})
if (!res.ok) {
let message = 'Logout failed'
try {
const data = await res.json()
if (data?.detail) message = data.detail
} catch (_) {
// ignore JSON parse errors
}
throw new Error(message)
}
sessionStorage.clear()
location.reload()
} catch (error) {
console.error('Logout error:', error)
this.showMessage(error.message, 'error')
}
},
async logoutEverywhere() {
try {
const res = await fetch('/auth/api/user/logout-all', {method: 'POST'})
if (!res.ok) {
let message = 'Logout failed'
try {
const data = await res.json()
if (data?.detail) message = data.detail
} catch (_) {
// ignore JSON parse errors
}
throw new Error(message)
}
sessionStorage.clear()
location.reload()
} catch (error) {
console.error('Logout-all error:', error)
this.showMessage(error.message, 'error')
}
},
}
})