Implement Android TOTP cached discovery and search (#110)
Android ARM verification / rust (push) Failing after 49m58s
Android ARM verification / android (push) Failing after 8s
Dependency security audit / rustsec (push) Failing after 22s

This commit is contained in:
hugo committed 2026-10-12 20:38:33 +02:00
1 parent 0c8366d34f
commit f4a6edbc68
18 files changed
+1070 -165

No files matched your search

+4 -3
View File
@@ -3,9 +3,10 @@
Issue [#107](https://git.rfc1437.de/hugo/IronStorage/issues/107) connects the TOTP
destination to the storage-owned discovery catalog. Opening the list reads cached
metadata without decrypting entries. Select a row, then Unlock to display its
issuer, account, grouped code, countdown and progress. Refresh TOTP catalog is an
explicit authenticated discovery action; the progress/search workflow belongs
to [#110](https://git.rfc1437.de/hugo/IronStorage/issues/110).
issuer, account, grouped code, countdown and progress. Refresh TOTP catalog reuses
unchanged ciphertext while locked and authenticates for new or changed entries;
[discovery, progress and cached search](totp-discovery.md) implement
[#110](https://git.rfc1437.de/hugo/IronStorage/issues/110).
The normal entry viewer and TOTP detail use the same code component and native
viewer controller. Decryption, creation and editing reconcile the catalog in
+1 -1
View File
@@ -30,7 +30,7 @@ Every issue linked here belongs to milestone 23.
| Password length/generation and replacement | generate; mobile_entry::MobileEntryDraft::generate_password | Generator controls call Rust | #103; Rust validation and unbiased generated value; no Kotlin generator |
| OTP URI input, camera/image import, review before Save (OtpImportViewController; TOTP Add action) | mobile_entry::MobileEntryDraft::add_otp_image; document/otp/presentation | CameraX frames or Android photo picker bytes; Rust decode and field construction | #103/#106/#107; URI/image/scan parity, invalid/oversized input, cancel; no payload parsing in Kotlin |
| Move/copy/delete entries and folders, destination browse, overwrite and dirty-editor handling (PasswordMutationCoordinator) | mobile_mutation::MobileMutationService/Plan/Request; mutation | Compose dialogs/destination picker | #108; revisions, destination conflicts, recipient reencryption and rollback |
| TOTP discovery catalog, incremental progress, warm cache, refresh, cancel/resume, cached search (TotpListViewController) | mobile_totp discovery/catalog/operation; mobile_authentication cached/search APIs | Compose list/progress/search; private no-backup catalog | #90/#110; cold/warm/change/add/remove/corrupt/wrong-store/concurrent-change tests |
| TOTP discovery catalog, incremental progress, warm cache, refresh, cancel/resume, cached search (TotpListViewController) | mobile_totp discovery/catalog/operation; mobile_authentication cached/search APIs | Compose list/progress/search; private no-backup catalog | #90/#110; [discovery behavior and evidence](totp-discovery.md), cold/warm/change/add/remove/corrupt/wrong-store/concurrent-change tests |
| TOTP rows, large detail code, countdown/expiry, copying (TotpDetailViewController, TotpCodeView) | mobile_totp::MobileOtpCodePresentation; otp; mobile_authentication::{presented_otp_code,copy_presented_otp_code,advance_presented_hotp} | Compose code/detail; OS clock facts, Rust timing | #107/#100; [OTP behavior and evidence](otp.md), RFC vectors, boundary countdown, stale callback/relock and clipboard |
| Repository/server identity, local-only/add-remote Settings, token replace/remove (PreferencesViewController, TokenUpdateViewController) | mobile_authentication::MobilePreferences; mobile_onboarding::replace_configured_application_token; config/secret_store | Compose Settings/facade | #104/#95; no token display; protected replacement/removal and offline operation |
| Key identity/fingerprint, GPG recovery import and public/private QR export (KeyImportScannerViewController, KeyExportListViewController, KeyQrExportViewController) | mobile_key_transfer::{MobileKeyTransferService,MobileKeyTransferImport}; crypto/presentation | CameraX Preview/ImageAnalysis; animated Rust-provided matrices | #106/#104; multi-frame order/duplicates/interruption, bounded frames, private export authorization and camera denial |
+56
View File
@@ -0,0 +1,56 @@
# Android TOTP discovery
The TOTP destination opens the storage-owned non-secret catalog while locked.
Rows are canonical entry identities and paths. Rust hashes current ciphertext
before returning a row, and Kotlin never parses entries or OTP URIs. Searching
uses the cancellable cached navigation API, debounces input, cancels the preceding
Rust operation, and publishes only the latest query's result.
Explicit refresh and pull-to-refresh use one serialized Rust discovery operation.
An unchanged usable catalog refreshes while locked without requesting a passphrase
or decrypting an entry. New or changed ciphertext requires authentication; an
existing valid lease is reused. Only changed records are decrypted. The UI polls
Rust's typed preparing, inspecting, saving, complete and cancelled phases and
shows total, inspected, cache hits, matches and unavailable counts. Progress is
determinate once the total is known. Cancellation and loss of foreground ownership
cancel native work and leave completed checkpoints available for the next refresh.
A pass that observes a changed repository never reports a complete result. Deleted
records are pruned only after a stable complete pass. Cache recovery/write notices
are presented separately from authentication/operation failures.
The existing catalog is `totp-catalog.toml` beside the private configuration in
Android's `noBackupFilesDir/ironstorage`, preserved by normal install-over updates.
The versioned store identity prevents another repository from using it. Each
record contains only canonical entry path, SHA-256 ciphertext hash, and `is_totp`.
Passwords, OTP URI/secret, issuer/account, codes, passphrases and keys are absent.
The file uses private permissions and atomic writes and is excluded from backup
and device transfer. Android bindings are built without the Watch feature, so
there are no Watch selection/status fields or controls.
Verification covers real encrypted cold/warm scans, locked zero-decrypt refresh,
changed/add/remove records, cancellation/resume without early deletion pruning,
concurrent ciphertext changes, damaged/wrong-store catalogs, relocation/update
retention, and storage-owned search across 1,000 cached entries. Android native
instrumentation additionally exercises latest-query-wins, recovery, typed progress
and reconstruction of the Rust/private-session owner while retaining the catalog.
Compose tests cover the displayed phase/counts, query control, determinate progress
and cancellation/resume message. Discovery remains busy through the subsequent
row reload, so observers cannot see an idle state with the old catalog rows.
On 2026-10-12 the required Rust gates passed, including 519 workspace tests.
Android verification passed for debug/release, both ARM ABIs, Lint, KtLint,
manifest/backup rules, native alignment/debug symbols and dependency/license/SBOM
audits. Full app, core and bridge instrumentation plus five cold starts passed on
API 26 ARM64/4 KB, API 37 ARM64/4 KB and API 37 ARM64/strict 16 KB.
Computer use verified locked catalog opening, explicit warm refresh with all
records reported as cache hits, typed counts/determinate completion, a nonmatching
query, and catalog retention after install-over/process recreation. The retained
public fixture on the strict 16 KB emulator also displayed its TOTP row in
portrait and adaptive landscape; warm refresh reported four inspected records,
four cache hits, one match and zero unavailable records without authentication.
Authenticated cold/recovery/cancellation paths use real encrypted public fixtures
in native instrumentation. The opt-in retained fixture helper checks its exact
public key fingerprint and reuses an existing current TOTP record without replacing
it. No emulator data or enrollment was reset. ARMv7 is package-audited; its runtime
and physical devices are outside the available emulator evidence.