Security hardening + code-review fixes
Outcome of a full multi-agent code review. Touches TLS, credential storage, API versioning, networking correctness, concurrency/lifecycle, and the release build. See CHANGELOG.md for the full list and the items to port to the iOS app. Security - Remove untrusted-TLS support: delete ServerTrustPolicy.AllowSelfSignedForHost and its trust-all X509TrustManager; drop the self-signed Settings toggle. - Enforce HTTPS in normalizedBaseUrl (reject http + embedded credentials); add network_security_config (no cleartext, system CAs only) + allowBackup=false. - Never persist passwords at rest: remember-me stores email only; no password pre-fill; clear creds on sign-out / when remember-me is off. - Match CSRF host lookup to OkHttp's host parsing; stop leaking raw exception text. Correctness - Fix API versioning: hardcode v1/v3 per endpoint (docs Sec.4) instead of one broken global apiVersion; remove the version plumbing + Settings field. - Treat "warning" status as success (committed write); fail-fast on a missing pagination cursor; close Response on cancellation; tolerant JSON parse; User-Agent. - Firmware isCompatible fails closed + extra acknowledgment for a non-compatible image. Concurrency / lifecycle - Run network I/O on Dispatchers.IO; stale-result generation guards + rethrow CancellationException in all loads; host AppState in a ViewModel (survive config change); thread-safe cookie jar; reset/upgrade re-entry guard; wire list Retry. Build - Enable R8 minify+shrink with kotlinx.serialization keep rules; drop unused navigation-compose; add the missing .gitignore. NOTE: built/verified by static review only (no Android SDK on the dev machine) — run :app:assembleDebug and a release build before shipping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ca3d7d05e0
commit
41098831ae
20 changed files with 505 additions and 191 deletions
24
HANDOFF.md
24
HANDOFF.md
|
|
@ -37,7 +37,9 @@ everything. Two loops:
|
|||
```
|
||||
Needs `local.properties` (`sdk.dir=…`, git-ignored). First run downloads deps
|
||||
to `~/.gradle`; afterwards it's ~20–60 s. This is what proves the whole app
|
||||
(UI + resources + manifest + icons) compiles.
|
||||
(UI + resources + manifest + icons) compiles. **`release` now enables R8
|
||||
minify+shrink** (keep rules in `proguard-rules.pro`) — smoke-test a `release` build
|
||||
before shipping, since R8 can strip serializers if the keep rules ever drift.
|
||||
- **Quick core-only check (no Gradle), when iterating on `core/`:** the bundled
|
||||
compiler at `…/Android Studio.app/Contents/plugins/Kotlin/kotlinc/bin/kotlinc`
|
||||
with `-Xplugin=…/kotlinc/lib/kotlinx-serialization-compiler-plugin.jar` and a
|
||||
|
|
@ -50,16 +52,24 @@ everything. Two loops:
|
|||
- **Single-encode URLs.** Ids stay RAW in `McmsEndpoint`; `ApiClient` encodes the
|
||||
path once via `HttpUrl.addPathSegments`. Pre-encoding double-encoded MAC colons
|
||||
(`:` → `%3A` → `%253A`) → MCMS "invalid id".
|
||||
- **Endpoint versions are fixed per endpoint (`v1`/`v3`), NOT global.** Lists/states are
|
||||
`v3`; single-doc/login/logs/firmware-files are `v1` (§4) — the two are not
|
||||
interchangeable, so there is no global API-version setting. Hardcoded in
|
||||
`McmsEndpoint.path()`; endpoints not in the §4 table are marked `// inferred`.
|
||||
- **401 bounces to login; 403 does NOT** (permission/CSRF — `requiresReauthentication`
|
||||
is 401-only).
|
||||
- **Writes return `{"status":"success"}` with no `data`** — the unwrap tolerates it.
|
||||
- **Writes return `{"status":"success"}` (or `"warning"`) with no `data`** — the unwrap
|
||||
tolerates both. `"warning"` means the write committed (schema mismatch only) and is
|
||||
treated as success, NOT an error (§3.5).
|
||||
- **ONU registration lives on OLT-STATE buckets** (`OltRepository.registrationMap`),
|
||||
not ONU-STATE. Friendly names are `ONU.Name` / `OLT.Name` (NOT `NETCONF.Name`).
|
||||
- **CPE DHCP** comes from the web helper `GET /api/cpe/onu/<id>/` — a versionless,
|
||||
bare `[code, cpe…]` array (use `ApiClient.getRaw`).
|
||||
- **Firmware** = Procedure 7: GET ONU-CFG → write filename/version into the
|
||||
**inactive** bank → full-doc PUT (`FirmwareUpgrade.apply`). Inactive-bank only,
|
||||
so service stays up until the ONU reboots. Still worth testing on a spare ONU.
|
||||
so service stays up until the ONU reboots. `FirmwareFile.isCompatible` now fails
|
||||
CLOSED (unknown vendor/model ⇒ not compatible-by-default) and staging a
|
||||
non-compatible image needs an extra acknowledgment. Still worth testing on a spare ONU.
|
||||
- Field paths were confirmed against live JSON; see `docs/MCMS_API.md` and the
|
||||
model accessors.
|
||||
|
||||
|
|
@ -73,9 +83,11 @@ everything. Two loops:
|
|||
drills ONU-state → filtered ONU list.
|
||||
- Toggles use `rememberSaveable` (survive rotation, not process death). Persist in
|
||||
prefs if you want parity with iOS `@AppStorage`.
|
||||
- Self-signed/cleartext: the TLS trust policy is in `ServerTrust`. Plain-HTTP hosts
|
||||
also need a `usesCleartextTraffic`/network-security-config exception (Android's
|
||||
ATS analogue) — add when needed.
|
||||
- **TLS is HTTPS-only with system-CA trust; self-signed/cleartext support was removed**
|
||||
(security — see `CHANGELOG.md`, not "easy to restore"). `res/xml/network_security_config.xml`
|
||||
forbids cleartext and user-installed CAs. To reach a private-cert box, install its CA in
|
||||
the device system store or pin its key via `ServerTrustPolicy.PinPublicKeySha256`. The
|
||||
trust policy lives in `ServerTrust`.
|
||||
|
||||
## Repo split
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue