Networking foundation: OpenAPI codegen, HTTP clients, encrypted token storage#3
Networking foundation: OpenAPI codegen, HTTP clients, encrypted token storage#3koinsaari wants to merge 3 commits into
Conversation
Vendor api-proxy/api/openapi.yaml under openapi/ with the source commit SHA recorded at the top. openApiGenerate emits Retrofit interfaces + kotlinx.serialization models into build/generated/openapi/ on every preBuild; the generated dir is gitignored. Pin generator to 7.21.0 — 7.22.0 has a regression that emits broken Room model references (#23658). Skip the supporting ApiClient.kt and auth/HttpBearerAuth.kt since HttpClients constructs Retrofit itself in the next commit; ApiClient otherwise pulls in retrofit-converter-scalars that we do not use.
Tokens schema (access, refresh, user_id, display_name) lives in tokens.proto, compiled via the protobuf gradle plugin into javalite bindings only — we use the Java builder API directly, no Kotlin DSL. The DataStore serializer wraps Tink's AES-256-GCM Aead primitive whose keyset is unwrapped from the Android Keystore at first use, so the on-disk blob is unreadable without the device's hardware-backed master key. Also tighten detekt: maxLineLength 140 -> 120, enable ExpressionBodySyntax so single-return functions stay in expression-body form, and correct the HttpClients signature flagged by ktlint. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Claude finished @koinsaari's task in 4m 38s —— View job Code Review
No blocking issues. The crypto + networking foundation is solid and the architecture invariants are all respected. Security checklist
|
Summary
Three foundational pieces for the networking + auth layer. None depend on each other; they're grouped because they're all plumbing the app needs before any feature talks to api-proxy.
1. OpenAPI codegen —
feat: wire openapi-generator with vendored api-proxy specapi-proxy/api/openapi.yamltoopenapi/openapi.yaml; first three lines record the source commit SHA so refreshes are auditable.openApiGenerateruns on everypreBuild, emitting Retrofit interfaces + kotlinx.serialization models intoapp/build/generated/openapi/(gitignored).doLaststep deletesApiClient.ktand the emptyauth/dir from generated output.ApiClient.ktpulls in retrofit'sconverter-scalars/converter-moshiwhich we don't depend on, and we construct Retrofit ourselves inHttpClients.2. HTTP clients —
feat: add HttpClients for OkHttp + Retrofit + kotlinx.serializationHttpClientshands out two flavours ofOkHttpClient(raw and authed) plus aRetrofitbuilder pre-wired with the kotlinx.serialization converter. Base URL ishttps://api.stoganet.com/, timeouts are 10s connect / 15s I/O, body logging is debug-only.3. Encrypted token storage —
feat: encrypted TokenStore via Proto DataStore + Tink AEADapp/src/main/proto/tokens.proto— schema for{access, refresh, user_id, display_name}; protobuf gradle plugin compiles it viajavaliteonly (no Kotlin DSL — we use the Java builder API directly).TokensSerializeradapts DataStore'sSerializer<T>contract: bytes in → Tink AES-256-GCM decrypt →Tokens.parseFrom; and the reverse on write. The Tink keyset is wrapped by a hardware-backed Android Keystore master key, so the on-diskstoganet-tokens.pbis unreadable without the device.TokenStoreis the public surface —Flow<Tokens>,current(),save(...),clear().Cross-cutting
maxLineLength140 → 120, enabledExpressionBodySyntax(withincludeLineWrapping=true) so single-return functions stay in=form.Test plan
./gradlew :app:openApiGenerate— emits 9 models +DefaultApi(auth + healthz)./gradlew :app:assembleDebug— clean build with generated code./gradlew detekt— clean