#[tracing::instrument(skip(root))]
pub fn load(
root: impl Into<PathBuf>,
platform: Platform,
username: String,
) -> Result<Option<Self>> {
let mut root: PathBuf = root.into();
root.push("identities");
root.push(platform.as_path());
root.push(&username);
if !root.try_exists()? {
return Ok(None);
}
let mut ssh = HashSet::new();
let mut gpg = HashMap::new();
debug!("Loading keys from {}", root.display());
for entry in fs::read_dir(&root)? {
let entry = entry?;
let path = entry.path();
match path.extension().and_then(|os| os.to_str()) {
Some("ssh") => {
let key = ssh::PublicKey::read_openssh_file(&path)?;
debug!("Read SSH key from {}", path.display());
ssh.insert(key);
},
Some("gpg") => {
let ascii = fs::read_to_string(&path)?;
let (key, _) = gpg::SignedPublicKey::from_string(&ascii)?;
debug!("Read GPG key from {}", path.display());
gpg.insert(key.fingerprint(), key);
},
_ => {},
}
}
Ok(Some(Self {
platform,
username,
ssh,
gpg,
}))
}
#[tracing::instrument(skip_all, fields(platform = ?self.platform, username = self.username))]
pub fn store(&self, root: impl Into<PathBuf>) -> Result<()> {
let mut root: PathBuf = root.into();
root.push("identities");
root.push(self.platform.as_path());
root.push(&self.username);
fs::create_dir_all(&root)?;
for key in &self.ssh {
let fp = key.fingerprint(ssh::HashAlg::Sha512);
root.push(bs58::encode(fp.as_bytes()).into_string());
root.set_extension("tmp");
let mut file = fs::File::options()
.create_new(true)
.write(true)
.open(&root)?;
let key = key.to_openssh()?;
file.write_all(key.as_bytes())?;
file.sync_all()?;
drop(file);
let target = root.with_extension("ssh");
fs::rename(&root, &target)?;
debug!("Wrote SSH key to {}", target.display());
root.pop();
}
for (fp, key) in &self.gpg {
root.push(hex::encode_upper(fp));
root.set_extension("tmp");
let mut file = fs::File::options()
.create_new(true)
.write(true)
.open(&root)?;
key.to_armored_writer(&mut file, None)?;
file.sync_all()?;
drop(file);
let target = root.with_extension("gpg");
fs::rename(&root, &target)?;
debug!("Wrote GPG key to {}", target.display());
root.pop();
}
Ok(())
}