use super::TempDir;
use crate::paths::AppPaths;
use crate::secret::*;
fn packaged(root: &std::path::Path) -> AppPaths {
AppPaths::from_host(
"com.example.myapp",
root.join("data"),
root.join("cache"),
root.join("resources"),
)
.expect("packaged paths")
}
#[test]
fn a_first_launch_generates_a_key_a_release_build_would_accept() {
let temp = TempDir::new("secret");
let paths = packaged(temp.path());
paths.prepare().expect("a first launch");
let secret = session_secret(&paths).expect("a key");
assert_eq!(secret.len(), 64, "32 random bytes, as hex");
assert!(secret.chars().all(|c| c.is_ascii_hexdigit()));
assert!(!secret.chars().all(|c| c == '0'));
}
#[test]
fn the_key_survives_a_restart() {
let temp = TempDir::new("secret");
let paths = packaged(temp.path());
paths.prepare().expect("a first launch");
let first = session_secret(&paths).expect("a key");
let second = session_secret(&paths).expect("the same key");
assert_eq!(first, second);
}
#[test]
fn two_installations_do_not_share_a_key() {
let one = TempDir::new("secret");
let two = TempDir::new("secret");
let (a, b) = (packaged(one.path()), packaged(two.path()));
a.prepare().unwrap();
b.prepare().unwrap();
assert_ne!(
session_secret(&a).unwrap(),
session_secret(&b).unwrap(),
"two installations were given the same signing key"
);
}
#[test]
fn the_key_is_kept_in_data_and_not_beside_the_assets() {
let temp = TempDir::new("secret");
let paths = packaged(temp.path());
paths.prepare().unwrap();
session_secret(&paths).unwrap();
let file = paths.secret_file();
assert!(file.exists());
assert!(file.starts_with(paths.data()));
assert!(!file.starts_with(paths.public()));
assert!(!file.starts_with(paths.resources()));
assert_eq!(file.file_name().unwrap(), SECRET_FILE);
}
#[cfg(windows)]
#[test]
fn the_stored_key_is_not_the_key_in_plain_text() {
let temp = TempDir::new("secret");
let paths = packaged(temp.path());
paths.prepare().unwrap();
let secret = session_secret(&paths).unwrap();
let stored = std::fs::read(paths.secret_file()).unwrap();
assert!(
!stored.windows(secret.len()).any(|w| w == secret.as_bytes()),
"the session key is on disk in plain text"
);
assert!(stored.len() > secret.len(), "nothing was encrypted");
}
#[test]
fn an_unreadable_key_file_is_replaced_rather_than_fatal() {
let temp = TempDir::new("secret");
let paths = packaged(temp.path());
paths.prepare().unwrap();
std::fs::write(paths.secret_file(), b"not a key this user can read").unwrap();
let secret = session_secret(&paths).expect("a replacement key");
assert_eq!(secret.len(), 64);
assert_eq!(session_secret(&paths).unwrap(), secret, "and it stuck");
}
#[test]
fn a_truncated_key_is_replaced() {
let temp = TempDir::new("secret");
let paths = packaged(temp.path());
paths.prepare().unwrap();
let first = session_secret(&paths).unwrap();
std::fs::write(paths.secret_file(), b"abc").unwrap();
let replacement = session_secret(&paths).expect("a replacement key");
assert_eq!(replacement.len(), 64);
assert_ne!(replacement, first);
}
#[test]
fn installing_the_key_puts_it_and_the_cookie_name_in_the_environment() {
let _guard = crate::tests::ENV_LOCK
.lock()
.unwrap_or_else(|e| e.into_inner());
let temp = TempDir::new("secret");
let paths = packaged(temp.path());
paths.prepare().unwrap();
install_session_secret(&paths, Some("rahti_session_9f2c")).expect("the environment");
assert_eq!(
std::env::var(rahti::auth::SECRET_ENV).unwrap(),
session_secret(&paths).unwrap()
);
assert_eq!(
std::env::var(rahti::auth::COOKIE_ENV).unwrap(),
"rahti_session_9f2c"
);
unsafe {
std::env::remove_var(rahti::auth::SECRET_ENV);
std::env::remove_var(rahti::auth::COOKIE_ENV);
}
}