use tracing::{debug, info, trace};
use crate::{libp2p::Keypair, utils::io::write_new_sensitive_file};
use std::{fs, path::Path};
const KEYPAIR_FILE: &str = "keypair";
pub fn get_or_create_keypair(data_dir: &Path) -> anyhow::Result<Keypair> {
match get_keypair(&data_dir.join(KEYPAIR_FILE)) {
Some(keypair) => Ok(keypair),
None => create_and_save_keypair(data_dir),
}
}
fn create_and_save_keypair(path: &Path) -> anyhow::Result<Keypair> {
let gen_keypair = crate::libp2p::ed25519::Keypair::generate();
let keypair_path = path.join(KEYPAIR_FILE);
if keypair_path.exists() {
let mut backup_path = keypair_path.clone();
backup_path.set_extension("bak");
info!("Backing up existing keypair to {}", backup_path.display());
fs::rename(&keypair_path, &backup_path)?;
}
write_new_sensitive_file(&gen_keypair.to_bytes(), &keypair_path)?;
Ok(gen_keypair.into())
}
pub fn get_keypair(path_to_file: &Path) -> Option<Keypair> {
match std::fs::read(path_to_file) {
Err(e) => {
info!("Networking keystore not found!");
trace!("Error {e}");
None
}
Ok(mut vec) => match crate::libp2p::ed25519::Keypair::try_from_bytes(&mut vec) {
Ok(kp) => {
debug!("Recovered libp2p keypair from {}", path_to_file.display());
Some(kp.into())
}
Err(e) => {
info!("Could not decode networking keystore!");
info!("Error {e}");
None
}
},
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::remove_file;
use tempfile::tempdir;
#[test]
fn test_get_or_create_keypair() {
let dir = tempdir().unwrap();
let path_to_file = dir.path().join(KEYPAIR_FILE);
let keypair = get_or_create_keypair(dir.path()).unwrap();
assert!(path_to_file.exists());
let keypair2 = get_or_create_keypair(dir.path()).unwrap();
assert_eq!(keypair.public(), keypair2.public());
assert_eq!(
keypair.clone().try_into_ed25519().unwrap().to_bytes(),
keypair2.try_into_ed25519().unwrap().to_bytes()
);
remove_file(&path_to_file).unwrap();
let keypair3 = get_or_create_keypair(dir.path()).unwrap();
assert_ne!(keypair.public(), keypair3.public());
assert_ne!(
keypair.try_into_ed25519().unwrap().to_bytes(),
keypair3.try_into_ed25519().unwrap().to_bytes()
);
}
#[test]
fn test_backup_keypair() {
let dir = tempdir().unwrap();
let path_to_file = dir.path().join(KEYPAIR_FILE);
let keypair = create_and_save_keypair(dir.path()).unwrap();
assert!(path_to_file.exists());
fs::write(
&path_to_file,
b"Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn",
)
.unwrap();
let keypair2 = get_or_create_keypair(dir.path()).unwrap();
assert_ne!(keypair.public(), keypair2.public());
assert_ne!(
keypair.try_into_ed25519().unwrap().to_bytes(),
keypair2.try_into_ed25519().unwrap().to_bytes()
);
assert!(path_to_file.exists());
assert!(dir.path().join(format!("{}.bak", KEYPAIR_FILE)).exists());
}
}