use std::cmp;
use std::time;
use sequoia_openpgp as openpgp;
use openpgp::types::RevocationStatus as OpenPgpRevocationStatus;
use openpgp::packet::Signature;
use openpgp::types::ReasonForRevocation;
use crate::Result;
use crate::Error;
#[derive(Debug, Clone, Eq)]
pub enum RevocationStatus {
NotAsFarAsWeKnow,
Soft(time::SystemTime),
Hard,
}
impl RevocationStatus {
pub fn in_effect(&self, t: time::SystemTime) -> bool {
match self {
RevocationStatus::NotAsFarAsWeKnow => false,
RevocationStatus::Soft(rev_t) => t >= *rev_t,
RevocationStatus::Hard => true,
}
}
}
impl Default for RevocationStatus {
fn default() -> Self {
RevocationStatus::NotAsFarAsWeKnow
}
}
impl Ord for RevocationStatus {
fn cmp(&self, other: &Self) -> cmp::Ordering {
use cmp::Ordering::*;
use RevocationStatus::*;
match (self, other) {
(NotAsFarAsWeKnow, NotAsFarAsWeKnow) => Equal,
(NotAsFarAsWeKnow, Soft(_)) => Less,
(NotAsFarAsWeKnow, Hard) => Less,
(Soft(_), NotAsFarAsWeKnow) => Greater,
(Soft(t1), Soft(t2)) => t1.cmp(t2).reverse(),
(Soft(_), Hard) => Less,
(Hard, NotAsFarAsWeKnow) => Greater,
(Hard, Soft(_)) => Greater,
(Hard, Hard) => Equal,
}
}
}
impl PartialOrd for RevocationStatus {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for RevocationStatus {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == cmp::Ordering::Equal
}
}
impl<'a> From<&OpenPgpRevocationStatus<'a>> for RevocationStatus {
fn from(rs: &OpenPgpRevocationStatus<'a>) -> Self {
match rs {
OpenPgpRevocationStatus::Revoked(sigs) => {
sigs.into_iter()
.map(|sig| {
RevocationStatus::try_from(*sig).expect("revocation")
})
.max()
.expect("revoked, but no revocation certificates")
}
OpenPgpRevocationStatus::CouldBe(_) => {
RevocationStatus::NotAsFarAsWeKnow
}
OpenPgpRevocationStatus::NotAsFarAsWeKnow => {
RevocationStatus::NotAsFarAsWeKnow
}
}
}
}
impl<'a> From<OpenPgpRevocationStatus<'a>> for RevocationStatus {
fn from(rs: OpenPgpRevocationStatus<'a>) -> Self {
RevocationStatus::from(&rs)
}
}
impl TryFrom<&Signature> for RevocationStatus {
type Error = anyhow::Error;
fn try_from(sig: &Signature) -> Result<Self> {
use openpgp::types::SignatureType;
use openpgp::types::RevocationType;
let rev_type = match sig.typ() {
SignatureType::KeyRevocation
| SignatureType::SubkeyRevocation
| SignatureType::CertificationRevocation => {
let r: Option<ReasonForRevocation>
= sig.reason_for_revocation().map(|(r, _msg)| r);
match r {
None => RevocationType::Hard,
Some(reason) => reason.revocation_type(),
}
}
_ => return Err(Error::NotARevocationCertificate.into()),
};
let rs = match rev_type {
RevocationType::Hard => RevocationStatus::Hard,
RevocationType::Soft =>
RevocationStatus::Soft(
sig.signature_creation_time()
.unwrap_or(time::UNIX_EPOCH)),
};
Ok(rs)
}
}