Complete Android parity and security audit (#111)
This commit is contained in:
1 parent
45d78aa5b3
commit
b54636b7bc
14 files changed
+498
-75
No files matched your search
+30
-30
@@ -1,43 +1,43 @@
|
||||
# Android parity and issue ownership
|
||||
|
||||
Contract for [#88](https://git.rfc1437.de/hugo/IronStorage/issues/88), reviewed
|
||||
2026-10-08 against apple/Sources/App/IronStorageApp.swift,
|
||||
2026-10-15 against apple/Sources/App/IronStorageApp.swift,
|
||||
apple/Sources/AutoFill/CredentialProviderViewController.swift, crates/apple/src/lib.rs,
|
||||
and crates/storage/src/mobile*.rs. See [architecture.md](architecture.md) for
|
||||
support, dependency, security and update policy.
|
||||
|
||||
**Status:** #88 records the architecture baseline. The Android shell (#89),
|
||||
native packaging (#92), shared contract (#91), and private runtime (#90) are
|
||||
implemented; feature presentation rows remain assigned below. Issue comments
|
||||
record per-issue validation and outstanding test gaps. #111 must attach the
|
||||
final screen/component/test evidence to each row before claiming full parity.
|
||||
Every issue linked here belongs to milestone 23.
|
||||
**Status:** implementation issues #89–#110 are delivered. The #111 audit
|
||||
maps each capability to current Android components and executable checks below.
|
||||
[audit.md](audit.md) records current results, dependency decisions and explicit
|
||||
runtime limits. Test names identify coverage; opt-in tests need separate runtime
|
||||
evidence and are not counted as exercised by a normal suite.
|
||||
Every implementation issue linked here belongs to milestone 23.
|
||||
|
||||
## Current iPhone and shared-mobile capabilities
|
||||
|
||||
| Existing capability / source | Owning Rust API/module | Android presentation / approved API | Implementation and required evidence |
|
||||
| --- | --- | --- | --- |
|
||||
| Five destinations: Home, Passwords, Search, TOTP, Preferences; loading/empty/ready/locked/error fixtures (AppContext, ShellViewController) | mobile::MobileShell, MobileTab, MobileShellState; config selected tab | Single Activity, Compose Material 3 Adaptive, Navigation 3, ViewModel/StateFlow | #89/#91/#102; shell fixtures, startup, back/navigation and recreation |
|
||||
| Local-first setup, generated/imported key, passphrase confirmation, staged QR import (SetupChoiceViewController, LocalSetupViewController) | mobile_onboarding::MobileOnboardingOperation, crypto; mobile_key_transfer import | Compose forms and core facade; OS input/camera adapters | #95/#106; real local init, key export/import, canceled/failed setup rollback |
|
||||
| Optional HTTPS clone, server/account/token, repository/branch discovery; attach remote to local store (OnboardingViewController) | mobile_onboarding::{MobileOnboardingRequest, MobileOnboardingOperation}; git/config/secret_store | Forms, typed incremental progress and cancel | #95; TLS/auth/branch/cancel/offline errors; repository remote authority |
|
||||
| Home history, ahead/behind, local/remote change status, commit activity (ShellViewController, MobileCommitActivityViewController) | mobile_home::MobileHomePage/Operation and git | Compose Home/list/detail | #97; summaries and stale/error state, Git identity, author/history |
|
||||
| Commit, Fetch, Pull, Push and pull-then-push Sync | mobile_home::MobileHomeOperation; git sync/merge/conflicts/signing | Typed actions, progress/cancel, conflict presentation | #97; pull failure prevents push, conflict/data-loss cases and signing |
|
||||
| Directory hierarchy, breadcrumbs, folder and entry rows (PasswordDirectoryViewController) | mobile_passwords::MobilePasswordPage/Row/RowKind; repository/read | Adaptive list/detail with stable IDs | #96; deep tree, empty/error, keyboard and size changes |
|
||||
| Password-store name search (PasswordSearchViewController) | mobile_passwords::MobilePasswordPage::search | Search ViewModel, Flow latest-query-wins | #101; large-store responsiveness and canceled/stale results |
|
||||
| Unlock entry, explicit user activity, timeout, manual/background lock; shared entry/TOTP/editor lease (LockedPasswordViewController, AppContext) | mobile_authentication::MobileAuthentication; authentication generation/leases | AndroidX BiometricPrompt/CryptoObject, KeyguardManager, lifecycle | #93/#98/#100; wrong passphrase, cancel, expiry, generation race, changed enrollment and process death |
|
||||
| Structured fields/sections, masked secrets, explicit reveal/select/copy; OTP field diagnostics (MobileEntryFieldCell) | mobile_entry::MobileEntryPage/Field; mobile_authentication::{entry_page,reveal_entry_field,copy_entry_field} | Compose viewer, sensitive controls and accessibility semantics | #99/#100; no pre-unlock values, relock clears all views, copy expiry/ownership |
|
||||
| Create entry/folder, structured multiline editing, add/remove/reorder fields, dirty discard confirmation (MobileEntryEditorViewController) | mobile_entry::MobileEntryDraft; mobile_authentication editor session/create/save/discard; write | Compose editor/forms, stable field IDs | #103; actual encrypted saves, conflict tokens, interrupted saves and dirty navigation |
|
||||
| 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; [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 |
|
||||
| Inactivity timeout, biometric enable/disable, Lock Now, appearance and Git commit name/email | mobile_authentication preference setters, git_identity; config | Compose Settings, BiometricPrompt, system/light/dark theme | #98/#104; persistent settings, validation, Keystore enrollment/recovery and lease revocation |
|
||||
| iPhone AutoFill credential selection (CredentialProviderViewController) and shared identity/access domain | desktop/read/document/secret_store today; storage-owned provider contract to add | AndroidX CredentialProviderService (API 34+) and framework AutofillService (API 26+) | #109; typed caller/site identity, non-secret candidates, explicit selection/auth, forged/stale requests, permissions and cross-process lifetime |
|
||||
| Camera permissions, private paths, secret-store mechanics, clipboard, scene/process events, screen privacy | Rust repository/config/secret_store/authentication/presentation; platform callbacks contain facts only | Android framework adapters, FLAG_SECURE, backup rules, ClipboardManager | #90/#93/#98/#100; backup inspection, sandbox paths, pressure/update, screen/clipboard/lifecycle tests |
|
||||
| Accessible labels/actions, large text, keyboard, responsive layout and localization | Typed Rust state/actions; UI accessibility is Kotlin | Compose semantics, TalkBack, adaptive layout, resources | #105; measured keyboard/TalkBack/large-font/multi-window/RTL/rotation coverage |
|
||||
| Five destinations: Home, Passwords, Search, TOTP, Preferences; loading/empty/ready/locked/error fixtures (AppContext, ShellViewController) | mobile::MobileShell, MobileTab, MobileShellState; config selected tab | `ShellScreen / ShellViewModel / MainActivity` | #89/#91/#102; shell fixtures, startup, back/navigation and recreation; **Checks:** ShellScreenTest, AdaptiveShellTest, Tier2WindowTest, HingeWindowTest |
|
||||
| Local-first setup, generated/imported key, passphrase confirmation, staged QR import (SetupChoiceViewController, LocalSetupViewController) | mobile_onboarding::MobileOnboardingOperation, crypto; mobile_key_transfer import | `OnboardingScreen / NativeOnboardingRepository` | #95/#106; real local init, key export/import, canceled/failed setup rollback; **Checks:** OnboardingScreenTest; Rust mobile_onboarding::android::tests |
|
||||
| Optional HTTPS clone, server/account/token, repository/branch discovery; attach remote to local store (OnboardingViewController) | mobile_onboarding::{MobileOnboardingRequest, MobileOnboardingOperation}; git/config/secret_store | `OnboardingScreen and SettingsScreen HTTPS actions` | #95; TLS/auth/branch/cancel/offline errors; repository remote authority; **Checks:** OnboardingScreenTest; Rust onboarding and git TLS/auth/remote-authority tests |
|
||||
| Home history, ahead/behind, local/remote change status, commit activity (ShellViewController, MobileCommitActivityViewController) | mobile_home::MobileHomePage/Operation and git | `HomeScreen / NativeHomeRepository` | #97; summaries and stale/error state, Git identity, author/history; **Checks:** HomeScreenTest; Rust mobile_home and tests/git_embedded.rs |
|
||||
| Commit, Fetch, Pull, Push and pull-then-push Sync | mobile_home::MobileHomeOperation; git sync/merge/conflicts/signing | `HomeScreen typed actions and progress` | #97; pull failure prevents push, conflict/data-loss cases and signing; **Checks:** HomeScreenTest; Rust mobile_home::android_tests and Git conflict/cancellation tests |
|
||||
| Directory hierarchy, breadcrumbs, folder and entry rows (PasswordDirectoryViewController) | mobile_passwords::MobilePasswordPage/Row/RowKind; repository/read | `PasswordScreen / NativePasswordRepository` | #96; deep tree, empty/error, keyboard and size changes; **Checks:** PasswordScreenTest, NativeEntryViewerTest, NativeTreeMutationTest |
|
||||
| Password-store name search (PasswordSearchViewController) | mobile_passwords::MobilePasswordPage::search | `SearchScreen / NativeSearchRepository` | #101; large-store responsiveness and canceled/stale results; **Checks:** SearchScreenTest; Rust mobile_passwords and large-store native instrumentation |
|
||||
| Unlock entry, explicit user activity, timeout, manual/background lock; shared entry/TOTP/editor lease (LockedPasswordViewController, AppContext) | mobile_authentication::MobileAuthentication; authentication generation/leases | `AuthenticationControls / AndroidKeystoreAdapter / MainActivity lifecycle` | #93/#98/#100; wrong passphrase, cancel, expiry, generation race, changed enrollment and process death; **Checks:** AuthenticationScreenTest, opt-in AuthenticationLeaseTest, AndroidKeystoreTest; tests/authentication_leases.rs |
|
||||
| Structured fields/sections, masked secrets, explicit reveal/select/copy; OTP field diagnostics (MobileEntryFieldCell) | mobile_entry::MobileEntryPage/Field; mobile_authentication::{entry_page,reveal_entry_field,copy_entry_field} | `EntryViewer / NativePasswordRepository` | #99/#100; no pre-unlock values, relock clears all views, copy expiry/ownership; **Checks:** EntryViewerTest, NativeEntryViewerTest, NativeOtpPresentationTest; tests/entry_documents.rs |
|
||||
| Create entry/folder, structured multiline editing, add/remove/reorder fields, dirty discard confirmation (MobileEntryEditorViewController) | mobile_entry::MobileEntryDraft; mobile_authentication editor session/create/save/discard; write | `EntryEditorScreen / NativeEditorRepository` | #103; actual encrypted saves, conflict tokens, interrupted saves and dirty navigation; **Checks:** EntryEditorScreenTest, NativeEntryViewerTest; Rust editor conflict/checkpoint/atomic-save tests |
|
||||
| Password length/generation and replacement | generate; mobile_entry::MobileEntryDraft::generate_password | `EntryEditorScreen generator controls` | #103; Rust validation and unbiased generated value; no Kotlin generator; **Checks:** EntryEditorScreenTest; tests/password_generation.rs |
|
||||
| OTP URI input, camera/image import, review before Save (OtpImportViewController; TOTP Add action) | mobile_entry::MobileEntryDraft::add_otp_image; document/otp/presentation | `EntryEditorScreen / QrCameraPane / AndroidQrCamera` | #103/#106/#107; URI/image/scan parity, invalid/oversized input, cancel; no payload parsing in Kotlin; **Checks:** EntryEditorScreenTest, AndroidQrCameraTest; Rust qr and tests/otp.rs |
|
||||
| Move/copy/delete entries and folders, destination browse, overwrite and dirty-editor handling (PasswordMutationCoordinator) | mobile_mutation::MobileMutationService/Plan/Request; mutation | `MutationDialog / NativePasswordRepository` | #108; revisions, destination conflicts, recipient reencryption and rollback; **Checks:** MutationWorkflowTest, NativeTreeMutationTest; tests/tree_mutations.rs and recipient_policy.rs |
|
||||
| TOTP discovery catalog, incremental progress, warm cache, refresh, cancel/resume, cached search (TotpListViewController) | mobile_totp discovery/catalog/operation; mobile_authentication cached/search APIs | `TotpScreen / NativeTotpRepository` | #90/#110; [discovery behavior and evidence](totp-discovery.md), cold/warm/change/add/remove/corrupt/wrong-store/concurrent-change tests; **Checks:** TotpDiscoveryFixtureTest, NativeTotpDiscoveryTest, NativeTotpPerformanceTest; tests/mobile_totp.rs |
|
||||
| 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} | `TotpScreen / OtpCodeView / EntryViewer` | #107/#100; [OTP behavior and evidence](otp.md), RFC vectors, boundary countdown, stale callback/relock and clipboard; **Checks:** TotpScreenTest, NativeOtpPresentationTest; Rust OTP boundary/relock/HOTP tests |
|
||||
| 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 | `SettingsScreen / NativeSettingsRepository` | #104/#95; no token display; protected replacement/removal and offline operation; **Checks:** SettingsScreenTest; Rust preference/token and Android onboarding tests |
|
||||
| Key identity/fingerprint, GPG recovery import and public/private QR export (KeyImportScannerViewController, KeyExportListViewController, KeyQrExportViewController) | mobile_key_transfer::{MobileKeyTransferService,MobileKeyTransferImport}; crypto/presentation | `SettingsScreen key transfer / QrCameraPane / AndroidQrCamera` | #106/#104; multi-frame order/duplicates/interruption, bounded frames, private export authorization and camera denial; **Checks:** SettingsScreenTest, AndroidQrCameraTest; Rust mobile_key_transfer frame/order/cancel/authorization tests |
|
||||
| Inactivity timeout, biometric enable/disable, Lock Now, appearance and Git commit name/email | mobile_authentication preference setters, git_identity; config | `SettingsScreen / AuthenticationControls / ApplicationTheme` | #98/#104; persistent settings, validation, Keystore enrollment/recovery and lease revocation; **Checks:** SettingsScreenTest, NativeEntryViewerTest, opt-in AuthenticationLeaseTest; Rust authenticated preference tests |
|
||||
| AutoFill extension boundary (current iPhone controller is empty), shared identity/access domain and Android provider requirement | mobile_credentials; mobile_authentication provider request/select/fill/save APIs | `IronCredentialProviderService / IronAutofillService / CredentialSelectionActivity` | #109; typed caller/site identity, non-secret candidates, explicit selection/auth, forged/stale requests, permissions and cross-process lifetime; **Checks:** ProviderIntentSecurityTest, CredentialSelectionScreenTest, NativeCredentialProviderTest; provider-client OS journeys |
|
||||
| Camera permissions, private paths, secret-store mechanics, clipboard, scene/process events, screen privacy | Rust repository/config/secret_store/authentication/presentation; platform callbacks contain facts only | `AndroidSecretClipboard / ProtectedInput / ProtectedPresentation / MainActivity` | #90/#93/#98/#100; backup inspection, sandbox paths, pressure/update, screen/clipboard/lifecycle tests; **Checks:** PresentationSecurityTest, BackupPolicyTest, AndroidQrCameraTest; Rust secret-store and editor recovery tests |
|
||||
| Accessible labels/actions, large text, keyboard, responsive layout and localization | Typed Rust state/actions; UI accessibility is Kotlin | `Compose semantics/resources / HingeSafeLayout / HingeSafeAlertDialog` | #105; measured keyboard/TalkBack/large-font/multi-window/RTL/rotation coverage; **Checks:** Tier2WindowTest, HingeWindowTest; hardening.md records manual accessibility and exact performance evidence |
|
||||
| Watch pairing/install state in Settings; TOTP Watch selection, snapshots, receipts, transfer and watchOS detail | mobile_watch; shared bridge's explicit `watch` feature enabled only by crates/apple | Absent from Android records and UI (#91) | Deliberate Watch-only exclusion; no unsupported placeholder controls or Wear implementation |
|
||||
|
||||
Name search matches current mobile behavior; CLI/TUI decrypted grep is not an
|
||||
@@ -49,8 +49,8 @@ an Android workflow invokes them; platform presentation may not replace them.
|
||||
Current iPhone camera adapters pass OS-decoded QR bytes. Android #106 supplies bounded Y-plane/stride/orientation facts through the
|
||||
shared native contract; storage decodes and reassembles the transfer. See
|
||||
[key-transfer.md](key-transfer.md) for interruption/security behavior and evidence.
|
||||
The external-credential matching/grant API required by #109 must be implemented
|
||||
in storage, rather than copying frontend selection assumptions from AutoFill.
|
||||
The external-credential matching/grant API is implemented in `mobile_credentials`
|
||||
and `mobile_authentication`; both Android providers delegate to it.
|
||||
|
||||
## Complete milestone issue-to-layer map
|
||||
|
||||
|
||||
Reference in new issue
Block a user