Skip to content

Ticket tiers can be purchased, even when sold out leading to crash #21

@chameleoncircuit

Description

@chameleoncircuit

Description

The available ticket inventory is only checked during the initial rendering of /cure/registration/form. The checkout page will assume the ticket is in-stock and attempt to decrement the number of available tickets. Upon doing so an uncaught ApiException is raised. The uncaught exception causes the application to crash and not accept further requests. The oversold ticket is billed and marked as paid in the database and the Square inventory is not updated.

The tickets can be oversold by creating a single registration with multiple entries for the low-stock ticket tier or by multiple visitors starting their registration in parallel (visitor A starts the registration process, visitor B starts the registration process, visitor B checks out, visitor A checks out; leading to a crash).

Steps to reproduce

  1. Identify the inventory count in Square of the ticket tier (i.e. 1)
  2. Create a registration containing 2 attendees at that ticket tier
  3. Attempt to check-out. Purchaser is redirect to the "successful checkout" page.
  4. Observe uncaught exception in console. Additionally, observe that server is no longer accepting requests.

Remediation

Add error handling to ensure calls to external services are successful.

Exception details

kicweb-1      | Unhandled exception. Square.Exceptions.ApiException: HTTP Response Not OK
kicweb-1      |    at APIMatic.Core.Utilities.CoreHelper.RunVoidTask(Task t)
kicweb-1      |    at APIMatic.Core.Utilities.CoreHelper.RunTask[T](Task`1 t)
kicweb-1      |    at Square.Apis.InventoryApi.BatchChangeInventory(BatchChangeInventoryRequest body)
kicweb-1      |    at KiCData.Services.PaymentService.<>c__DisplayClass13_0.<ReduceTicketInventory>b__0() in /src/kicdata/Services/PaymentService.cs:line 300
kicweb-1      |    at System.Threading.Tasks.Task`1.InnerInvoke()
kicweb-1      |    at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
kicweb-1      | --- End of stack trace from previous location ---
kicweb-1      |    at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
kicweb-1      |    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
kicweb-1      | --- End of stack trace from previous location ---
kicweb-1      |    at KiCData.Services.PaymentService.ReduceTicketInventory(List`1 registrationViewModels) in /src/kicdata/Services/PaymentService.cs:line 300
kicweb-1      |    at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
kicweb-1      |    at System.Threading.QueueUserWorkItemCallback.Execute()
kicweb-1      |    at System.Threading.ThreadPoolWorkQueue.Dispatch()
kicweb-1      |    at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions