Files
dticket.tootaio.com/server/utils/auth.ts
xiaomai cb683d6b3d feat(bookings): restrict management to assigned PIC or super admin
Secure API endpoints with requireBookingManager authorization check
Update confirmation page to prompt for login if unauthorized
Add safe redirect handling to login and guest middleware
2026-05-09 13:28:50 +08:00

89 lines
2.0 KiB
TypeScript

import type { H3Event } from 'h3'
import type { PublicBooking } from '~~/shared/booking'
import { normalizeUsername, type UserRole } from '~~/shared/auth'
import { createUserSession, destroyUserSession, getUserSession } from './session'
import { getUserById, updateLastLogin, type UserAuthRecord } from './user-repository'
export async function getAuthContext(event: H3Event): Promise<{
session: Awaited<ReturnType<typeof getUserSession>>
user: UserAuthRecord
} | null> {
const session = await getUserSession(event)
if (!session) {
return null
}
const user = await getUserById(session.userId)
if (!user || !user.isActive) {
await destroyUserSession(event)
return null
}
return {
session,
user
}
}
export async function requireAuth(event: H3Event) {
const auth = await getAuthContext(event)
if (!auth) {
throw createError({
statusCode: 401,
statusMessage: 'Authentication required'
})
}
return auth
}
export async function requireRole(event: H3Event, role: UserRole) {
const auth = await requireAuth(event)
if (auth.user.role !== role) {
throw createError({
statusCode: 403,
statusMessage: 'You are not allowed to perform this action'
})
}
return auth
}
export async function requireBookingManager(event: H3Event, booking: Pick<PublicBooking, 'personInChargeId'>) {
const auth = await requireAuth(event)
if (auth.user.role !== 'super_admin' && auth.user.id !== booking.personInChargeId) {
throw createError({
statusCode: 403,
statusMessage: 'You are not allowed to manage this booking'
})
}
return auth
}
export async function signInUser(event: H3Event, user: UserAuthRecord, remember: boolean) {
await createUserSession(event, {
userId: user.id,
remember
})
await updateLastLogin(user.id)
const refreshedUser = await getUserById(user.id)
if (!refreshedUser) {
throw createError({
statusCode: 500,
statusMessage: 'Unable to load authenticated user'
})
}
return refreshedUser
}