sequoia_wot/
revocation.rs1use std::cmp;
2use std::time;
3
4use sequoia_openpgp as openpgp;
5use openpgp::types::RevocationStatus as OpenPgpRevocationStatus;
6use openpgp::packet::Signature;
7use openpgp::types::ReasonForRevocation;
8
9use crate::Result;
10use crate::Error;
11
12#[derive(Debug, Clone, Eq)]
42pub enum RevocationStatus {
43 NotAsFarAsWeKnow,
44 Soft(time::SystemTime),
45 Hard,
46}
47
48impl RevocationStatus {
49 pub fn in_effect(&self, t: time::SystemTime) -> bool {
54 match self {
55 RevocationStatus::NotAsFarAsWeKnow => false,
56 RevocationStatus::Soft(rev_t) => t >= *rev_t,
57 RevocationStatus::Hard => true,
58 }
59 }
60}
61
62impl Default for RevocationStatus {
63 fn default() -> Self {
64 RevocationStatus::NotAsFarAsWeKnow
65 }
66}
67
68impl Ord for RevocationStatus {
69 fn cmp(&self, other: &Self) -> cmp::Ordering {
73 use cmp::Ordering::*;
74 use RevocationStatus::*;
75
76 match (self, other) {
77 (NotAsFarAsWeKnow, NotAsFarAsWeKnow) => Equal,
78 (NotAsFarAsWeKnow, Soft(_)) => Less,
79 (NotAsFarAsWeKnow, Hard) => Less,
80
81 (Soft(_), NotAsFarAsWeKnow) => Greater,
82 (Soft(t1), Soft(t2)) => t1.cmp(t2).reverse(),
83 (Soft(_), Hard) => Less,
84
85 (Hard, NotAsFarAsWeKnow) => Greater,
86 (Hard, Soft(_)) => Greater,
87 (Hard, Hard) => Equal,
88 }
89 }
90}
91
92impl PartialOrd for RevocationStatus {
93 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
94 Some(self.cmp(other))
95 }
96}
97
98impl PartialEq for RevocationStatus {
99 fn eq(&self, other: &Self) -> bool {
100 self.cmp(other) == cmp::Ordering::Equal
101 }
102}
103
104impl<'a> From<&OpenPgpRevocationStatus<'a>> for RevocationStatus {
105 fn from(rs: &OpenPgpRevocationStatus<'a>) -> Self {
106 match rs {
107 OpenPgpRevocationStatus::Revoked(sigs) => {
108 sigs.into_iter()
109 .map(|sig| {
110 RevocationStatus::try_from(*sig).expect("revocation")
111 })
112 .max()
113 .expect("revoked, but no revocation certificates")
114 }
115 OpenPgpRevocationStatus::CouldBe(_) => {
116 RevocationStatus::NotAsFarAsWeKnow
117 }
118 OpenPgpRevocationStatus::NotAsFarAsWeKnow => {
119 RevocationStatus::NotAsFarAsWeKnow
120 }
121 }
122 }
123}
124
125impl<'a> From<OpenPgpRevocationStatus<'a>> for RevocationStatus {
126 fn from(rs: OpenPgpRevocationStatus<'a>) -> Self {
127 RevocationStatus::from(&rs)
128 }
129}
130
131impl TryFrom<&Signature> for RevocationStatus {
132 type Error = anyhow::Error;
133
134 fn try_from(sig: &Signature) -> Result<Self> {
135 use openpgp::types::SignatureType;
136 use openpgp::types::RevocationType;
137
138 let rev_type = match sig.typ() {
139 SignatureType::KeyRevocation
140 | SignatureType::SubkeyRevocation
141 | SignatureType::CertificationRevocation => {
142 let r: Option<ReasonForRevocation>
143 = sig.reason_for_revocation().map(|(r, _msg)| r);
144 match r {
145 None => RevocationType::Hard,
146 Some(reason) => reason.revocation_type(),
147 }
148 }
149
150 _ => return Err(Error::NotARevocationCertificate.into()),
152 };
153
154 let rs = match rev_type {
155 RevocationType::Hard => RevocationStatus::Hard,
156 RevocationType::Soft =>
157 RevocationStatus::Soft(
158 sig.signature_creation_time()
159 .unwrap_or(time::UNIX_EPOCH)),
160 };
161
162 Ok(rs)
163 }
164}