diff --git a/src/tests/crypto_tests.rs b/src/tests/crypto_tests.rs index 49f2218..b6be323 100644 --- a/src/tests/crypto_tests.rs +++ b/src/tests/crypto_tests.rs @@ -24,6 +24,7 @@ pub fn run_tests(env: JNIEnv, context: Context) -> (usize, usize) { ("missing_iv_len", missing_iv_len), ("data_too_small", data_too_small), ("invalid_iv", invalid_iv), + ("malformed_base64", malformed_base64), ("decryption_failure", decryption_failure), ("jni_instance_frames", jni_instance_frames), ("jni_static_frames", jni_static_frames), @@ -202,6 +203,35 @@ fn invalid_iv(vm: JavaVM, ctx: Context) -> keyring_core::Result<()> { Ok(()) } +fn malformed_base64(vm: JavaVM, ctx: Context) -> keyring_core::Result<()> { + let entry = Entry::new("malformed-base64", "user")?; + entry.set_password("test")?; + const MALFORMED: &str = "not base64!!!"; + { + let mut env = vm.attach_current_thread().unwrap(); + let shared = ctx + .get_shared_preferences(&mut env, "crypto-test", MODE_PRIVATE) + .unwrap(); + let editor = shared.edit(&mut env).unwrap(); + editor + .put_string(&mut env, "user@malformed-base64", MALFORMED) + .unwrap(); + editor.commit(&mut env).unwrap(); + } + match entry.get_password() { + Err(keyring_core::Error::NoEntry) => {} + x => return bad_result("malformed_base64", &format!("NoEntry, got {x:?}")), + } + entry.set_password("recovered")?; + match entry.get_password() { + Ok(p) if p.eq("recovered") => {} + Ok(p) => return bad_result("get_password", &format!("'recovered', got '{p}'")), + Err(e) => return bad_result("get_password", &format!("'recovered', got {e:?}")), + } + entry.delete_credential()?; + Ok(()) +} + fn decryption_failure(_vm: JavaVM, _ctx: Context) -> keyring_core::Result<()> { // create secret on entry with existing key let entry1 = Entry::new("corrupted", "my-user")?; diff --git a/src/tests/store_tests.rs b/src/tests/store_tests.rs index ad99eee..572b51e 100644 --- a/src/tests/store_tests.rs +++ b/src/tests/store_tests.rs @@ -15,10 +15,14 @@ pub fn run_tests() -> (usize, usize) { ("delete_credential", delete_credential), ("concurrent_access", concurrent_access), ("search", search), + ("entry_validation", entry_validation), + ("existing_credential", existing_credential), ("teardown", teardown), ("user_auth_timeout", user_auth_timeout), ("lost_key", lost_key), ("exists", exists), + ("configuration_mismatch", configuration_mismatch), + ("default_store", default_store), ] .iter() // user_auth_timeout needs a secure lock screen and a device unlocked in the last 300 seconds. @@ -231,6 +235,40 @@ fn search() -> keyring_core::Result<()> { Ok(()) } +fn entry_validation() -> keyring_core::Result<()> { + for (service, user, key) in [("a@b", "user", "service"), ("service", "u@x", "user")] { + match Entry::new(service, user) { + Err(keyring_core::Error::Invalid(k, _)) if k == key => {} + r => return bad_result("new", &format!("Invalid({key}), got {r:?}")), + } + } + let modifiers = HashMap::from([("color", "blue")]); + match Entry::new_with_modifiers("service", "user", &modifiers) { + Err(keyring_core::Error::NotSupportedByStore(_)) => {} + r => return bad_result("new_with_modifiers", &format!("NotSupported, got {r:?}")), + } + for key in ["id", "service", "user"] { + match Entry::search(&HashMap::from([(key, "(")])) { + Err(keyring_core::Error::Invalid(k, _)) if k == key => {} + r => return bad_result("search", &format!("Invalid({key}), got {r:?}")), + } + } + match Entry::new("my-service", "never-set")?.delete_credential() { + Err(keyring_core::Error::NoEntry) => Ok(()), + r => bad_result("delete_credential", &format!("NoEntry, got {r:?}")), + } +} + +fn existing_credential() -> keyring_core::Result<()> { + let entry = Entry::new("my-service", "existing-test")?; + entry.set_password("existing")?; + match entry.get_credential()?.get_password() { + Ok(p) if p == "existing" => {} + r => return bad_result("get_credential", &format!("'existing', got {r:?}")), + } + entry.delete_credential() +} + const AUTH_OPEN_CONFIG: [(&str, &str); 4] = [ ("name", "auth-open-test"), ("divider", "@"), @@ -357,3 +395,69 @@ fn exists() -> keyring_core::Result<()> { crate::Store::delete(&config)?; Ok(()) } + +const MISMATCH_CONFIG: [(&str, &str); 2] = [("name", "mismatch-test"), ("divider", "@")]; + +fn configuration_mismatch() -> keyring_core::Result<()> { + let config = HashMap::from(MISMATCH_CONFIG); + crate::Store::delete(&config)?; + let expect_invalid = |attempt: &[(&str, &str)], expected: &str| -> keyring_core::Result<()> { + let attempt = attempt.iter().copied().collect::>(); + match crate::Store::new_with_configuration(&attempt) { + Err(keyring_core::Error::Invalid(key, _)) if key == expected => Ok(()), + r => bad_result( + "new_with_configuration", + &format!("Invalid({expected}), got {r:?}"), + ), + } + }; + let store = crate::Store::new_with_configuration(&config)?; + expect_invalid( + &[ + ("name", "mismatch-test"), + ("filename", "keyring-other"), + ("divider", "@"), + ], + "filename", + )?; + expect_invalid( + &[ + ("name", "mismatch-test"), + ("divider", "@"), + ("user-auth-required", "true"), + ("user-auth-timeout", "30"), + ], + "user-auth-timeout", + )?; + drop(store); + crate::by_store::clear_vault_list(); + expect_invalid( + &[ + ("name", "other-name"), + ("filename", "keyring-mismatch-test"), + ("divider", "@"), + ], + "name", + )?; + crate::Store::delete(&config)?; + Ok(()) +} + +fn default_store() -> keyring_core::Result<()> { + let default = HashMap::new(); + crate::Store::delete(&default)?; + let store = crate::Store::new()?; + let entry = store.build("default-service", "default-user", None)?; + entry.set_password("default")?; + match entry.get_password() { + Ok(p) if p == "default" => {} + r => return bad_result("get_password", &format!("'default', got {r:?}")), + } + drop(entry); + drop(store); + crate::by_store::clear_vault_list(); + if !crate::Store::delete(&default)? { + return bad_result("delete", "true for the default store"); + } + Ok(()) +}