Implement Android TOTP discovery cache, progress, refresh, and search #110

Closed
opened 2026-08-17 19:15:15 +00:00 by hugo · 1 comment
Owner

Goal

Open the TOTP destination quickly from the storage-owned non-secret discovery catalog and support cancellable incremental refresh.

Scope

  • Render cached TOTP rows immediately without decrypting entries; if no usable catalog exists, start discovery only after authentication.
  • Use the existing storage cache contract: canonical entry path, SHA-256 of ciphertext, and is_totp; never cache decrypted text, OTP URI/secret, issuer/account, generated code, password, passphrase, or key material.
  • Store the catalog in the Android private/no-backup location selected by the path issue and preserve it across normal app updates.
  • Display typed monotonic phases, total, inspected, cache hits, matches, unavailable entries, determinate progress when known, cancellation, and resumable checkpoints.
  • Pull-to-refresh/explicit refresh must hash current ciphertext and decrypt only new/changed records, preserve completed checkpoints on cancellation, and prune deleted records only after a complete stable pass.
  • Add query filtering through the storage-owned cached-search API with latest-query-wins cancellation.
  • Serialize discovery and reject a complete result if the repository changes during the pass.
  • Remove Apple Watch selection/status UI and fields from Android TOTP models.

Acceptance criteria

  • Cold scan, warm zero-decrypt refresh, one-entry change/add/remove, corruption recovery, cancellation/resume, concurrent repository change, and wrong-store catalog are covered.
  • Opening a valid catalog does not authenticate or decrypt.
  • Search is responsive on large catalogs and never parses entry content in Kotlin.
  • Process death/update retains valid completed cache records without backing them up off-device.
  • No Watch controls or dead Watch state appear on Android.

Depends on private-path integration, biometric authentication, shared mobile contract, and app shell. Part of #87.

Android support update (2026-10-08)

User-directed scope: Android release and CI targets are arm64-v8a and armeabi-v7a. x86_64 Android is excluded for now. Validation for every Android milestone issue uses emulator devices only; physical-device testing and physical-device checklists are excluded. Record the limits of available ARM emulator/API images without claiming physical-device coverage.

## Goal Open the TOTP destination quickly from the storage-owned non-secret discovery catalog and support cancellable incremental refresh. ## Scope - Render cached TOTP rows immediately without decrypting entries; if no usable catalog exists, start discovery only after authentication. - Use the existing storage cache contract: canonical entry path, SHA-256 of ciphertext, and `is_totp`; never cache decrypted text, OTP URI/secret, issuer/account, generated code, password, passphrase, or key material. - Store the catalog in the Android private/no-backup location selected by the path issue and preserve it across normal app updates. - Display typed monotonic phases, total, inspected, cache hits, matches, unavailable entries, determinate progress when known, cancellation, and resumable checkpoints. - Pull-to-refresh/explicit refresh must hash current ciphertext and decrypt only new/changed records, preserve completed checkpoints on cancellation, and prune deleted records only after a complete stable pass. - Add query filtering through the storage-owned cached-search API with latest-query-wins cancellation. - Serialize discovery and reject a complete result if the repository changes during the pass. - Remove Apple Watch selection/status UI and fields from Android TOTP models. ## Acceptance criteria - Cold scan, warm zero-decrypt refresh, one-entry change/add/remove, corruption recovery, cancellation/resume, concurrent repository change, and wrong-store catalog are covered. - Opening a valid catalog does not authenticate or decrypt. - Search is responsive on large catalogs and never parses entry content in Kotlin. - Process death/update retains valid completed cache records without backing them up off-device. - No Watch controls or dead Watch state appear on Android. Depends on private-path integration, biometric authentication, shared mobile contract, and app shell. Part of #87. ## Android support update (2026-10-08) User-directed scope: Android release and CI targets are **arm64-v8a** and **armeabi-v7a**. x86_64 Android is excluded for now. Validation for every Android milestone issue uses emulator devices only; physical-device testing and physical-device checklists are excluded. Record the limits of available ARM emulator/API images without claiming physical-device coverage.
hugo added this to the 06 - Implement an Android version of the software milestone 2026-08-17 19:15:15 +00:00
hugo added the enhancement label 2026-08-17 19:15:15 +00:00
hugo added the critical label 2026-10-11 13:37:55 +00:00
Author
Owner

Implemented in f4a6edbc68 on main.

  • Preserved and completed the retained Rust/Kotlin implementation. Rust owns canonical identities, ciphertext hashes, the private non-secret catalog, authentication decisions, incremental discovery, serialized refresh, cancellation/checkpoints, stable-pass deletion pruning, and cancellable cached search.
  • Cached opening and unchanged refresh work while locked without authentication or decryption. New/changed ciphertext authenticates and reuses a valid lease. Android displays typed phases, total/inspected/cache-hit/match/unavailable counts, determinate progress, cancellation/resume, recovery notices, explicit/pull refresh and debounced latest-query-wins search. Android records/UI have no Watch state.
  • Fixed the discovery completion race: the facade stays busy until refreshed rows arrive. Final pruning and completion cannot be split by cancellation. The existing API 26 viewer test now traverses its lazy list to locate off-screen rows/actions; every original assertion remains.
  • Added real encrypted regressions for cold/warm/change/add/remove, corruption/wrong-store recovery, cancellation/checkpoint retention, concurrent ciphertext change, container relocation, and 1,000-entry cached search. Native Android coverage verifies locked warm refresh, latest-query-wins, recovery, cancellation and reconstruction of the Rust/private-session owner. Compose covers typed progress/counts, query, cancellation and no Watch controls. Documentation: docs/android/totp-discovery.md.

