From b38a54727232698d1bf1613d793d31ccd8512c14 Mon Sep 17 00:00:00 2001 From: Daniel Covington Date: Mon, 24 Aug 2026 12:23:07 -0400 Subject: [PATCH] Fix: token marked used on link view instead of order submission Root cause: OrderController.Continue (GET /order/continue) was calling MarkTokenUsed the moment the link loaded, not when the customer actually submitted the order. This burns a one-time link before the customer opens it whenever anything else issues a GET first - most likely mail security link-scanners (e.g. Outlook Safe Links) that pre-fetch URLs found in email bodies, which matches the admin site's mailto-link workflow. - OrderController.Continue: only checks TokenUsedAt/TokenExpiresAt for validity now, no longer marks the token used - OrderApiController.SubmitOrderDetails: rejects an already-used token (410), and marks the token used only after the order details are successfully saved --- app/controllers/OrderApiController.asp | 6 ++++++ app/controllers/OrderController.asp | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/controllers/OrderApiController.asp b/app/controllers/OrderApiController.asp index d3ad008..a0ae003 100644 --- a/app/controllers/OrderApiController.asp +++ b/app/controllers/OrderApiController.asp @@ -60,6 +60,11 @@ Class OrderApiController_Class Exit Sub End If + If Not IsNull(order("TokenUsedAt")) Then + WriteJsonError "410 Gone", "This order has already been submitted." + Exit Sub + End If + Dim csrfToken : csrfToken = Request.ServerVariables("HTTP_X_CSRF_TOKEN") If Not HTMLSecurity().IsValidAntiCSRFToken("Order.Continue", csrfToken) Then @@ -114,6 +119,7 @@ Class OrderApiController_Class End If On Error GoTo 0 + OrdersRepository().MarkTokenUsed order("OrderID") ' Best-effort: the order is already safely persisted at this point, so an SMTP hiccup ' should not turn a successful submission into a failed one. diff --git a/app/controllers/OrderController.asp b/app/controllers/OrderController.asp index 3403f7c..d4a8919 100644 --- a/app/controllers/OrderController.asp +++ b/app/controllers/OrderController.asp @@ -40,9 +40,13 @@ Class OrderController_Class If Len(token) > 0 Then Set order = OrdersRepository().FindByToken(token) If Not (order Is Nothing) Then + ' Only checks validity here - the token is marked used when the order is + ' actually submitted (OrderApiController.SubmitOrderDetails), not on this GET. + ' Marking it used here would burn a one-time link the moment it's merely + ' opened/previewed (e.g. by mail security link-scanners), before the + ' customer ever sees the form. If IsNull(order("TokenUsedAt")) And order("TokenExpiresAt") >= Now() Then isValid = True - OrdersRepository().MarkTokenUsed order("OrderID") End If End If End If