361b25a8bd10df2fd66d2bc6a3e6b15489c8c42d
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
361b25a8bd |
hub: answer the local network only, whichever way a client arrives
The reported bug was the Hub being reachable from outside the local
network when Server + Desktop is active.
|
||
|
|
7d784eb653 |
hub: make the login lockout that LOGIN_FAIL_MAX described
LOGIN_FAIL_MAX was declared as "max failures in window before extra delay" and then never read anywhere in the file. _record_failure() only ever slept a flat LOGIN_FAIL_DELAY. So the Hub's entire defence against online guessing was a constant 2 second pause per wrong password: no escalation, no lockout, no ban, and fail2ban is configured for SSH only. Worse, the old 60 second window could not have worked even if the constant had been wired up. With a delay per attempt, reaching 10 failures takes about 80 seconds, so the earliest failures aged out of the window before the count could ever reach the limit. - security_helpers.py: new LoginThrottle. The delay ramps with the failure count (2s, 4s, ... capped at 10s), and once LOGIN_FAIL_MAX failures land inside the window the address is refused outright for LOGIN_LOCKOUT_SECONDS (5 minutes). A successful login clears the address, so an operator who fumbles a password is not penalised later. The sleep is never taken under the lock, so one slow client cannot stall every other login. Tracked addresses are evicted, so a distributed sweep cannot grow the table without bound. The window moves from 60s to 900s so the whole ramp fits inside it. clock and sleep are injectable, which is what makes it testable. - server.py: /api/login checks the lockout before the scrypt hash, so a locked-out client costs almost nothing to reject, and answers 429 with a human-readable wait instead of a bare 401. - tests/test_login_throttle.py: covers the ramp, the cap, the lockout firing and expiring, per-address isolation, clearing on success, eviction, and that the limit is actually reachable inside the window. Verified against the real app with TestClient: 10 wrong passwords return 401 and the 11th returns 429 "Too many failed attempts. Try again in about 5 minute(s)." A correct password clears the counter. |