Close the smaller state inconsistencies (B-96, BET-02, BET-07, WDR-01, WDR-15, TX-16, TX-18, TX-27, TX-29, DEP-15, DEP-16, AUD-30, AUD-46, DAT-22)
- bet/withdrawal routes read listener.client after taking the user lock - a reduced full-balance withdrawal is checked against the minimum again - a bet covered only by pending balance answers balance_pending_confirmation - a recovered bet/withdrawal/payout writes bet_placed/withdrawal_sent/payout_sent - an abandoned payout clears winner/fee/reserve amounts with payout_txid - the reconciler pings SSE only for rows it changed - closing_stalled every 30 minutes past the deadline; closing_waiting_since on /rounds/current - one refresh per user at a time; a failed refresh no longer ends the Electrum session Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
24e5fc3d8b
commit
9520c80dcf
23 files changed
+445
-151
No files matched your search
+5
-17
@@ -323,9 +323,7 @@ che ne è il proprietario; qui ci sono le regole di sicurezza.
|
||||
[REG-12](registrazione-e-depositi.md#sessione-e-password).
|
||||
*Codice:* `app/auth/security.py:MIN_PASSWORD_LENGTH`, `app/auth/routes.py:RegisterRequest`,
|
||||
`app/auth/routes.py:LoginRequest`, `app/api/routes/users.py:ChangePasswordRequest` ·
|
||||
*Test:* `tests/unit/test_users.py`
|
||||
*Oggi:* il massimo di 256 vale solo per la password della registrazione;
|
||||
i campi del login e del cambio password non hanno limite di lunghezza.
|
||||
*Test:* `tests/unit/test_users.py`, `tests/unit/test_abuse_limits.py`
|
||||
|
||||
- ~~[SEC-18]~~ Assorbito da [REG-01](registrazione-e-depositi.md#registrazione)
|
||||
e [REG-02](registrazione-e-depositi.md#registrazione): formato dello
|
||||
@@ -373,8 +371,6 @@ che ne è il proprietario; qui ci sono le regole di sicurezza.
|
||||
*Codice:* `app/auth/dependencies.py:get_current_user`, `app/api/routes/users.py:change_password`,
|
||||
`app/api/routes/admin.py:reset_user_password` ·
|
||||
*Test:* `tests/unit/test_users.py`, `tests/unit/test_security.py`, `tests/unit/test_admin.py`
|
||||
l'header assente risponde 401 con il corpo non strutturato di FastAPI
|
||||
`{"detail": "Not authenticated"}`.
|
||||
|
||||
- **[SEC-23]** Gli endpoint raggiungibili anche da non autenticati (ad esempio
|
||||
`GET /rounds/current`, `POST /bug-reports`) usano l'utente solo per
|
||||
@@ -396,7 +392,6 @@ endpoint `/admin/*`, che richiedono l'header `X-Admin-Token`.
|
||||
`invalid_admin_token` ([API-08](api.md#convenzioni-generali)).
|
||||
*Codice:* `app/api/routes/admin.py:require_admin` ·
|
||||
*Test:* `tests/unit/test_admin.py`
|
||||
non strutturato `{"detail": "invalid admin token"}`.
|
||||
|
||||
- **[SEC-25]** Il token è **unico e condiviso**: non esiste un'identità per
|
||||
singolo operatore, e l'audit log registra *cosa* è cambiato ma non *chi*
|
||||
@@ -491,7 +486,6 @@ ogni riavvio e non funzionerebbero con più worker.
|
||||
*Codice:* `app/api/routes/users.py:change_password`,
|
||||
`app/auth/rate_limit.py:RateLimiter`, `app/auth/rate_limit.py:AuthRateLimiters` ·
|
||||
*Test:* `tests/unit/test_abuse_limits.py`
|
||||
la password attuale si può provare senza limiti.
|
||||
|
||||
- **[SEC-55]** L'invio di segnalazioni di bug è una **quota** per IP
|
||||
([SEC-35]): al massimo 10 segnalazioni per IP ogni 3600s (finestra mobile,
|
||||
@@ -503,7 +497,6 @@ ogni riavvio e non funzionerebbero con più worker.
|
||||
*Codice:* `app/api/routes/bug_reports.py:create_bug_report`,
|
||||
`app/auth/rate_limit.py:RollingQuota` ·
|
||||
*Test:* `tests/unit/test_abuse_limits.py`
|
||||
inserire segnalazioni senza limite, fino a riempire il database.
|
||||
|
||||
- **[SEC-32]** La memoria dei limitatori è limitata: le voci esaurite vengono
|
||||
rimosse (al più ogni 60s, e alla lettura), e comunque non si superano 50.000
|
||||
@@ -518,9 +511,7 @@ ogni riavvio e non funzionerebbero con più worker.
|
||||
[API-16](api.md#contratto-degli-errori); il browser ripiega sul polling).
|
||||
*Codice:* `app/rounds/events.py:RoundEventBroadcaster.subscribe`,
|
||||
`app/api/routes/rounds.py:round_stream` ·
|
||||
*Test:* `tests/unit/test_round_events.py`
|
||||
*Oggi:* il 503 ha il corpo non strutturato
|
||||
`{"detail": "too many concurrent update streams"}`.
|
||||
*Test:* `tests/unit/test_round_events.py`, `tests/unit/test_abuse_limits.py`
|
||||
|
||||
- **[SEC-34]** **Non** hanno limiti di frequenza: scommesse, prelievi,
|
||||
endpoint admin (tentativi sul token compresi), QR, `GET /rounds/current` e
|
||||
@@ -678,10 +669,8 @@ a sé. L'unica risorsa esterna ammessa è Google Fonts (l'`@import` in
|
||||
validazione e framework compresi — ha il formato strutturato con un codice
|
||||
([API-16](api.md#contratto-degli-errori)) e non ripete il valore ricevuto,
|
||||
così una password troppo lunga non torna indietro in chiaro.
|
||||
*Codice:* `app/main.py:log_unhandled_exception`, `app/main.py`
|
||||
*Oggi:* 401 senza header, 403 admin, 404/405 del framework e 503 dell'SSE
|
||||
hanno `detail` come stringa, e il 422 di validazione ripete nel campo
|
||||
`input` il valore ricevuto.
|
||||
*Codice:* `app/main.py:log_unhandled_exception`, `app/main.py` ·
|
||||
*Test:* `tests/unit/test_abuse_limits.py`
|
||||
|
||||
Il pannello `/admin` non è collegato da `/` (né viceversa), ma è una scelta
|
||||
di discrezione, non una protezione: la pagina è pubblica, gli endpoint no.
|
||||
@@ -753,8 +742,7 @@ sicurezza.
|
||||
il quorum prima del pagamento
|
||||
([RND-35](ciclo-di-vita-del-round.md#0--apertura), B-82): un round
|
||||
del backup già pagato risulta impagabile invece di essere pagato due volte
|
||||
con il denaro dei round successivi. *Oggi:* la pausa si imposta a mano nel
|
||||
database.
|
||||
con il denaro dei round successivi.
|
||||
- **Chiave sbagliata.** Una master key che non corrisponde al database
|
||||
ripristinato ferma l'avvio ([SEC-49]).
|
||||
- **Commit persi.** Con `synchronous=FULL` un commit confermato al chiamante
|
||||
|
||||
Reference in new issue
Block a user