Files
husk-milter/src/types/introducer.rs
T
Malte Meiboom 21b45d1702 Some cleanups
- Remove unused errors.
- Add doc comments.
2026-05-06 16:30:42 +02:00

108 lines
3.1 KiB
Rust

//! introducers
use anyhow::Result;
use sequoia_wot as wot;
use wot::{CertSynopsis, Certification};
use sequoia_openpgp::{cert::ValidCert, policy::StandardPolicy};
use sequoia_openpgp::Cert;
use crate::types::husk_context::HuskContext;
use crate::common::crypto;
#[derive(thiserror::Error, Debug)]
pub enum IntroducerError {
#[error("Unsuitable certificate")]
UnsuitableCertificate,
}
#[derive(Debug, Clone)]
pub struct Introducer {
pub cert: CertSynopsis,
pub certification: Certification,
}
impl Introducer {
/// Can this introducer potentially introduce `email`?
///
/// This check matches the email with the list of domains of the
/// introducer.
pub fn can_introduce(&self, email: &str) -> bool {
if let Some(regexset) = self.certification.regular_expressions() {
if regexset.matches_everything() {
// return false, because unlimited certifications are
// ignored.
false
} else {
regexset.is_match(email)
}
} else {
false
}
}
pub fn is_introducing(&self, cert: &Cert) -> bool {
let policy = StandardPolicy::new();
let mut result = false;
let my_keyid = self.cert.keyid();
if let Ok(vc) = cert.with_policy(&policy, None) {
vc.userids()
.revoked(false)
.for_each(|u| {
u.certifications().for_each(|s| {
if s.signature_alive(None, None).is_ok() {
s.issuers().for_each(|i| {
if i == &my_keyid { result = true; }
});
}
})
});
}
result
}
pub fn create(context: &HuskContext, cert: &ValidCert, domains: Vec<String>)
-> Result<()> {
// Check if the local trust root certificate should be made an
// introducer, which would be an error.
if cert.fingerprint() == context.local_trust_root.fingerprint() {
return Err(IntroducerError::UnsuitableCertificate.into());
}
crypto::authenticate(context, cert, true, Some(domains))
}
pub fn remove(context: &HuskContext, cert: &ValidCert, _demote: bool)
-> Result<()> {
// Check if the local trust root certificate should be made an
// introducer, which would be an error.
if cert.fingerprint() == context.local_trust_root.fingerprint() {
return Err(IntroducerError::UnsuitableCertificate.into());
}
crypto::authenticate(context, cert, false, None)
}
}
use std::fmt::{Display, Formatter};
impl Display for Introducer {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let uids = self.cert.userids()
.map(|u| String::from_utf8_lossy(u.userid().value()).to_string())
.collect::<Vec<String>>()
.join(", ");
writeln!(f, "Introducer: {}", self.cert.fingerprint())?;
writeln!(f, " UserIDs: {}", uids)?;
Ok(())
}
}