feat: replace success modal with non-blocking toast notification
All checks were successful
Code Analysis and Production Deploy / analyze (push) Successful in 5m10s
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 2m14s

feat: add global event listener for mannschaften updates in Navigation component

feat: notify app of mannschaften changes after CSV save and handle visibility changes

refactor: remove unused anlagen page

fix: update CmsMannschaften reference in sportbetrieb page for reactivity

fix: enhance authentication token retrieval in passkey API endpoints

feat: implement refresh session and access token generation for Android clients in passkey login

fix: unify token retrieval method across passkey API endpoints

feat: add MediaTypes utility for JSON content type in Android app

feat: create PasskeyRepository for handling passkey authentication and registration in Android app

feat: add validated text field and rich text components for Android UI

feat: implement newsletter subscription and unsubscription screens in Android app

feat: create public pages including Impressum with dynamic content loading
This commit is contained in:
Torsten Schulz (local)
2026-05-28 08:33:28 +02:00
parent e033d716dd
commit 0528334eb4
37 changed files with 1297 additions and 364 deletions

View File

@@ -1,7 +1,7 @@
import { getUserFromToken } from '../../../utils/auth.js'
export default defineEventHandler(async (event) => {
const token = getCookie(event, 'auth_token')
const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '')
const user = token ? await getUserFromToken(token) : null
if (!user) {
@@ -24,4 +24,3 @@ export default defineEventHandler(async (event) => {
}
})

View File

@@ -1,5 +1,5 @@
import { verifyAuthenticationResponse } from '@simplewebauthn/server'
import { createSession, generateToken, migrateUserRoles, readUsers, writeUsers } from '../../../utils/auth.js'
import { createRefreshSession, createSession, generateAndroidAccessToken, generateToken, migrateUserRoles, readUsers, writeUsers } from '../../../utils/auth.js'
import { getWebAuthnConfig } from '../../../utils/webauthn-config.js'
import { consumeAuthChallenge } from '../../../utils/webauthn-challenges.js'
import { fromBase64Url, parseClientDataJSON } from '../../../utils/webauthn-encoding.js'
@@ -39,6 +39,7 @@ export default defineEventHandler(async (event) => {
const ip = getClientIp(event)
const body = await readBody(event)
const isAndroidClient = body?.client === 'android'
const response = body?.credential
if (!response) {
throw createError({ statusCode: 400, statusMessage: 'Credential fehlt' })
@@ -105,10 +106,21 @@ export default defineEventHandler(async (event) => {
passkey.lastUsedAt = new Date().toISOString()
await writeUsers(users)
const token = generateToken(user)
await createSession(user.id, token)
let token
let refreshSession = null
if (isAndroidClient) {
refreshSession = await createRefreshSession(user.id, body?.deviceName || 'Harheimer TC Android-App')
token = generateAndroidAccessToken(user, refreshSession.session.id)
} else {
token = generateToken(user)
await createSession(user.id, token)
}
setCookie(event, 'auth_token', token, { ...getAuthCookieOptions() })
if (isAndroidClient) {
deleteCookie(event, 'auth_token')
} else {
setCookie(event, 'auth_token', token, { ...getAuthCookieOptions() })
}
await writeAuditLog('auth.passkey.login.success', { ip, userId: user.id })
@@ -120,6 +132,9 @@ export default defineEventHandler(async (event) => {
return {
success: true,
token,
accessToken: isAndroidClient ? token : undefined,
refreshToken: refreshSession?.refreshToken,
sessionId: refreshSession?.session.id,
user: {
id: user.id,
email: user.email,
@@ -129,4 +144,3 @@ export default defineEventHandler(async (event) => {
role: roles[0] || 'mitglied'
}
})

View File

@@ -33,7 +33,7 @@ export default defineEventHandler(async (event) => {
return { success: true }
}
const token = getCookie(event, 'auth_token')
const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '')
const user = token ? await getUserFromToken(token) : null
if (!user) {
@@ -119,4 +119,3 @@ export default defineEventHandler(async (event) => {
await writeAuditLog('auth.passkey.registered', { userId: user.id })
return { success: true, message: 'Passkey hinzugefügt.' }
})

View File

@@ -26,7 +26,7 @@ export default defineEventHandler(async (event) => {
? body.preferredAuthenticatorType
: undefined
const token = getCookie(event, 'auth_token')
const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '')
const user = token ? await getUserFromToken(token) : null
if (!user) {
@@ -83,4 +83,3 @@ export default defineEventHandler(async (event) => {
return { success: true, options }
})

View File

@@ -2,7 +2,7 @@ import { getUserFromToken, readUsers, writeUsers } from '../../../utils/auth.js'
import { writeAuditLog } from '../../../utils/audit-log.js'
export default defineEventHandler(async (event) => {
const token = getCookie(event, 'auth_token')
const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '')
const currentUser = token ? await getUserFromToken(token) : null
if (!currentUser) {
@@ -36,4 +36,3 @@ export default defineEventHandler(async (event) => {
}
})