Validation:

  • cargo fmt --all -- --check, RUSTFLAGS="-D warnings" cargo check --workspace --all-targets, cargo clippy --workspace --all-targets -- -D warnings, and cargo test --workspace passed (519 tests). SSH fixture sockets required execution outside the filesystem/network sandbox; the unrestricted workspace run passed.
  • Android verification passed: debug/release, JVM checks, Lint/KtLint, architecture, ARM native packaging/16 KB alignment, release symbols/build IDs, manifest/backup exclusions, dependency/license/SBOM audits. CI helper self-checks: 9 passed.
  • Full app/core/bridge instrumentation and five cold starts passed on API 26 ARM64/4 KB, API 37 ARM64/4 KB, and API 37 ARM64/strict 16 KB. Opt-in biometric/inspection tests remain separate from these ordinary suite runs.
  • Computer use verified locked cached opening, explicit warm refresh, typed completion/counts and determinate progress, nonmatching cached search, and catalog retention after install-over/process recreation. The retained public strict-16-KB fixture displayed its TOTP row in portrait and adaptive landscape; warm refresh reported 4 inspected, 4 cache hits, 1 match and 0 unavailable without authentication. The exact-key-guarded opt-in fixture check passed and reuses an existing Rust-verified record without overwriting it.
  • Authenticated cold/recovery/cancellation paths were validated by native instrumentation with real encrypted public fixtures. No emulator data, preferences or enrollment were reset. No iPhone app changes. ARMv7 is built/package-audited; ARMv7 runtime and physical devices are not claimed.
  • Reviewed the completed change and connected callers against every issue acceptance criterion; no remaining implementation gap found.
Implemented in f4a6edbc6809854244174462d6fec84ed67a84e2 on main. - Preserved and completed the retained Rust/Kotlin implementation. Rust owns canonical identities, ciphertext hashes, the private non-secret catalog, authentication decisions, incremental discovery, serialized refresh, cancellation/checkpoints, stable-pass deletion pruning, and cancellable cached search. - Cached opening and unchanged refresh work while locked without authentication or decryption. New/changed ciphertext authenticates and reuses a valid lease. Android displays typed phases, total/inspected/cache-hit/match/unavailable counts, determinate progress, cancellation/resume, recovery notices, explicit/pull refresh and debounced latest-query-wins search. Android records/UI have no Watch state. - Fixed the discovery completion race: the facade stays busy until refreshed rows arrive. Final pruning and completion cannot be split by cancellation. The existing API 26 viewer test now traverses its lazy list to locate off-screen rows/actions; every original assertion remains. - Added real encrypted regressions for cold/warm/change/add/remove, corruption/wrong-store recovery, cancellation/checkpoint retention, concurrent ciphertext change, container relocation, and 1,000-entry cached search. Native Android coverage verifies locked warm refresh, latest-query-wins, recovery, cancellation and reconstruction of the Rust/private-session owner. Compose covers typed progress/counts, query, cancellation and no Watch controls. Documentation: docs/android/totp-discovery.md. Validation: - cargo fmt --all -- --check, RUSTFLAGS="-D warnings" cargo check --workspace --all-targets, cargo clippy --workspace --all-targets -- -D warnings, and cargo test --workspace passed (519 tests). SSH fixture sockets required execution outside the filesystem/network sandbox; the unrestricted workspace run passed. - Android verification passed: debug/release, JVM checks, Lint/KtLint, architecture, ARM native packaging/16 KB alignment, release symbols/build IDs, manifest/backup exclusions, dependency/license/SBOM audits. CI helper self-checks: 9 passed. - Full app/core/bridge instrumentation and five cold starts passed on API 26 ARM64/4 KB, API 37 ARM64/4 KB, and API 37 ARM64/strict 16 KB. Opt-in biometric/inspection tests remain separate from these ordinary suite runs. - Computer use verified locked cached opening, explicit warm refresh, typed completion/counts and determinate progress, nonmatching cached search, and catalog retention after install-over/process recreation. The retained public strict-16-KB fixture displayed its TOTP row in portrait and adaptive landscape; warm refresh reported 4 inspected, 4 cache hits, 1 match and 0 unavailable without authentication. The exact-key-guarded opt-in fixture check passed and reuses an existing Rust-verified record without overwriting it. - Authenticated cold/recovery/cancellation paths were validated by native instrumentation with real encrypted public fixtures. No emulator data, preferences or enrollment were reset. No iPhone app changes. ARMv7 is built/package-audited; ARMv7 runtime and physical devices are not claimed. - Reviewed the completed change and connected callers against every issue acceptance criterion; no remaining implementation gap found.
hugo closed this issue 2026-10-12 18:39:17 +00:00
Sign in to join this conversation.