141 lines
4.3 KiB
JavaScript
141 lines
4.3 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
import { register, authenticate } from '@/utils/passkey'
|
|
|
|
export const useAuthStore = defineStore('auth', {
|
|
state: () => ({
|
|
// Auth State
|
|
userInfo: null, // Contains the full user info response: {user, credentials, aaguid_info, session_type, authenticated}
|
|
settings: null, // Server provided settings (/auth/settings)
|
|
isLoading: false,
|
|
resetToken: null, // transient reset token
|
|
restrictedMode: false, // If true, app loaded outside /auth/ and should restrict to login or permission denied
|
|
|
|
// UI State
|
|
currentView: 'login',
|
|
status: {
|
|
message: '',
|
|
type: 'info',
|
|
show: false
|
|
},
|
|
}),
|
|
actions: {
|
|
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/set-session', {
|
|
method: 'POST',
|
|
headers: {'Authorization': `Bearer ${sessionToken}`},
|
|
})
|
|
const result = await response.json()
|
|
if (result.detail) {
|
|
throw new Error(result.detail)
|
|
}
|
|
// On successful session establishment, discard any reset token to avoid
|
|
// sending stale Authorization headers on subsequent API calls.
|
|
this.resetToken = null
|
|
return result
|
|
},
|
|
async register() {
|
|
this.isLoading = true
|
|
try {
|
|
const result = await register()
|
|
await this.setSessionCookie(result.session_token)
|
|
await this.loadUserInfo()
|
|
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()
|
|
|
|
return result
|
|
} finally {
|
|
this.isLoading = false
|
|
}
|
|
},
|
|
selectView() {
|
|
if (this.restrictedMode) {
|
|
// In restricted mode only allow login or show permission denied if already authenticated
|
|
if (!this.userInfo) this.currentView = 'login'
|
|
else if (this.userInfo.authenticated) this.currentView = 'permission-denied'
|
|
else this.currentView = 'login' // do not expose reset/registration flows outside /auth/
|
|
return
|
|
}
|
|
if (!this.userInfo) this.currentView = 'login'
|
|
else if (this.userInfo.authenticated) this.currentView = 'profile'
|
|
else this.currentView = 'reset'
|
|
},
|
|
setRestrictedMode(flag) {
|
|
this.restrictedMode = !!flag
|
|
},
|
|
async loadUserInfo() {
|
|
const headers = {}
|
|
// Reset tokens are only passed via query param now, not Authorization header
|
|
const url = this.resetToken ? `/auth/user-info?reset=${encodeURIComponent(this.resetToken)}` : '/auth/user-info'
|
|
const response = await fetch(url, { method: 'POST', headers })
|
|
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 loadSettings() {
|
|
try {
|
|
const res = await fetch('/auth/settings')
|
|
if (!res.ok) return
|
|
const data = await res.json()
|
|
this.settings = data
|
|
if (data?.rp_name) {
|
|
document.title = data.rp_name
|
|
}
|
|
} catch (_) {
|
|
// ignore
|
|
}
|
|
},
|
|
async deleteCredential(uuid) {
|
|
const response = await fetch(`/auth/credential/${uuid}`, {method: 'Delete'})
|
|
const result = await response.json()
|
|
if (result.detail) throw new Error(`Server: ${result.detail}`)
|
|
|
|
await this.loadUserInfo()
|
|
},
|
|
async logout() {
|
|
try {
|
|
await fetch('/auth/logout', {method: 'POST'})
|
|
} catch (error) {
|
|
console.error('Logout error:', error)
|
|
}
|
|
|
|
this.userInfo = null
|
|
},
|
|
}
|
|
})
|