From 99893fbb62e0c045762ec2546710ca0b82cddacd Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 18 Feb 2026 00:46:37 +0000 Subject: [PATCH] Identify sessions by session key - a hash that can be safely shared. --- frontend/src/admin/AdminUserDetail.vue | 12 ++++---- frontend/src/components/ProfileView.vue | 18 ++++++------ frontend/src/components/SessionList.vue | 39 ++++++++++++++----------- frontend/src/stores/auth.js | 4 +-- paskia/db/operations.py | 5 ++-- paskia/db/structs.py | 11 +++---- paskia/fastapi/admin.py | 13 ++++----- paskia/fastapi/api.py | 3 +- paskia/fastapi/oid.py | 8 ++--- paskia/fastapi/user.py | 5 +--- paskia/util/apistructs.py | 2 +- paskia/util/userinfo.py | 11 ++++--- 12 files changed, 65 insertions(+), 66 deletions(-) diff --git a/frontend/src/admin/AdminUserDetail.vue b/frontend/src/admin/AdminUserDetail.vue index 96658eb..c71a0b0 100644 --- a/frontend/src/admin/AdminUserDetail.vue +++ b/frontend/src/admin/AdminUserDetail.vue @@ -57,11 +57,11 @@ async function handleDelete(credential) { } async function handleTerminateSession(session) { - const sessionId = session?.id - if (!sessionId) return - terminatingSessions.value = { ...terminatingSessions.value, [sessionId]: true } + const sessionKey = session?.key + if (!sessionKey) return + terminatingSessions.value = { ...terminatingSessions.value, [sessionKey]: true } try { - const data = await apiJson(`/auth/api/admin/users/${props.selectedUser.uuid}/sessions/${sessionId}`, { method: 'DELETE' }) + const data = await apiJson(`/auth/api/admin/users/${props.selectedUser.uuid}/sessions/${sessionKey}`, { method: 'DELETE' }) if (data.status === 'ok') { if (data.current_session_terminated) { sessionStorage.clear() @@ -78,7 +78,7 @@ async function handleTerminateSession(session) { authStore.showMessage(err.message || 'Failed to terminate session', 'error') } finally { const next = { ...terminatingSessions.value } - delete next[sessionId] + delete next[sessionKey] terminatingSessions.value = next } } @@ -232,7 +232,7 @@ defineExpose({ focusFirstElement }) { const rpName = computed(() => authStore.settings?.rp_name || 'this service') const paskiaVersion = computed(() => authStore.settings?.version || '') -const sessions = computed(() => authStore.userInfo?.sessions || []) +const sessions = computed(() => authStore.userInfo?.sessions || {}) const currentSessionHost = computed(() => { - const currentSession = sessions.value.find(session => session.is_current) + const currentSession = Object.values(sessions.value).find(session => session.is_current) return currentSession?.host || 'this host' }) const terminatingSessions = ref({}) const terminateSession = async (session) => { - const sessionId = session?.id - if (!sessionId) return - terminatingSessions.value = { ...terminatingSessions.value, [sessionId]: true } - try { await authStore.terminateSession(sessionId) } + const sessionKey = session?.key + if (!sessionKey) return + terminatingSessions.value = { ...terminatingSessions.value, [sessionKey]: true } + try { await authStore.terminateSession(sessionKey) } catch (error) { authStore.showMessage(error.message || 'Failed to terminate session', 'error', 5000) } finally { const next = { ...terminatingSessions.value } - delete next[sessionId] + delete next[sessionKey] terminatingSessions.value = next } } @@ -368,12 +368,12 @@ const isAdmin = computed(() => { const perms = authStore.ctx?.permissions return perms?.includes('auth:admin') || perms?.includes('auth:org:admin') }) -const hasMultipleSessions = computed(() => sessions.value.length > 1) +const hasMultipleSessions = computed(() => Object.keys(sessions.value).length > 1) const credentials = computed(() => authStore.userInfo?.credentials ? Object.values(authStore.userInfo.credentials) : []) const useWideLayout = computed(() => { // Check if any single site has more than 8 sessions const groups = {} - for (const session of sessions.value) { + for (const session of Object.values(sessions.value)) { const host = session.host || '' if (!groups[host]) groups[host] = [] groups[host].push(session) diff --git a/frontend/src/components/SessionList.vue b/frontend/src/components/SessionList.vue index 09c6922..ebb81f2 100644 --- a/frontend/src/components/SessionList.vue +++ b/frontend/src/components/SessionList.vue @@ -6,7 +6,7 @@
-