108 lines
3.1 KiB
Rust
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(())
|
|
}
|
|
}
|
|
|