-
Notifications
You must be signed in to change notification settings - Fork 0
Security
-
Ed25519 request signing (Breeze Core ≥ 3.0.0). The private key is generated
on the device and never leaves it — a seed in
flutter_secure_storage, backed by the Android Keystore — and the server holds only the public key. Every request is signed over method + path + timestamp + single-use nonce + SHA3-512 body digest: no replay, no tampering, and a server compromise exposes nothing forgeable. A device on the old scheme upgrades itself in place on first launch against a 3.0 server. -
Bearer fallback for pre-3.0 servers, also Keystore-backed. A
426triggers the in-place upgrade. -
allowBackup=falsekeeps credentials out of device and cloud backups. - HTTPS enforced for non-private hosts — Android blocks cleartext by default, and the app does not make an exception for anything outside your LAN.
- Admin approval is LAN-only, enforced by the server. The app never performs approval; it only asks for a code and waits.
This was the app's worst bug, fixed in 2.1.1, and the reasoning is worth keeping visible.
The app used to treat any 401 as "my credential is dead": it deleted the
stored Ed25519 private key and demanded re-pairing. Re-pairing needs an admin on
the LAN — so a user away from home could not recover, and when the immediate
re-enrolment also failed, the app fell through to onboarding having forgotten the
server entirely.
The trigger did not even have to be real. A phone whose clock had drifted past the server's 60-second window fails every signed request, which looks identical to a revoked credential.
Now:
-
Transient failures are retried once, transparently. On a
clock_skewrejection the app learnsserver_time − device_timeand signs everything afterwards with server time, so a drifted clock self-heals in one round-trip instead of costing a pairing. -
Re-pairing only happens when the server says the credential is genuinely
finished, or after three unexplained
401s in a row for servers too old to say which it is. -
On a kept-credential
401the app drops to its offline state instead of continuing to poll every 5 seconds. That hammering is what tripped the server's fail2ban and, behind NAT, banned everyone's shared address at once.
The server half of this — stable error codes and a retryable flag — is in
Authentication and pairing.
Privately, please: SECURITY.md.
Breeze · Breeze Core (the server) · APKs · AGPL-3.0
Start here
Using it
- The control screen
- Home-screen widgets
- Android Auto
- Programs
- Diagnostics and the Nerd screen
- Multiple servers
- Settings and theming
Under the hood
The server