diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-09-09 15:49:43 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-09-09 17:00:59 +0200 |
commit | 5fd621f485bb43cb0f81b2fcfc0bcf834ddc7893 (patch) | |
tree | 4d5873cfbaf8ebb13d748d2ba7aeffcde2c4821d | |
parent | 95dae32c90bbd61d649df9c4b0ef980a1c05a937 (diff) |
net: Update existing TPKs in a WKD.
-rw-r--r-- | net/src/wkd.rs | 59 |
1 files changed, 55 insertions, 4 deletions
diff --git a/net/src/wkd.rs b/net/src/wkd.rs index 3e18532a..0f80f937 100644 --- a/net/src/wkd.rs +++ b/net/src/wkd.rs @@ -17,10 +17,12 @@ extern crate tempfile; extern crate tokio_core; +use std::collections::HashMap; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; +use failure::ResultExt; use futures::{future, Future, Stream}; use hyper::{Uri, Client}; use hyper_tls::HttpsConnector; @@ -32,7 +34,10 @@ use nettle::{ }; use url; -use crate::openpgp::TPK; +use crate::openpgp::{ + Fingerprint, + TPK, +}; use crate::openpgp::parse::Parse; use crate::openpgp::serialize::Serialize; use crate::openpgp::tpk::TPKParser; @@ -296,7 +301,8 @@ pub fn get<S: AsRef<str>>(email_address: S) /// Inserts a key into a Web Key Directory. /// /// Creates a WKD hierarchy at `base_path` for `domain`, and inserts -/// the given `tpk`. +/// the given `tpk`. If `tpk` already exists in the WKD, it is +/// updated. Any existing TPKs are left in place. /// /// # Errors /// @@ -337,14 +343,59 @@ pub fn insert<P, S, T>(base_path: P, domain: S, direct_method: T, for address in addresses.into_iter() { let path = base_path.join(address.to_file_path(direct_method)?); fs::create_dir_all(path.parent().expect("by construction"))?; - // XXX: Update keyring, don't merely replace it! + let mut keyring = KeyRing::default(); + if path.is_file() { + for t in TPKParser::from_file(&path).context( + format!("Error parsing existing file {:?}", path))? + { + keyring.insert(t.context( + format!("Malformed TPK in existing {:?}", path))?)?; + } + } + keyring.insert(tpk.clone())?; let mut file = fs::File::create(&path)?; - tpk.export(&mut file)?; + keyring.export(&mut file)?; } Ok(()) } +struct KeyRing(HashMap<Fingerprint, TPK>); + +impl Default for KeyRing { + fn default() -> Self { + Self(Default::default()) + } +} + +impl KeyRing { + fn insert(&mut self, tpk: TPK) -> Result<()> { + let fp = tpk.fingerprint(); + if let Some(existing) = self.0.get_mut(&fp) { + *existing = existing.clone().merge(tpk)?; + } else { + self.0.insert(fp, tpk); + } + Ok(()) + } +} + +impl Serialize for KeyRing { + fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { + for tpk in self.0.values() { + tpk.serialize(o)?; + } + Ok(()) + } + + fn export(&self, o: &mut dyn std::io::Write) -> Result<()> { + for tpk in self.0.values() { + tpk.export(o)?; + } + Ok(()) + } +} + #[cfg(test)] mod tests { |