db: treat emails correctly during publication

This commit is contained in:
Vincent Breitmoser 2020-05-14 17:38:47 +02:00
parent c3d4b448a5
commit 30bb4b2993
No known key found for this signature in database
GPG Key ID: 7BD18320DEADFA11
2 changed files with 29 additions and 39 deletions

View File

@ -53,7 +53,7 @@ mod stateful_tokens;
pub use stateful_tokens::StatefulTokens;
mod openpgp_utils;
use openpgp_utils::{tpk_filter_userids, tpk_to_string, tpk_clean, is_status_revoked, POLICY};
use openpgp_utils::{tpk_filter_userids, tpk_filter_alive_emails, tpk_to_string, tpk_clean, is_status_revoked, POLICY};
#[cfg(test)]
mod test;
@ -270,36 +270,11 @@ pub trait Database: Sync + Send {
return Ok(ImportResult::Unchanged(TpkStatus { is_revoked, email_status, unparsed_uids }));
}
// If the key is revoked, consider all uids revoked
let newly_revoked_uids: Vec<&UserID> = if is_revoked {
full_tpk_new.userids().bundles().map(|binding| binding.userid()).collect()
let published_tpk_new = if is_revoked {
tpk_filter_alive_emails(&full_tpk_new, &[])
} else {
let revoked_uids: Vec<UserID> = full_tpk_new
.userids()
.bundles()
.filter(|binding| is_status_revoked(binding.revoked(&*POLICY, None)))
.map(|binding| binding.userid().clone())
.collect();
published_tpk_old
.as_ref()
.map(|tpk| tpk
.userids()
.bundles()
.map(|binding| binding.userid())
.filter(|uid| revoked_uids.contains(uid))
.collect()
).unwrap_or_default()
};
let published_tpk_new = tpk_filter_userids(
&full_tpk_new, |uid| {
if let Ok(email) = Email::try_from(uid) {
published_emails.contains(&email) && !newly_revoked_uids.contains(&uid)
} else {
false
}
})?;
tpk_filter_alive_emails(&full_tpk_new, &published_emails)
}?;
let newly_revoked_emails: Vec<&Email> = published_emails
.iter()
@ -470,12 +445,10 @@ pub trait Database: Sync + Send {
return Ok(());
}
let published_tpk_new = {
tpk_filter_userids(&full_tpk, |uid| {
Email::try_from(uid).map(|email| email == *email_new)
.unwrap_or(false) || published_uids_old.contains(uid)
})?
};
let mut published_emails = published_emails_old.clone();
published_emails.push(email_new.clone());
let published_tpk_new = tpk_filter_alive_emails(&full_tpk, &published_emails)?;
if !published_tpk_new
.userids()
@ -556,7 +529,7 @@ pub trait Database: Sync + Send {
.collect();
let published_tpk_new = {
tpk_filter_userids(&published_tpk_old, |uid| email_remove(uid))?
tpk_filter_userids(&published_tpk_old, |uid| email_remove(uid.userid()))?
};
let published_emails_new: Vec<Email> = published_tpk_new

View File

@ -1,7 +1,9 @@
use failure::Fallible as Result;
use std::convert::TryFrom;
use openpgp::{
Cert,
cert::components::ComponentBundle,
RevocationStatus,
armor::{Writer, Kind},
packet::UserID,
@ -9,6 +11,8 @@ use openpgp::{
policy::StandardPolicy,
};
use Email;
lazy_static! {
pub static ref POLICY: StandardPolicy = StandardPolicy::new();
}
@ -62,10 +66,23 @@ pub fn tpk_clean(tpk: &Cert) -> Result<Cert> {
Cert::from_packet_pile(acc.into())
}
/// Filters the Cert, keeping only UserIDs that aren't revoked, and whose emails match the given list
pub fn tpk_filter_alive_emails(tpk: &Cert, emails: &[Email]) -> Result<Cert> {
tpk_filter_userids(tpk, |uid| {
if is_status_revoked(uid.revoked(&*POLICY, None)) {
false
} else if let Ok(email) = Email::try_from(uid.userid()) {
emails.contains(&email)
} else {
false
}
})
}
/// Filters the Cert, keeping only those UserIDs that fulfill the
/// predicate `filter`.
pub fn tpk_filter_userids<F>(tpk: &Cert, filter: F) -> Result<Cert>
where F: Fn(&UserID) -> bool
where F: Fn(&ComponentBundle<UserID>) -> bool
{
// Iterate over the Cert, pushing packets we want to merge
// into the accumulator.
@ -91,7 +108,7 @@ pub fn tpk_filter_userids<F>(tpk: &Cert, filter: F) -> Result<Cert>
// Updates for UserIDs fulfilling `filter`.
for uidb in tpk.userids().bundles() {
// Only include userids matching filter
if filter(uidb.userid()) {
if filter(uidb) {
acc.push(uidb.userid().clone().into());
for s in uidb.self_signatures() { acc.push(s.clone().into()) }
for s in uidb.certifications() { acc.push(s.clone().into()) }