use std::time;
use std::ops::Deref;
use crate::{
Error,
packet::Signature,
packet::Key,
packet::key,
packet::UserID,
packet::UserAttribute,
packet::Unknown,
Packet,
policy::Policy,
Result,
};
use crate::types::{
RevocationType,
RevocationStatus,
};
use super::{
sig_cmp,
canonical_signature_order,
};
mod iter;
pub use iter::{
ComponentBundleIter,
ValidComponentBundleIter,
};
#[derive(Debug, Clone, PartialEq)]
pub struct ComponentBundle<C> {
pub(crate) component: C,
pub(crate) self_signatures: Vec<Signature>,
pub(crate) certifications: Vec<Signature>,
pub(crate) self_revocations: Vec<Signature>,
pub(crate) other_revocations: Vec<Signature>,
}
pub type KeyBundle<KeyPart, KeyRole> = ComponentBundle<Key<KeyPart, KeyRole>>;
pub type PrimaryKeyBundle<KeyPart> =
KeyBundle<KeyPart, key::PrimaryRole>;
pub type SubkeyBundle<KeyPart>
= KeyBundle<KeyPart, key::SubordinateRole>;
pub type UserIDBundle = ComponentBundle<UserID>;
pub type UserAttributeBundle = ComponentBundle<UserAttribute>;
pub type UnknownBundle = ComponentBundle<Unknown>;
impl<C> Deref for ComponentBundle<C>
{
type Target = C;
fn deref(&self) -> &Self::Target {
&self.component
}
}
impl<C> ComponentBundle<C> {
pub fn component(&self) -> &C {
&self.component
}
fn component_mut(&mut self) -> &mut C {
&mut self.component
}
pub fn binding_signature<T>(&self, policy: &dyn Policy, t: T)
-> Result<&Signature>
where T: Into<Option<time::SystemTime>>
{
let t = t.into().unwrap_or_else(|| time::SystemTime::now());
let i =
if Some(t) >= self.self_signatures.get(0)
.and_then(|s| s.signature_creation_time())
{
0
} else {
match self.self_signatures.binary_search_by(
|s| canonical_signature_order(
s.signature_creation_time(), Some(t)))
{
Ok(mut i) => {
while i > 0
&& self.self_signatures[i - 1].signature_creation_time()
== Some(t)
{
i -= 1;
}
i
}
Err(i) => i,
}
};
let mut sig = None;
let mut error = None;
for s in self.self_signatures[i..].iter() {
if let Err(e) = s.signature_alive(t, time::Duration::new(0, 0)) {
if error.is_none() {
error = Some(e);
}
continue;
}
if let Err(e) = policy.signature(s) {
if error.is_none() {
error = Some(e);
}
continue;
}
sig = Some(s);
break;
}
if let Some(sig) = sig {
Ok(sig)
} else if let Some(err) = error {
Err(err)
} else {
Err(Error::NoBindingSignature(t).into())
}
}
pub fn self_signatures(&self) -> &[Signature] {
&self.self_signatures
}
pub fn certifications(&self) -> &[Signature] {
&self.certifications
}
pub fn self_revocations(&self) -> &[Signature] {
&self.self_revocations
}
pub fn other_revocations(&self) -> &[Signature] {
&self.other_revocations
}
pub(crate) fn _revoked<'a, T>(&'a self, policy: &dyn Policy, t: T,
hard_revocations_are_final: bool,
selfsig: Option<&Signature>)
-> RevocationStatus<'a>
where T: Into<Option<time::SystemTime>>
{
let time_zero = || time::UNIX_EPOCH;
let t = t.into()
.unwrap_or_else(|| time::SystemTime::now());
let selfsig_creation_time
= selfsig.and_then(|s| s.signature_creation_time())
.unwrap_or_else(time_zero);
tracer!(super::TRACE, "ComponentBundle::_revoked", 0);
t!("hard_revocations_are_final: {}, selfsig: {:?}, t: {:?}",
hard_revocations_are_final,
selfsig_creation_time,
t);
if let Some(selfsig) = selfsig {
assert!(
selfsig.signature_alive(t, time::Duration::new(0, 0)).is_ok());
}
let check = |revs: &'a [Signature]| -> Option<Vec<&'a Signature>> {
let revs = revs.iter().filter_map(|rev| {
if let Err(err) = policy.signature(rev) {
t!(" revocation rejected by caller policy: {}", err);
None
} else if hard_revocations_are_final
&& rev.reason_for_revocation()
.map(|(r, _)| {
r.revocation_type() == RevocationType::Hard
})
.unwrap_or(true)
{
t!(" got a hard revocation: {:?}, {:?}",
rev.signature_creation_time()
.unwrap_or_else(time_zero),
rev.reason_for_revocation()
.map(|r| (r.0, String::from_utf8_lossy(r.1))));
Some(rev)
} else if selfsig_creation_time
> rev.signature_creation_time().unwrap_or_else(time_zero)
{
t!(" newer binding signature trumps soft revocation ({:?} > {:?})",
selfsig_creation_time,
rev.signature_creation_time().unwrap_or_else(time_zero));
None
} else if let Err(err)
= rev.signature_alive(t, time::Duration::new(0, 0))
{
t!(" revocation not alive ({:?} - {:?}): {}",
rev.signature_creation_time().unwrap_or_else(time_zero),
rev.signature_validity_period()
.unwrap_or_else(|| time::Duration::new(0, 0)),
err);
None
} else {
t!(" got a revocation: {:?} ({:?})",
rev.signature_creation_time().unwrap_or_else(time_zero),
rev.reason_for_revocation()
.map(|r| (r.0, String::from_utf8_lossy(r.1))));
Some(rev)
}
}).collect::<Vec<&Signature>>();
if revs.len() == 0 {
None
} else {
Some(revs)
}
};
if let Some(revs) = check(&self.self_revocations) {
RevocationStatus::Revoked(revs)
} else if let Some(revs) = check(&self.other_revocations) {
RevocationStatus::CouldBe(revs)
} else {
RevocationStatus::NotAsFarAsWeKnow
}
}
pub(crate) fn into_packets<'a>(self) -> impl Iterator<Item=Packet>
where Packet: From<C>
{
let p : Packet = self.component.into();
std::iter::once(p)
.chain(self.self_revocations.into_iter().map(|s| s.into()))
.chain(self.self_signatures.into_iter().map(|s| s.into()))
.chain(self.certifications.into_iter().map(|s| s.into()))
.chain(self.other_revocations.into_iter().map(|s| s.into()))
}
pub(crate) fn sort_and_dedup(&mut self)
{
self.self_signatures.sort_by(sig_cmp);
self.self_signatures.dedup();
self.certifications.sort_by(sig_cmp);
self.certifications.dedup();
self.self_revocations.sort_by(sig_cmp);
self.self_revocations.dedup();
self.other_revocations.sort_by(sig_cmp);
self.other_revocations.dedup();
}
}
impl<P: key::KeyParts, R: key::KeyRole> ComponentBundle<Key<P, R>> {
pub fn key(&self) -> &Key<P, R> {
self.component()
}
pub(crate) fn key_mut(&mut self) -> &mut Key<P, R> {
self.component_mut()
}
}
impl<P: key::KeyParts> ComponentBundle<Key<P, key::SubordinateRole>> {
pub fn revoked<T>(&self, policy: &dyn Policy, t: T)
-> RevocationStatus
where T: Into<Option<time::SystemTime>>
{
let t = t.into();
self._revoked(policy, t, true, self.binding_signature(policy, t).ok())
}
}
impl ComponentBundle<UserID> {
pub fn userid(&self) -> &UserID {
self.component()
}
pub fn revoked<T>(&self, policy: &dyn Policy, t: T)
-> RevocationStatus
where T: Into<Option<time::SystemTime>>
{
let t = t.into();
self._revoked(policy, t, false, self.binding_signature(policy, t).ok())
}
}
impl ComponentBundle<UserAttribute> {
pub fn user_attribute(&self) -> &UserAttribute {
self.component()
}
pub fn revoked<T>(&self, policy: &dyn Policy, t: T)
-> RevocationStatus
where T: Into<Option<time::SystemTime>>
{
let t = t.into();
self._revoked(policy, t, false, self.binding_signature(policy, t).ok())
}
}
impl ComponentBundle<Unknown> {
pub fn unknown(&self) -> &Unknown {
self.component()
}
}