Already fixed on master in commit 573153b (fix(payment): make Swish QR code scannable by the Swish app).
The normalizeSwishNumber function in payment.ts now strips a leading + via…
Root cause: Guest checkout was unreachable from the UI
The guest checkout pages existed as routes (/gast-bestallning, etc.) but there was no link to them anywhere in the UI. The homepage…
Created issues for the vulnerabilities identified across the advisory reviews on this PR, so they are tracked independently of the review comments:
⚠️ Critical: This endpoint is public (no JWT) and marks the order as paid without any payment verification. Combined with POST /api/guest-orders returning the guestToken in the response body, anyone can create an order and immediately confirm it as paid. Needs server-side Swish payment verification before fulfillment.
⚠️ amountPaid is never set here. The order goes directly to PROCESSING with amountPaid = null. The GuestOrderResponse will report amountPaid: null even after "payment". The frontend test mock expects amountPaid: 49 which the real backend won't return.
⚠️ /api/guest-orders/** is permitAll with no rate limiting. Consider adding a throttle filter (Bucket4j or Spring rate limiter) to prevent abuse of the public create + pay endpoints.
✅ Correct approach - a plain UNIQUE INDEX on guest_token treats NULLs as distinct on both H2 and PostgreSQL, so existing user-owned orders (NULL token) won't collide. A partial WHERE guest_token IS NOT NULL index would be slightly more efficient on Postgres, but the plain form works correctly and preserves H2 compatibility.
⚠️ The guest token is passed as a query parameter, which lands in browser history, server logs, and Referer headers. The code comments acknowledge this trade-off explicitly, so this is a conscious decision backed by the refresh-safety requirement.