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
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { CancelBookingConfirmationResponse } from '~~/shared/booking'
|
||||
|
||||
import { requireBookingManager } from '../../../../utils/auth'
|
||||
import { cancelBookingConfirmationByConfirmationToken, getBookingByConfirmationToken } from '../../../../utils/booking-repository'
|
||||
import { getRequiredRouteParam, httpError } from '../../../../utils/http'
|
||||
|
||||
@@ -11,6 +12,8 @@ export default defineEventHandler(async (event): Promise<CancelBookingConfirmati
|
||||
httpError(404, 'Booking not found')
|
||||
}
|
||||
|
||||
await requireBookingManager(event, existingBooking)
|
||||
|
||||
if (existingBooking.status === 'pending') {
|
||||
return {
|
||||
booking: existingBooking,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ConfirmBookingResponse } from '~~/shared/booking'
|
||||
|
||||
import { requireBookingManager } from '../../../../utils/auth'
|
||||
import { confirmBookingByConfirmationToken, getBookingByConfirmationToken, getBookingInventorySummary } from '../../../../utils/booking-repository'
|
||||
import { getRequiredRouteParam, httpError } from '../../../../utils/http'
|
||||
import { sendBookingTicketReceiptViaWhatsApp } from '../../../../utils/whatsapp'
|
||||
@@ -12,6 +13,8 @@ export default defineEventHandler(async (event): Promise<ConfirmBookingResponse>
|
||||
httpError(404, 'Booking not found')
|
||||
}
|
||||
|
||||
await requireBookingManager(event, existingBooking)
|
||||
|
||||
if (existingBooking.status === 'confirmed') {
|
||||
return {
|
||||
booking: existingBooking,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { UpdateBookingDetailsResponse } from '~~/shared/booking'
|
||||
|
||||
import { requireBookingManager } from '../../../../utils/auth'
|
||||
import {
|
||||
clearBookingTransactionDocumentByConfirmationToken,
|
||||
getBookingByConfirmationToken,
|
||||
@@ -17,6 +18,8 @@ export default defineEventHandler(async (event): Promise<UpdateBookingDetailsRes
|
||||
httpError(404, 'Booking not found')
|
||||
}
|
||||
|
||||
await requireBookingManager(event, existingBooking)
|
||||
|
||||
if (existingBooking.status !== 'pending') {
|
||||
httpError(409, 'Payment details can only be changed before confirmation')
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { UpdateBookingDetailsResponse } from '~~/shared/booking'
|
||||
|
||||
import { requireBookingManager } from '../../../../utils/auth'
|
||||
import {
|
||||
clearBookingTransactionDocumentByConfirmationToken,
|
||||
getBookingByConfirmationToken
|
||||
@@ -15,6 +16,8 @@ export default defineEventHandler(async (event): Promise<UpdateBookingDetailsRes
|
||||
httpError(404, 'Booking not found')
|
||||
}
|
||||
|
||||
await requireBookingManager(event, booking)
|
||||
|
||||
if (booking.status !== 'pending') {
|
||||
httpError(409, 'Transaction document can only be changed before confirmation')
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { sendStream, setHeader } from 'h3'
|
||||
|
||||
import { getBookingTransactionDocumentByConfirmationToken } from '../../../../utils/booking-repository'
|
||||
import { requireBookingManager } from '../../../../utils/auth'
|
||||
import { getBookingByConfirmationToken, getBookingTransactionDocumentByConfirmationToken } from '../../../../utils/booking-repository'
|
||||
import { getRequiredRouteParam, httpError } from '../../../../utils/http'
|
||||
import {
|
||||
getSafeDownloadName,
|
||||
@@ -9,6 +10,14 @@ import {
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const token = getRequiredRouteParam(event, 'token', 'Confirmation token')
|
||||
const booking = await getBookingByConfirmationToken(token)
|
||||
|
||||
if (!booking) {
|
||||
httpError(404, 'Booking not found')
|
||||
}
|
||||
|
||||
await requireBookingManager(event, booking)
|
||||
|
||||
const document = await getBookingTransactionDocumentByConfirmationToken(token)
|
||||
|
||||
if (!document) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { UpdateBookingDetailsResponse } from '~~/shared/booking'
|
||||
|
||||
import { getHeader, readMultipartFormData } from 'h3'
|
||||
|
||||
import { requireBookingManager } from '../../../../utils/auth'
|
||||
import {
|
||||
getBookingByConfirmationToken,
|
||||
replaceBookingTransactionDocumentByConfirmationToken
|
||||
@@ -22,6 +23,8 @@ export default defineEventHandler(async (event): Promise<UpdateBookingDetailsRes
|
||||
httpError(404, 'Booking not found')
|
||||
}
|
||||
|
||||
await requireBookingManager(event, booking)
|
||||
|
||||
if (booking.status !== 'pending') {
|
||||
httpError(409, 'Transaction document can only be changed before confirmation')
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { H3Event } from 'h3'
|
||||
import type { PublicBooking } from '~~/shared/booking'
|
||||
|
||||
import { normalizeUsername, type UserRole } from '~~/shared/auth'
|
||||
|
||||
@@ -54,6 +55,19 @@ export async function requireRole(event: H3Event, role: UserRole) {
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user