funman300 561e666dc3 config: never let an unreadable config.json become production defaults
load() did:

    read_to_string(&path).ok()
        .and_then(|s| serde_json::from_str(&s).ok())
        .unwrap_or_default()

so ANY parse failure silently produced compiled defaults -- blaze_main 42130 and
account_sync 8099, both PRODUCTION -- with an empty game_profile, and the next
save() wrote that over the operator's real settings. The launcher then could not
start the game and was pointed at the live service.

Observed 2026-08-23 from nothing worse than a UTF-8 BOM: PowerShell 5.1's
Set-Content -Encoding UTF8 prepends EF BB BF and serde_json rejects it. A
staging config (42327/42330/8299) was destroyed and replaced with production
ports without a word.

Two changes:

- parse_json() strips a leading BOM, since Windows editors and PowerShell both
  emit one. Split out from load() so it is testable without touching the real
  config path.
- A file that EXISTS but does not parse is no longer treated like a missing one.
  It is renamed to config.json.corrupt-<epoch> and the error is reported naming
  the production risk, so defaults can never overwrite a recoverable config.

A missing file still yields defaults: that is genuine first-run.

Tests cover the exact incident (BOM-prefixed config keeps 42327/42330/8299 and
does NOT fall back to 42130/8099) with a precondition asserting raw serde_json
really does reject the BOM, so the guard cannot rot into a tautology.
2026-08-23 02:06:38 +00:00
S
Description
GUI launcher for OpenFUT — manages core/bridge services, DLL hook deployment, and TLS cert setup
2 MiB
Languages
Rust 100%