Files
ElyOffice/crates/ely-mail-engine/tests/vault.rs
T
ZacharyZhang-NYandClaude bd68382921 C12.4: mail credentials and OAuth sign-in
Passwords and refresh tokens go only to the system keychain; a refused
keychain keeps them in memory until exit and says why. Gmail and
Microsoft sign in by authorization code with S256 PKCE on a loopback
redirect; refresh tokens are kept, and revoked grants ask to sign in
again. Client IDs come from the build (env or oauth.env). ureq trace
records never reach the log.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-19 18:59:56 -04:00

87 lines
2.5 KiB
Rust

use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use ely_mail_engine::{Backend, Error, Kept, Vault};
#[derive(Clone, Default)]
struct Fake {
saved: Arc<Mutex<HashMap<String, String>>>,
refuse: Option<&'static str>,
}
impl Backend for Fake {
fn get(&self, name: &str) -> Result<Option<String>, String> {
match self.refuse {
Some(reason) => Err(reason.into()),
None => Ok(self.saved.lock().unwrap().get(name).cloned()),
}
}
fn set(&self, name: &str, secret: &str) -> Result<(), String> {
match self.refuse {
Some(reason) => Err(reason.into()),
None => {
self.saved
.lock()
.unwrap()
.insert(name.into(), secret.into());
Ok(())
}
}
}
fn delete(&self, name: &str) -> Result<(), String> {
match self.refuse {
Some(reason) => Err(reason.into()),
None => {
self.saved.lock().unwrap().remove(name);
Ok(())
}
}
}
}
#[test]
fn secrets_go_to_the_system_store() {
let fake = Fake::default();
let vault = Vault::new(Box::new(fake.clone()));
assert_eq!(vault.get("a").unwrap(), None);
assert_eq!(vault.put("a", "rt-1"), Kept::System);
assert_eq!(fake.saved.lock().unwrap()["a"], "rt-1");
assert_eq!(vault.get("a").unwrap().as_deref(), Some("rt-1"));
vault.remove("a").unwrap();
assert!(fake.saved.lock().unwrap().is_empty());
}
#[test]
fn a_refused_store_keeps_the_secret_for_this_session() {
let vault = Vault::new(Box::new(Fake {
refuse: Some("locked"),
..Fake::default()
}));
assert_eq!(vault.put("a", "pw"), Kept::Session("locked".into()));
assert_eq!(vault.get("a").unwrap().as_deref(), Some("pw"));
let err = vault.get("b").err().unwrap();
assert!(matches!(err, Error::Vault(text) if text.contains("locked")));
let err = vault.remove("a").err().unwrap();
assert!(matches!(err, Error::Vault(_)));
assert!(
vault.get("a").is_err(),
"the session copy is gone after remove"
);
}
#[test]
fn a_new_secret_replaces_the_session_copy() {
let fake = Fake {
refuse: Some("locked"),
..Fake::default()
};
let vault = Vault::new(Box::new(fake));
vault.put("a", "old");
assert_eq!(vault.put("a", "new"), Kept::Session("locked".into()));
assert_eq!(vault.get("a").unwrap().as_deref(), Some("new"));
}