use std::path::{Path, PathBuf};
pub use crate::runtime_paths::{
CHAIN_CHECKPOINT_FILE, LEGACY_MIGRATED_MARKER, MIGRATED_FROM_FILE, RUNTIME_DIR_ENV,
user_chain_root,
};
pub const USER_KEY_FILE: &str = "user.key";
pub fn user_key_path(home: &Path) -> PathBuf {
crate::runtime_paths::user_weftos_dir(home).join(USER_KEY_FILE)
}
pub fn chain_key_for_checkpoint(checkpoint: &Path) -> PathBuf {
let fallback = checkpoint.with_extension("key");
let user_key = checkpoint
.parent()
.filter(|chain_dir| chain_dir.file_name().is_some_and(|n| n == "chain"))
.and_then(Path::parent)
.filter(|weftos| weftos.file_name().is_some_and(|n| n == ".weftos"))
.map(|weftos| weftos.join(USER_KEY_FILE));
match user_key {
Some(p) if std::fs::symlink_metadata(&p).is_ok() => p,
_ => fallback,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn user_key_hangs_off_weftos_dir() {
assert_eq!(user_key_path(Path::new("/h")), Path::new("/h/.weftos/user.key"));
}
#[test]
fn loader_prefers_user_key_and_falls_back_to_chain_key() {
let t = tempfile::tempdir().unwrap();
let weftos = t.path().join(".weftos");
let ckpt = weftos.join("chain").join("chain.json");
std::fs::create_dir_all(ckpt.parent().unwrap()).unwrap();
assert_eq!(chain_key_for_checkpoint(&ckpt), weftos.join("chain").join("chain.key"));
std::fs::write(weftos.join("user.key"), [1u8; 32]).unwrap();
assert_eq!(chain_key_for_checkpoint(&ckpt), weftos.join("user.key"));
}
#[test]
fn other_checkpoints_always_use_their_own_key() {
let t = tempfile::tempdir().unwrap();
std::fs::write(t.path().join("user.key"), [1u8; 32]).unwrap();
let ckpt = t.path().join("runtime").join("chain.json");
assert_eq!(chain_key_for_checkpoint(&ckpt), t.path().join("runtime").join("chain.key"));
}
}