use saturating_time::SaturatingTime;
use super::*;
pub trait NetdocUnverified: Sized {
type Body: Sized;
type Signatures: NetdocParseableSignatures;
fn inspect_unverified(&self) -> (&Self::Body, &SignaturesData<Self>);
fn unwrap_unverified(self) -> (Self::Body, SignaturesData<Self>);
fn from_parts(body: Self::Body, signatures: SignaturesData<Self>) -> Self;
}
pub trait HasUnverifiedParsedBody {
type UnverifiedParsedBody: NetdocParseable;
fn unverified_into_inner_unchecked(unverified: Self::UnverifiedParsedBody) -> Self;
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SignaturesData<U: NetdocUnverified> {
pub sigs: U::Signatures,
pub unsigned_body_len: usize,
pub hashes: <U::Signatures as NetdocParseableSignatures>::HashesAccu,
}
pub trait SignatureItemParseable: Sized {
type HashAccu;
fn from_unparsed_and_body(
item: UnparsedItem<'_>,
hash_inputs: &SignatureHashInputs<'_>,
hash: &mut Self::HashAccu,
) -> Result<Self, ErrorProblem>;
}
pub trait NetdocParseableSignatures: Sized {
type HashesAccu: Default + Debug + Clone;
fn is_item_keyword(kw: KeywordRef<'_>) -> bool;
fn from_items<'s>(
input: &mut ItemStream<'s>,
signed_doc_body: SignedDocumentBody<'s>,
sig_hashes: &mut Self::HashesAccu,
stop_at: stop_at!(),
) -> Result<Self, ErrorProblem>;
}
pub trait SignatureHashesAccumulator: Clone {
fn update_from_netdoc_body(
&mut self,
document_body: &SignatureHashInputs<'_>,
) -> Result<(), EP>;
}
#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, amplify::Getters)]
pub struct SignedDocumentBody<'s> {
#[getter(as_copy)]
pub(crate) body: &'s str,
}
#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, amplify::Getters)]
pub struct SignatureHashInputs<'s> {
#[getter(as_copy)]
pub(crate) body: SignedDocumentBody<'s>,
#[getter(skip)]
pub(crate) document_sofar: &'s str,
#[getter(skip)]
pub(crate) signature_item_kw_spc: &'s str,
#[getter(skip)]
pub(crate) signature_item_line: &'s str,
}
impl<'s> SignatureHashInputs<'s> {
pub(crate) fn hash_whole_keyword_line(&self, h: &mut impl Digest) {
h.update(self.body().body());
h.update(self.signature_item_line);
h.update("\n");
}
}
pub mod sig_hashes {
use super::*;
#[derive(Debug, Clone, Default, Deftly)]
#[derive_deftly(AsMutSelf)]
#[allow(clippy::exhaustive_structs)]
pub struct Sha1WholeKeywordLine(pub Option<[u8; 20]>);
impl SignatureHashesAccumulator for Sha1WholeKeywordLine {
fn update_from_netdoc_body(&mut self, body: &SignatureHashInputs<'_>) -> Result<(), EP> {
self.0.get_or_insert_with(|| {
let mut h = tor_llcrypto::d::Sha1::new();
body.hash_whole_keyword_line(&mut h);
h.finalize().into()
});
Ok(())
}
}
}
pub fn check_validity_time(
now: SystemTime,
validity: std::ops::RangeInclusive<SystemTime>,
) -> Result<(), VF> {
if now < *validity.start() {
Err(VF::TooNew)
} else if now > *validity.end() {
Err(VF::TooOld)
} else {
Ok(())
}
}
pub fn check_validity_time_tolerance(
now: SystemTime,
validity: std::ops::RangeInclusive<SystemTime>,
pre_tolerance: Duration,
post_tolerance: Duration,
) -> Result<(), VF> {
let start = *validity.start();
let end = *validity.end();
let validity = start.saturating_sub(pre_tolerance)..=end.saturating_add(post_tolerance);
check_validity_time(now, validity)
}