use pgp::{
composed::SignedKeyDetails,
packet::Signature,
types::{SignedUser, Timestamp},
};
use crate::{signature, signature::SigStack};
fn pick_by_newest_sig<'a>(users: &'_ [(&'a SignedUser, &'a Signature)]) -> Option<&'a SignedUser> {
let mut newest: Option<(&'a SignedUser, &'a Signature)> = None;
for (su, sig) in users {
match newest {
None => newest = Some((su, sig)),
Some((_, stored)) => {
if stored.created() < sig.created() {
newest = Some((su, sig))
}
}
}
}
newest.map(|(su, _)| su)
}
pub(crate) fn primary_user_id(
details: &SignedKeyDetails,
reference: Timestamp,
key_creation: Timestamp,
) -> Option<&SignedUser> {
let candidates: Vec<_> = details
.users
.iter()
.map(|su| {
let stack = SigStack::from_iter(&su.signatures);
(su, stack.active_at(reference, key_creation))
})
.filter_map(|(su, sig)| match (su, sig) {
(u, Some(sig)) => Some((u, sig)),
(_, None) => None,
})
.filter(|(_, sig)| !signature::is_revocation(sig))
.collect();
let primary: Vec<_> = candidates
.clone()
.into_iter()
.filter(|(_, s)| s.is_primary())
.collect();
if !primary.is_empty() {
pick_by_newest_sig(&primary)
} else {
pick_by_newest_sig(&candidates)
}
}
pub(crate) fn primary_user_id_binding_at(
details: &SignedKeyDetails,
reference: Timestamp,
key_creation: Timestamp,
) -> Option<&Signature> {
primary_user_id(details, reference, key_creation).and_then(|uid| {
SigStack::from_iter(uid.signatures.iter()).active_at(reference, key_creation)
})
}