Implement structured Android entry viewer (#99)
Android ARM verification / rust (push) Failing after 47m18s
Android ARM verification / android (push) Failing after 8s
Dependency security audit / rustsec (push) Successful in 22s

This commit is contained in:
hugo committed 2026-10-09 17:36:38 +02:00
1 parent 647dc1bb4b
commit c0ba6d43d8
29 files changed
+1768 -78

No files matched your search

@@ -740,6 +740,79 @@ fn mobile_expiry_and_user_input_never_reveal_old_editor_handles() -> TestResult
Ok(())
}
#[test]
fn presented_field_ids_reject_replaced_documents_and_ticks_do_not_renew_the_lease() -> TestResult {
use ironstorage::{
config::Config,
mobile_authentication::{MobileAuthentication, MobileAuthenticationErrorKind},
};
let fixture = FixtureSet::load()?;
let vault = fixture.materialize_store("basic")?;
let root = tempfile::tempdir()?;
let source = root.path().join("config.toml");
std::fs::write(
&source,
format!(
"vault = {:?}\nkey_material = {:?}\ndefault_key = {:?}\n",
vault.path().to_str().unwrap(),
fixture.path("keys").to_str().unwrap(),
fixture.key("alice")?.primary_fingerprint
),
)?;
let clock = ManualClock::default();
let authentication = MobileAuthentication::with_platform(
Config::load(Some(&source))?,
Arc::new(MemoryBackend::default()),
Arc::new(clock.clone()),
)?;
authentication.set_authentication_timeout(2)?;
authentication.unlock_entry(
"email/personal",
Some(SecretBytes::new(
fixture.key("alice")?.passphrase.as_bytes().to_vec(),
)),
)?;
let page = authentication.entry_page("email/personal", 59)?;
let id = page.page().sections()[0].fields()[0].id();
assert!(
!authentication
.reveal_presented_entry_field("email/personal", id, page.page().revision())?
.is_empty()
);
clock.advance(Duration::from_secs(1));
authentication.refresh_entry_presentation("email/personal", page.page().revision(), 60)?;
assert_eq!(authentication.state()?.remaining_seconds(), 1);
authentication.replace_entry_field("email/personal", id, "changed password".to_owned())?;
let error = authentication
.replace_presented_entry_field(
"email/personal",
id,
page.page().revision(),
"must not overwrite".to_owned(),
)
.unwrap_err();
assert_eq!(error.kind(), MobileAuthenticationErrorKind::Conflict);
assert!(!authentication.state()?.unlocked());
authentication.unlock_entry(
"email/personal",
Some(SecretBytes::new(
fixture.key("alice")?.passphrase.as_bytes().to_vec(),
)),
)?;
assert_eq!(
authentication.reveal_entry_field("email/personal", id)?,
"changed password"
);
clock.advance(Duration::from_secs(2));
assert!(
authentication
.refresh_entry_presentation("email/personal", page.page().revision(), 61)
.is_err()
);
assert!(!authentication.state()?.unlocked());
Ok(())
}
#[test]
fn locking_interrupts_an_os_prompt_before_waiting_for_the_lease_mutex() -> TestResult {
struct PromptBackend {
+2
View File
@@ -145,6 +145,7 @@ fn mobile_totp_catalog_details_and_watch_selection_are_storage_owned() -> TestRe
let detail = service.detail("otp/alice", 59, &BTreeSet::new(), &mut secrets)?;
assert_eq!(detail.code().expose(), b"94287082");
assert_eq!(detail.valid_until(), 60);
assert_eq!(detail.remaining_seconds(), 1);
assert_eq!(detail.period(), 30);
assert!(!format!("{detail:?}").contains("94287082"));
@@ -161,6 +162,7 @@ fn mobile_totp_catalog_details_and_watch_selection_are_storage_owned() -> TestRe
let detail = service.detail("otp/alice", 60, &selected, &mut secrets)?;
assert!(detail.shared_with_watch());
assert_eq!(detail.valid_until(), 90);
assert_eq!(detail.remaining_seconds(), 30);
Ok(())
}
+26
View File
@@ -139,6 +139,32 @@ fn clipboard_races_and_cancellation_never_overwrite_newer_user_content() -> Test
Ok(())
}
#[test]
fn clearing_clipboard_never_reads_or_restores_previous_secrets() -> TestResult {
let backend = MemoryClipboard::with_text(b"previous secret");
let mut manager = ClipboardManager::new(backend.clone(), ClipboardTimeout::default());
let secret = SecretBytes::new(b"copied secret".to_vec());
assert_eq!(
manager.copy_clearing_with(&secret, |_| ClipboardWait::Elapsed)?,
ClipboardDisposition::Cleared
);
assert_eq!(backend.text(), None);
assert_eq!(
manager.copy_clearing_with(&secret, |_| {
backend.set_text(b"newer value");
ClipboardWait::Elapsed
})?,
ClipboardDisposition::PreservedNewer
);
assert_eq!(backend.text().as_deref(), Some(b"newer value".as_slice()));
assert_eq!(
manager.copy_clearing_with(&secret, |_| ClipboardWait::Cancelled),
Err(ClipboardError::Cancelled)
);
assert_eq!(backend.text(), None);
Ok(())
}
#[test]
fn clipboard_validation_and_cleanup_failures_are_typed_and_redacted() -> TestResult {
assert_eq!(