use pgp::packet::SubpacketType;
use crate::{
model::info::{CertInfo, SigInfo, SubpacketInfo, subpacket::typ_to_name},
signature,
};
pub(crate) fn print_cert_info(ci: &CertInfo, verbose: bool, ordered: bool) {
println!(
"🔐 {} v{} {}",
ci.primary.algorithm, ci.primary.version, ci.primary.fingerprint
);
println!(" ⏱️ Created {}", ci.primary.created);
if !ci.primary.revocations.is_empty() {
println!(" Revocation signatures:");
print_sig_infos(&ci.primary.revocations, verbose, ordered);
}
if !ci.primary.signatures.is_empty() {
println!(" Direct signatures:");
print_sig_infos(&ci.primary.signatures, verbose, ordered);
}
println!();
for sk in &ci.subkeys {
println!(" 🔑 {} v{} {}", sk.algorithm, sk.version, sk.fingerprint);
println!(" ⏱️ Created {}", sk.created);
if !sk.revocations.is_empty() {
println!(" subkey revocation signatures:");
print_sig_infos(&sk.revocations, verbose, ordered);
}
print_sig_infos(&sk.signatures, verbose, ordered);
println!();
}
for uid in &ci.users {
println!(" 🪪 ID {:?}", uid.id);
print_sig_infos(&uid.signatures, verbose, ordered);
println!();
}
for ua in &ci.user_attributes {
println!(" 🪪 ATTR [{:?}]", ua.id);
print_sig_infos(&ua.signatures, verbose, ordered);
println!();
}
}
fn print_sig_infos(sigs: &[SigInfo], verbose: bool, ordered: bool) {
let mut sigs = sigs.to_vec();
if ordered {
sigs.sort_by(|a, b| b.created.cmp(&a.created));
}
sigs.iter().for_each(|s| print_sig_info(s, verbose))
}
pub(crate) fn print_sig_info(s: &SigInfo, verbose: bool) {
let summary = if !verbose {
let issuer = s
.hashed
.iter()
.chain(&s.unhashed)
.find(|spi| spi.typ == SubpacketType::IssuerKeyId);
let issuer_fp = s
.hashed
.iter()
.chain(&s.unhashed)
.find(|spi| spi.typ == SubpacketType::IssuerFingerprint);
let issued_by = match (issuer, issuer_fp, &s.legacy_issuer) {
(Some(keyid), _, _) => &keyid.value,
(None, Some(fp), _) => &fp.value,
(_, _, Some(legacy)) => legacy,
(None, None, None) => "??",
};
format!(" {}, by {issued_by}", s.created)
} else {
"".to_string()
};
let sig_icon = match signature::is_revocation_type(s.typ) {
false => "🖋",
true => "🚫",
};
println!(
" {sig_icon} {:?}{summary} [{}, {}, v{}]",
s.typ, s.public_key_algo, s.hash_algo, s.version
);
if verbose {
print_subpackets(&s.hashed);
if !s.unhashed.is_empty() {
println!(" Unhashed subpackets:");
print_subpackets(&s.unhashed);
}
println!();
}
}
fn print_subpackets(subpackets: &[SubpacketInfo]) {
for sp in subpackets {
let crit = match sp.critical {
true => "!",
false => " ",
};
println!(" {crit}{}: {}", typ_to_name(sp.typ), sp.value);
}
}