Android: send X-Kvitt-App app key on every server request (D-126)

The reverse proxy closes requests from outside the home LAN that lack
X-Kvitt-App: <key>. The key is the build property kvitt.appKey
(-Pkvitt.appKey, else android/local.properties, else empty = no header),
validated as 16-128 printable ASCII without whitespace, exposed as
BuildConfig.APP_KEY and passed via AppBuildInfo.appKey to KvittApi
(every call, /health and other unauthenticated calls included) and the
Coil picture client (PictureAuth). AppBuildInfo.toString hides the key.
Tests use a made-up key; README documents the property.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-21 18:50:57 +02:00
parent d9e189abd5
commit 34e5cad02a
9 changed files with 172 additions and 11 deletions
+10
View File
@@ -13,6 +13,16 @@ prefills (AC-2.7). Gradle takes `-Pkvitt.publicHost=…` first (`infra/publish-a
placeholder `kvitt.example.invalid`, so a release built without it cannot talk to a real host. Debug builds pair with
the address typed on S-1. Tests and goldens never depend on it: they use fixed hosts.
**App key (D-126).** Outside the home LAN the reverse proxy closes every request that does not carry the header
`X-Kvitt-App: <key>`; the server never reads it, and the per-device bearer token stays the authentication. The key is
the build property `kvitt.appKey`: `:app` exposes it as `BuildConfig.APP_KEY`, passed through `AppBuildInfo.appKey` to
`KvittApi` and the picture client (`PictureAuth`), which send it on every request to the server, `/health` and the other
unauthenticated calls included. Gradle takes `-Pkvitt.appKey=…` first, else the key `kvitt.appKey` in
`android/local.properties`, where the owner sets it (git-ignored, never committed), else empty: no header, which is
what debug builds against the dev server need. A key that is set must be 16 to 128 printable ASCII characters without
whitespace, or the build fails (the message names its length, never the value). It is a secret: never logged, never in
a test, golden or report; tests use a made-up key.
## Modules
| Module | Plugin (build-logic) | Notes |