bober-bbq-bot/bober_bbq
byrsapty f5e46ef648 Fix two audit findings: fiscalization gap in checkout polling, path traversal in supplier import
1. GET /api/checkout/payment-status/<id> (the Mini App's "Перевірити
   оплату" poll, used before the Monobank webhook arrives) marked an
   order paid but skipped everything the webhook and reconciliation
   paths do afterward — no fiscal receipt, no staff notification.
   Confirmed by cross-checking every other payment_status="paid" call
   site in the codebase (api/payments.py, admin/routes.py x3,
   utils/reconciliation.py) — all of them call fiscalize_in_background;
   this was the only one that didn't. Added the missing staff-chat
   notification and fiscalization call, matching the webhook's pattern.
   (Skipped the customer Telegram message the webhook also sends — the
   customer is already looking at the Mini App screen that just told
   them "paid", a duplicate ping there would be noise, not signal.)

2. bober_bbq/utils/supplier_import.py's discard_upload/load_preview/
   parse_rows all built a path as `TMP_DIR / token`, where `token` is a
   client-submitted hidden form field round-tripped across the
   preview/confirm steps — not re-validated as one of save_upload()'s
   own uuid4-named files. Path("/some/dir") / "/etc/passwd" evaluates
   to "/etc/passwd" (an absolute right-hand side silently discards the
   left), so a crafted token let any authenticated suppliers-access
   user delete (via discard_upload's error-path cleanup) or, if the
   extension happened to match, read the contents of an arbitrary file
   on the server. Added _resolve_upload_path() — validates the token
   against the exact <uuid4 hex><supported extension> shape and that
   the resolved path's parent is still TMP_DIR — used by all three
   functions instead of the raw join.

Verified with two smoke tests: 22 checks confirming 6 different attack
payloads (absolute paths both slash styles, relative traversal both
separator styles, a malformed-but-real-extension token, an empty
token) are all rejected without touching a planted victim file, while
a real save_upload()/discard_upload() round trip still works exactly
as before; and 8 checks confirming the checkout endpoint now fiscalizes
and notifies staff on the first paid poll, and does neither again on a
second poll (no double-fiscalization/double-notification). Plus a full
regression rerun of the session's other smoke suites.
2026-08-27 00:33:23 +03:00
..
admin Fix TypeError crashing restock-from-ingredient-page on production 2026-08-26 23:57:01 +03:00
api Fix two audit findings: fiscalization gap in checkout polling, path traversal in supplier import 2026-08-27 00:33:23 +03:00
payments Make brand identity reusable for redeploying to other clients 2026-08-25 17:54:29 +03:00
static Add EU-14 allergen labeling to products 2026-08-25 15:52:21 +03:00
templates/admin Track payment method (cash/bank) on supplier deliveries, surface it in statements 2026-08-26 21:02:56 +03:00
utils Fix two audit findings: fiscalization gap in checkout polling, path traversal in supplier import 2026-08-27 00:33:23 +03:00
__init__.py Initial commit: Bober BBQ Telegram bot + backend + admin + Mini App 2026-08-08 15:50:50 +03:00
app.py Add owner-alerting on unhandled errors, backup integrity checks, and a client-provisioning script 2026-08-25 18:11:15 +03:00
config.py Enable TEMPLATES_AUTO_RELOAD so template edits don't need a restart 2026-08-09 16:46:10 +03:00
extensions.py Login page: real logo/name, Ukrainian auth message, fix remaining tight spacing 2026-08-09 16:42:38 +03:00
migrate.py Track payment method (cash/bank) on supplier deliveries, surface it in statements 2026-08-26 21:02:56 +03:00
models.py Track payment method (cash/bank) on supplier deliveries, surface it in statements 2026-08-26 21:02:56 +03:00
seed.py Add dine-in orders and manual order creation for staff 2026-08-09 23:53:14 +03:00