Implement iPhone and Apple Watch preferences (#53)

This commit is contained in:
2026-08-15 22:37:31 +02:00
parent 81886756a2
commit 5ae6ef55ad
14 changed files with 1402 additions and 60 deletions

View File

@@ -249,6 +249,30 @@ fn user_activity_extends_the_lease_but_secret_access_and_timer_polling_do_not()
Ok(())
}
#[test]
fn timeout_updates_apply_to_the_active_lease_and_later_activity() -> TestResult {
let fixture = FixtureSet::load()?;
let keys = KeyStore::load(fixture.path("keys"))?;
let alice = fixture_key(&fixture, &keys, "alice")?;
let backend = MemoryBackend::default();
provision_passphrase(
backend.clone(),
&alice,
fixture.key("alice")?.passphrase.as_bytes(),
)?;
let clock = ManualClock::default();
let session = session(backend, clock.clone(), 120)?;
let handle = session.authenticate(&alice)?;
clock.advance(Duration::from_secs(20));
session.set_timeout(AuthenticationTimeout::new(Duration::from_secs(30))?)?;
assert_eq!(handle.remaining_time()?, Duration::from_secs(30));
clock.advance(Duration::from_secs(10));
handle.touch_user_activity()?;
assert_eq!(handle.remaining_time()?, Duration::from_secs(30));
Ok(())
}
#[test]
fn manual_lock_cancellation_and_expiry_revoke_all_existing_handles() -> TestResult {
let fixture = FixtureSet::load()?;

View File

@@ -4,8 +4,10 @@ use std::{collections::BTreeSet, error::Error, ffi::OsStr, fs, path::Path, time:
use ironstorage::presentation::DEFAULT_CLIPBOARD_TIMEOUT;
use ironstorage::{
authentication::{DEFAULT_AUTHENTICATION_TIMEOUT, MAX_AUTHENTICATION_TIMEOUT},
config::{ConfigError, ConfigLoader, EditorSource},
authentication::{
AuthenticationTimeout, DEFAULT_AUTHENTICATION_TIMEOUT, MAX_AUTHENTICATION_TIMEOUT,
},
config::{ConfigError, ConfigLoader, EditorSource, MobileAppearance},
desktop::DesktopStorage,
git::GitIdentity,
mobile::MobileTab,
@@ -299,6 +301,29 @@ fn biometric_preference_is_secret_free_and_defaults_to_disabled() -> TestResult
Ok(())
}
#[test]
fn mobile_timeout_and_appearance_share_the_secret_free_configuration() -> TestResult {
let fixture = ConfigurationFixture::new()?;
fs::create_dir_all(fixture.temporary.path().join("cwd/vault"))?;
fixture.write_explicit(fixture.valid_contents())?;
let config = fixture.loader().load(Some(&fixture.explicit_path()))?;
assert_eq!(config.mobile_appearance(), MobileAppearance::System);
config.update_mobile_appearance(MobileAppearance::Dark)?;
config.update_authentication_timeout(AuthenticationTimeout::new(Duration::from_secs(300))?)?;
let reloaded = fixture.loader().load(Some(&fixture.explicit_path()))?;
assert_eq!(reloaded.mobile_appearance(), MobileAppearance::Dark);
assert_eq!(
reloaded.authentication_timeout().duration(),
Duration::from_secs(300)
);
let contents = fs::read_to_string(fixture.explicit_path())?;
assert!(contents.contains("mobile_appearance = \"dark\""));
assert!(contents.contains("inactivity_timeout_seconds = 300"));
assert!(!contents.to_ascii_lowercase().contains("token ="));
Ok(())
}
#[test]
fn desktop_vault_switch_preserves_and_reloads_the_shared_configuration() -> TestResult {
let fixture = ConfigurationFixture::new()?;

View File

@@ -11,7 +11,7 @@ use std::{
};
use ironstorage::{
config::ConfigLoader,
config::{ConfigLoader, GitRemote},
crypto::{CryptoError, KeyInfo, KeyStore, SecretProvider as _, SecretProviderError},
git::{GitCredentialProvider as _, GitError},
repository::{EncryptedEntry, SecretBytes},
@@ -325,6 +325,40 @@ fn bounded_cache_is_cleared_by_lock_and_never_aliases_git_accounts() -> TestResu
Ok(())
}
#[test]
fn git_account_status_and_removal_never_expose_the_token() -> TestResult {
let backend = MemoryBackend::default();
let store = SecretStore::new(
backend,
SecretCachePolicy::Disabled,
SecretProtectionPolicy::device_unlocked(),
);
let remote = GitRemote::https(
"origin",
"https://git.example.test/alice/store.git",
"personal-git",
"ironstorage-mobile",
)?;
store.unlock()?;
store.store_https_git_credential(
remote.server_id(),
remote.application_id(),
"alice",
SecretBytes::new(b"private-token".to_vec()),
)?;
assert_eq!(
store.https_git_credential_account(remote.server_id(), remote.application_id())?,
"alice"
);
store.delete_https_git_credential(remote.server_id(), remote.application_id())?;
assert!(matches!(
store.https_git_credential_account(remote.server_id(), remote.application_id()),
Err(SecretStoreError::Missing)
));
assert!(!format!("{store:?}").contains("private-token"));
Ok(())
}
#[test]
fn one_unlocked_provider_supplies_openpgp_and_https_git_secrets() -> TestResult {
let fixture = FixtureSet::load()?;