//! A certificate store abstraction.
//!
//! A [`Network`] accesses certificates via the [`Store`] interface.
//!
//! [`Network`]: crate::Network
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::sync::Arc;
use std::time::SystemTime;

use sequoia_openpgp as openpgp;

use openpgp::Fingerprint;
use openpgp::KeyHandle;
use openpgp::KeyID;
use openpgp::Result;
use openpgp::cert::prelude::*;
use openpgp::packet::Signature;
use openpgp::packet::UserID;

pub use sequoia_cert_store::store::StoreError;

use crate::CertificationSet;
use crate::CertSynopsis;
use crate::Certification;
use crate::Depth;

use crate::TRACE;

mod cert_store;
pub use cert_store::{CertStore, MaybeOwnedPolicy};
mod synopses;
pub use synopses::SynopsisSlice;

/// Returns certificates from a backing store.
pub trait Backend<'a>: sequoia_cert_store::Store<'a> {
    /// Returns all certifications on a certificate.
    ///
    /// `target`'s policy and reference time is used to determine what
    /// certificates are valid.  Only active valid certifications are
    /// returned.  (A certification is active if it is the newest
    /// valid certification of a particular binding as of the
    /// reference time.)
    ///
    /// Example:
    ///
    /// ```text
    /// 0xA certifies <Carol, 0xC>.    \ CertificationSet
    /// 0xA certifies <Caroline, 0xC>. /
    /// 0xB certifies <Carol, 0xC>.    > CertificationSet
    /// ```
    ///
    /// The entry for 0xC has two `CertificationSet`s: one for those
    /// made by 0xA and one for those made by 0xB.
    ///
    /// An implementation may (but need not) use the `min_depth`
    /// parameter to filter the the certifications it returns.  The
    /// `min_depth` parameter says that the caller is only interested
    /// in certifications for which the trust depth is at least
    /// `min_depth`.  If an implementation returns certifications
    /// whose trust depth is less than `min_depth` the caller must
    /// ignore them.
    fn redges(&self, target: ValidCert, min_depth: Depth) -> Arc<Vec<CertificationSet>>
    {
        tracer!(TRACE, "Backend::redges");
        t!("({}, {}; {})",
           target.fingerprint(),
           target.primary_userid()
               .map(|ua| String::from_utf8_lossy(ua.userid().value()))
               .unwrap_or("<unknown>".into()),
           min_depth);

        let reference_time = target.time();

        // certifications is all of the certifications for a given
        // <Cert, User ID>.  Returns the active certification, if any,
        // and any issuers that should be retried with a min_depth of 0.
        let get_active = |ua: &UserIDAmalgamation,
                          certifications: &[&Signature],
                          min_depth: Depth,
                          // If some, only return certifications by these
                          // issuers.
                          filter: Option<BTreeSet<KeyID>>|
            -> (Vec<Certification>, BTreeSet<KeyID>)
        {
            t!("Looking for active signatures: min depth: {}", min_depth);

            let mut valid_certifications: Vec<Certification> = Vec::new();

            // If we've already seen a valid certification from the
            // Issuer on the current <Cert, UserID> binding.
            let mut seen: BTreeMap<Fingerprint, std::time::SystemTime>
                = BTreeMap::new();

            // If we skipped a certification due to the min_depth
            // constraint, and then find another certification that
            // does pass the constraint, we need to recheck the first
            // one, as it would be preferred.  We do this in a second
            // pass.
            let mut skipped: BTreeSet<KeyID> = BTreeSet::new();
            let mut retry: BTreeSet<KeyID> = BTreeSet::new();

            'cert: for certification in certifications {
                // Check that the certification is valid:
                //
                //   - Find the issuer.
                //   - Verify the signature.
                //
                // If we don't have a certificate for the alleged issuer,
                // then we ignore the certification.

                let certification_time =
                    if let Some(t) = certification.signature_creation_time() {
                        t
                    } else {
                        continue;
                    };

                let mut alleged_issuers = certification.get_issuers();

                // Dedup the issuers as follows: if we have a
                // fingerprint, and its key ID, looking it up by key
                // ID will return the certificate.  So there is no
                // need to look it up once by key ID and once by
                // fingerprint.
                if alleged_issuers.iter()
                           .any(|i| {
                               matches!(i, KeyHandle::Fingerprint(_))
                           })
                    && alleged_issuers.iter()
                           .any(|i| {
                               matches!(i, KeyHandle::KeyID(_))
                           })
                {
                    t!("Dedupping {} alleged issuers: {}",
                       alleged_issuers.len(),
                       alleged_issuers
                           .iter()
                           .map(|i| format!("{}", i))
                           .collect::<Vec<_>>()
                           .join(", "));

                    // Collect the key ids.
                    let mut keyids = Vec::with_capacity(
                        alleged_issuers.len() - 1);
                    for issuer in alleged_issuers.iter() {
                        if let KeyHandle::KeyID(keyid) = issuer {
                            keyids.push(keyid.clone())
                        }
                    }

                    // Get a list of fingerprints that are aliased.
                    let mut kill = Vec::with_capacity(
                        alleged_issuers.len() - keyids.len());
                    for (i, issuer) in alleged_issuers.iter().enumerate() {
                        if let KeyHandle::Fingerprint(fingerprint) = issuer {
                            if keyids.contains(&KeyID::from(fingerprint)) {
                                kill.push(i);
                            }
                        }
                    }

                    // Remove the aliased fingerprints.
                    for i in kill.into_iter().rev() {
                        alleged_issuers.swap_remove(i);
                    }

                    t!("Have {} alleged issuers after dedupping: {}",
                       alleged_issuers.len(),
                       alleged_issuers
                           .iter()
                           .map(|i| format!("{}", i))
                           .collect::<Vec<_>>()
                           .join(", "));
                }

                if min_depth > 0.into() {
                    let depth = certification.trust_signature()
                        .map(|(depth, _amount)| depth)
                        .unwrap_or(0);

                    if Depth::from(depth as usize) < min_depth {
                        for alleged_issuer in alleged_issuers {
                            let keyid = KeyID::from(alleged_issuer);

                            t!("Skipping {} for {:02X}{:02X} as depth \
                                of {} is less than the minimum {}",
                               keyid,
                               certification.digest_prefix()[0],
                               certification.digest_prefix()[1],
                               depth, min_depth);

                            skipped.insert(keyid);
                        }
                        continue;
                    } else {
                        // It's okay.
                        t!("Checking {:02X}{:02X} as depth \
                            of {} is at least the minimum of {}",
                           certification.digest_prefix()[0],
                           certification.digest_prefix()[1],
                           depth, min_depth);
                    }
                }

                // Improve tracing: distinguish between we don't have
                // the issuer's certificate and we have it, but the
                // signature is invalid.
                let mut invalid_sig: Option<(KeyHandle, _)> = None;
                for alleged_issuer in alleged_issuers.into_iter() {
                    let alleged_issuer_keyid = KeyID::from(&alleged_issuer);

                    if skipped.get(&alleged_issuer_keyid).is_some() {
                        // We skipped a newer certification (due to
                        // the min_depth filter) so even if this older
                        // one is valid, it might not be active.  Add
                        // this to the `retry` list so that we try
                        // this issuer again without the depth filter.
                        t!("Skipped possible certification from {}, \
                            queuing to retry with no depth constraints",
                           alleged_issuer_keyid);

                        retry.insert(alleged_issuer_keyid);
                        continue;
                    }

                    if let Some(ref filter) = filter {
                        // Are we interested in certifications from
                        // this certificate?
                        if ! filter.get(&alleged_issuer_keyid).is_some() {
                            continue;
                        } else {
                            t!("Reconsidering certification {:02X}{:02X}, \
                                which is possibly from {}",
                               certification.digest_prefix()[0],
                               certification.digest_prefix()[1],
                               alleged_issuer_keyid);
                        }
                    }

                    match self.lookup_by_cert_or_subkey(&alleged_issuer) {
                        Ok(alleged_issuers) => {
                            for alleged_issuer in alleged_issuers.into_iter() {

                                let alleged_issuer_fpr
                                    = alleged_issuer.fingerprint();
                                if let Some(saw) = seen.get(&alleged_issuer_fpr)
                                {
                                    if saw > &certification_time {
                                        // We already have a newer
                                        // certification from this
                                        // issuer.
                                        t!("Skipping certification \
                                            by {} for <{:?}, {}> at {:?}: \
                                            saw a newer one.",
                                           alleged_issuer_fpr,
                                           ua.userid(), target.keyid(),
                                           certification_time);
                                        continue;
                                    }
                                }


                                let alleged_issuer = match alleged_issuer
                                    .with_policy(target.policy(), reference_time)
                                {
                                    Ok(c) => c,
                                    Err(err) => {
                                        t!("Ignoring possible certification \
                                            by {}: {}",
                                           alleged_issuer_fpr, err);
                                        continue;
                                    }
                                };

                                let r = Certification::try_from_signature(
                                    &alleged_issuer, Some(ua), &target,
                                    certification);
                                match r {
                                    Ok(c) => {
                                        t!("Using certification {:02X}{:02X} \
                                            by {} for <{:?}, {}> at {:?}: \
                                            {}/{}.",
                                           certification.digest_prefix()[0],
                                           certification.digest_prefix()[1],
                                           alleged_issuer_fpr,
                                           ua.userid(), target.keyid(),
                                           c.creation_time(),
                                           c.depth(),
                                           c.amount());

                                        valid_certifications.push(c);
                                        seen.insert(alleged_issuer_fpr,
                                                    certification_time);

                                        continue 'cert;
                                    }
                                    Err(err) => {
                                        invalid_sig = Some(
                                            (alleged_issuer_fpr.into(), err));
                                    }
                                }
                            }
                        }
                        Err(err) => {
                            invalid_sig = Some((alleged_issuer, err));
                        }
                    }
                }

                if let Some((keyid, err)) = invalid_sig {
                    t!("Invalid certification {:02X}{:02X} \
                        by {} for <{:?}, {}>: {}",
                       certification.digest_prefix()[0],
                       certification.digest_prefix()[1],
                       keyid, ua.userid(), target.keyid(),
                       err);
                } else {
                    t!("Certification {:02X}{:02X} for <{:?}, {}>: \
                        missing issuer's certificate ({}).",
                       certification.digest_prefix()[0],
                       certification.digest_prefix()[1],
                       ua.userid(), target.keyid(),
                       certification.get_issuers()
                           .first()
                           .map(|h| h.to_string())
                           .unwrap_or("(no issuer subkeys)".into())
                    );
                }
            }

            (valid_certifications, retry)
        };

        let mut valid_certifications = Vec::new();
        // Be careful: we expect a valid certificate, but the User IDs
        // don't require a self signature.
        for ua in target.cert().userids() {
            // Skip invalid User IDs.
            if let Err(_) = std::str::from_utf8(ua.userid().value()) {
                t!("{}: Non-UTF-8 User ID ({:?}) skipped.",
                   target.keyid(),
                   String::from_utf8_lossy(ua.userid().value()));
                continue;
            }

            // We iterate over all of the certifications.  We need to
            // be careful: we only want the newest certification for a
            // given <Issuer, <Cert, UserID>> tuple.

            let mut certifications: Vec<_> = ua.certifications()
                // Filter out certifications made after the reference time.
                .filter(|c| {
                    if let Some(ct) = c.signature_creation_time() {
                        ct <= reference_time
                    } else {
                        false
                    }
                })
                .collect();
            t!("<{}, {}>: {} third-party certifications",
               target.fingerprint(),
               String::from_utf8_lossy(ua.userid().value()),
               certifications.len());

            // Sort the certifications so that the newest comes first.
            certifications.sort_by(|a, b| {
                a.signature_creation_time().cmp(&b.signature_creation_time())
                    .reverse()
            });

            let (c, retry) = get_active(&ua, &certifications, min_depth, None);
            valid_certifications.extend(c);

            if ! retry.is_empty() {
                assert!(min_depth > 0.into());
                t!("Retrying: depth filter excludes some, but not all \
                    certifications for: {}",
                   retry.iter()
                       .map(|k| k.to_hex())
                       .collect::<Vec<String>>()
                       .join(", "));

                let (c, retry) = get_active(
                    &ua, &certifications, Depth::from(0), Some(retry));
                valid_certifications.extend(c);

                assert!(retry.is_empty());
            }
        }

        t!("Merging certifications.");

        Arc::new(CertificationSet::from_certifications(
            valid_certifications, reference_time))
    }

    /// Prefills the cache.
    ///
    /// Prefilling the cache makes sense when you plan to examine most
    /// nodes and edges in the network.  It doesn't make sense if you
    /// are just authenticating a single or a few bindings.
    ///
    /// This function may be multi-threaded.
    ///
    /// Errors should be silently ignored and propagated when the
    /// operation in question is executed directly.
    fn precompute(&self) {
        self.prefetch_all()
    }
}

impl<'a: 't, 't, T> Backend<'a> for Box<T>
where T: Backend<'a> + ?Sized + 't
{
    fn redges(&self, target: ValidCert, min_depth: Depth)
        -> Arc<Vec<CertificationSet>>
    {
        self.as_ref().redges(target, min_depth)
    }

    fn precompute(&self) {
        self.as_ref().precompute()
    }
}

impl<'a: 't, 't, T> Backend<'a> for &'t T
where T: Backend<'a> + ?Sized
{
    fn redges(&self, target: ValidCert, min_depth: Depth)
        -> Arc<Vec<CertificationSet>>
    {
        (*self).redges(target, min_depth)
    }

    fn precompute(&self) {
        (*self).precompute()
    }
}

impl<'a> Backend<'a> for sequoia_cert_store::CertStore<'a>
{
}

pub trait Store {
    /// Returns the reference time.
    fn reference_time(&self) -> SystemTime;

    /// Lists all of the certificates.
    fn iter_fingerprints<'a>(&'a self) -> Box<dyn Iterator<Item=Fingerprint> + 'a>;

    /// Returns all of the certificates.
    fn synopses<'a>(&'a self) -> Box<dyn Iterator<Item=CertSynopsis> + 'a> {
        Box::new(self.iter_fingerprints()
            .filter_map(|fpr| {
                self.lookup_synopsis_by_fpr(&fpr).ok()
            }))
    }

    /// Returns the certificates matching the handle.
    ///
    /// Returns [`StoreError::NotFound`] if the certificate is not
    /// found.  This function SHOULD NOT return an empty vector if the
    /// certificate is not found.
    ///
    /// The caller may assume that looking up a fingerprint returns at
    /// most one certificate.
    fn lookup_synopses(&self, kh: &KeyHandle) -> Result<Vec<CertSynopsis>>;

    /// Returns the corresponding certificate, if any.
    ///
    /// Returns [`StoreError::NotFound`] if the certificate is not
    /// found.  This function SHOULD NOT return an empty vector if the
    /// certificate is not found.
    fn lookup_synopsis_by_fpr(&self, fingerprint: &Fingerprint)
        -> Result<CertSynopsis>
    {
        let kh = KeyHandle::from(fingerprint.clone());
        self.lookup_synopses(&kh)
            .and_then(|v| {
                assert!(v.len() <= 1);
                v.into_iter().next()
                    .ok_or(StoreError::NotFound(kh).into())
            })
    }

    /// Returns a certification set for the specified certificate.
    ///
    /// A `CertificateSet` is returned for the certificate itself as
    /// well as for each User ID (self signed or not) that has a
    /// cryptographically valid certification.
    ///
    /// Returns [`StoreError::NotFound`] if the certificate is not
    /// found.  This function SHOULD NOT return an empty vector if the
    /// certificate is not found.
    ///
    /// An implementation may (but need not) use the `min_depth`
    /// parameter to filter the the certifications it returns.  The
    /// `min_depth` parameter says that the caller is only interested
    /// in certifications for which the trust depth is at least
    /// `min_depth`.  If an implementation returns certifications
    /// whose trust depth is less than `min_depth` the caller must
    /// ignore them.
    fn certifications_of(&self, target: &Fingerprint, min_depth: Depth)
        -> Result<Arc<Vec<CertificationSet>>>;

    /// Returns all third-party certifications of the specified
    /// certificate.
    fn third_party_certifications_of(&self, fpr: &Fingerprint)
        -> Vec<Certification>
    {
        self.certifications_of(fpr, 0.into())
            .unwrap_or(Arc::new(Vec::new()))
            .iter()
            .flat_map(|cs| {
                cs.certifications()
                    .flat_map(|(_userid, certifications)| {
                        certifications.iter().cloned()
                    })
            })
            .collect::<Vec<_>>()
    }

    /// Returns all User IDs that were certified for the specified
    /// certificate.
    ///
    /// This returns both self-signed User IDs, and User IDs certified
    /// by third-parties for the specified certificate.  The result is
    /// deduped.
    fn certified_userids_of(&self, fpr: &Fingerprint)
        -> Vec<UserID>
    {
        if let Ok(cert) = self.lookup_synopsis_by_fpr(fpr) {
            let mut userids: Vec<UserID> = self
                .third_party_certifications_of(&cert.fingerprint())
                .into_iter()
                .filter_map(|c| c.userid().map(Clone::clone))
                .chain(cert.userids().map(|u| u.userid().clone()))
                .collect();
            userids.sort_unstable();
            userids.dedup();
            userids
        } else {
            Vec::new()
        }
    }

    /// Returns all User IDs that were certified.
    ///
    /// This returns both self-signed User IDs, and User IDs certified
    /// by third-parties.  The result is deduped.
    fn certified_userids(&self)
        -> Vec<(Fingerprint, UserID)>
    {
        let mut userids = self.synopses().flat_map(|cert| {
            let fpr = cert.fingerprint();

            let userids = cert.userids().map(|u| {
                (fpr.clone(), u.userid().clone())
            }).collect::<Vec<(Fingerprint, UserID)>>();

            self
                .third_party_certifications_of(&fpr)
                .into_iter()
                .filter_map(move |c| {
                    c.userid().map(|u| (fpr.clone(), u.clone()))
                })
                .chain(userids)
        }).collect::<Vec<(Fingerprint, UserID)>>();

        userids.sort_unstable();
        userids.dedup();
        userids
    }

    /// Returns all certificates that may have the specified User ID.
    ///
    /// This returns both self-signed User IDs, and User IDs certified
    /// by third-parties.  It is okay for this function to return
    /// false positives, i.e., certificates that on closer inspection
    /// shouldn't be associated with that User ID.
    fn lookup_synopses_by_userid(&self, userid: UserID) -> Vec<Fingerprint> {
        self.certified_userids()
            .into_iter()
            .filter_map(|(fpr, u)| {
                if u == userid {
                    Some(fpr)
                } else {
                    None
                }
            })
            .collect()
    }

    /// Returns all certificates that may have a User ID with the
    /// specified email address.
    ///
    /// This returns both self-signed User IDs, and User IDs certified
    /// by third-parties.  It is okay for this function to return
    /// false positives, i.e., certificates that on closer inspection
    /// shouldn't be associated with that User ID.
    fn lookup_synopses_by_email(&self, email: &str) -> Vec<(Fingerprint, UserID)> {
        let userid_check = UserID::from(format!("<{}>", email));
        if let Ok(Some(email_check)) = userid_check.email() {
            if email != email_check {
                // Does not appear to be an email address.
                return Vec::new();
            }
        } else {
            // Does not appear to be an email address.
            return Vec::new();
        }
        let email_normalized = userid_check.email_normalized()
            .expect("checked").expect("checked");

        self.certified_userids()
            .into_iter()
            .filter_map(|(fpr, u)| {
                if let Ok(Some(e)) = u.email_normalized() {
                    if e == email_normalized {
                        return Some((fpr, u));
                    }
                }
                None
            })
            .collect()
    }
}

impl<'t, T> Store for Box<T>
where T: Store + ?Sized + 't
{
    /// Returns the reference time.
    fn reference_time(&self) -> SystemTime {
        self.as_ref().reference_time()
    }

    /// Lists all of the certificates.
    fn iter_fingerprints<'b>(&'b self) -> Box<dyn Iterator<Item=Fingerprint> + 'b> {
        self.as_ref().iter_fingerprints()
    }

    /// Returns all of the certificates.
    fn synopses<'b>(&'b self) -> Box<dyn Iterator<Item=CertSynopsis> + 'b> {
        self.as_ref().synopses()
    }

    fn lookup_synopses(&self, kh: &KeyHandle) -> Result<Vec<CertSynopsis>> {
        self.as_ref().lookup_synopses(kh)
    }

    fn lookup_synopsis_by_fpr(&self, fingerprint: &Fingerprint)
        -> Result<CertSynopsis>
    {
        self.as_ref().lookup_synopsis_by_fpr(fingerprint)
    }

    fn certifications_of(&self, target: &Fingerprint, min_depth: Depth)
        -> Result<Arc<Vec<CertificationSet>>>
    {
        self.as_ref().certifications_of(target, min_depth)
    }

    fn third_party_certifications_of(&self, fpr: &Fingerprint)
        -> Vec<Certification>
    {
        self.as_ref().third_party_certifications_of(fpr)
    }

    fn certified_userids_of(&self, fpr: &Fingerprint)
        -> Vec<UserID>
    {
        self.as_ref().certified_userids_of(fpr)
    }

    fn certified_userids(&self)
        -> Vec<(Fingerprint, UserID)>
    {
        self.as_ref().certified_userids()
    }

    fn lookup_synopses_by_userid(&self, userid: UserID) -> Vec<Fingerprint> {
        self.as_ref().lookup_synopses_by_userid(userid)
    }

    fn lookup_synopses_by_email(&self, email: &str) -> Vec<(Fingerprint, UserID)> {
        self.as_ref().lookup_synopses_by_email(email)
    }
}

impl<'t, T> Store for &'t T
where T: Store + ?Sized
{
    /// Returns the reference time.
    fn reference_time(&self) -> SystemTime {
        (*self).reference_time()
    }

    /// Lists all of the certificates.
    fn iter_fingerprints<'b>(&'b self) -> Box<dyn Iterator<Item=Fingerprint> + 'b> {
        (*self).iter_fingerprints()
    }

    /// Returns all of the certificates.
    fn synopses<'b>(&'b self) -> Box<dyn Iterator<Item=CertSynopsis> + 'b> {
        (*self).synopses()
    }

    fn lookup_synopses(&self, kh: &KeyHandle) -> Result<Vec<CertSynopsis>> {
        (*self).lookup_synopses(kh)
    }

    fn lookup_synopsis_by_fpr(&self, fingerprint: &Fingerprint)
        -> Result<CertSynopsis>
    {
        (*self).lookup_synopsis_by_fpr(fingerprint)
    }

    fn certifications_of(&self, target: &Fingerprint, min_depth: Depth)
        -> Result<Arc<Vec<CertificationSet>>>
    {
        (*self).certifications_of(target, min_depth)
    }

    fn third_party_certifications_of(&self, fpr: &Fingerprint)
        -> Vec<Certification>
    {
        (*self).third_party_certifications_of(fpr)
    }

    fn certified_userids_of(&self, fpr: &Fingerprint)
        -> Vec<UserID>
    {
        (*self).certified_userids_of(fpr)
    }

    fn certified_userids(&self)
        -> Vec<(Fingerprint, UserID)>
    {
        (*self).certified_userids()
    }

    fn lookup_synopses_by_userid(&self, userid: UserID) -> Vec<Fingerprint> {
        (*self).lookup_synopses_by_userid(userid)
    }

    fn lookup_synopses_by_email(&self, email: &str) -> Vec<(Fingerprint, UserID)> {
        (*self).lookup_synopses_by_email(email)
    }
}

/// A workaround to create a `Box<dyn Store + Backend>`.
///
/// We can't directly do: `Box<dyn Store + Backend>`.  That only works
/// for auto traits like `Send` and `Sync`.  Instead we need to use a
/// special trait that depends on all of the traits that we care
/// about.
pub trait StorePlusBackend<'a>: Store + Backend<'a> {
}

impl<'a, T> StorePlusBackend<'a> for T
where T: Store + Backend<'a>
{
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::time::Duration;
    use std::time::UNIX_EPOCH;

    use sequoia_openpgp as openpgp;

    use openpgp::cert::raw::RawCert;
    use openpgp::cert::raw::RawCertParser;
    use openpgp::parse::Parse;
    use openpgp::policy::StandardPolicy;

    use crate::Network;
    use crate::NetworkBuilder;

    #[test]
    #[allow(unused)]
    fn override_certification() -> Result<()> {
        tracer!(true, "override_certification");

        let p = &StandardPolicy::new();

        let alice_fpr: Fingerprint =
            "B4259E0C1D764615CA560EE57E10F6E7AC1D0A4E"
           .parse().expect("valid fingerprint");
        let alice_uid
            = UserID::from("<alice@example.org>");

        let bob_fpr: Fingerprint =
            "3E2CBBFE672E101E0061D55C60FCD2B055FFB4A2"
           .parse().expect("valid fingerprint");
        let bob_uid
            = UserID::from("<bob@example.org>");
        // Certified by: B4259E0C1D764615CA560EE57E10F6E7AC1D0A4E
        // Certified by: B4259E0C1D764615CA560EE57E10F6E7AC1D0A4E

        let carol_fpr: Fingerprint =
            "2C6CA00307C776386646C76757CCD98BEB17EA38"
           .parse().expect("valid fingerprint");
        let carol_uid
            = UserID::from("<carol@example.org>");
        // Certified by: 3E2CBBFE672E101E0061D55C60FCD2B055FFB4A2

        let bytes = &crate::testdata::data("override.pgp");
        let certs = RawCertParser::from_bytes(bytes)?;
        let certs: Vec<RawCert> = certs
            .map(|c| c.expect("Valid certificate"))
            .collect();

        // date '+%s' -u -d '2023-01-14 01:00:00'
        let jan14 = UNIX_EPOCH + Duration::new(1673658000, 0);
        // date '+%s' -u -d '2023-01-16 01:00:00'
        let jan16 = UNIX_EPOCH + Duration::new(1673830800, 0);

        // Alice certified Bob twice.  Once on the 14th as a trusted
        // introducer, and once on the 15 using a normal
        // certification.

        // On the 14th, Bob should be a trusted introducer.
        t!("Jan 14, Bob");
        let n = Network::from_raw_certs(certs.iter().cloned(), p, Some(jan14),
                                        &[ alice_fpr.clone() ])?;
        let got = n.authenticate(bob_uid.clone(),
                                 bob_fpr.clone(),
                                 120);
        assert!(got.amount() == 120);

        t!("Jan 14, Carol");
        let n = Network::from_raw_certs(certs.iter().cloned(), p, Some(jan14),
                                        &[ alice_fpr.clone() ])?;
        let got = n.authenticate(carol_uid.clone(),
                                 carol_fpr.clone(),
                                 120);
        assert!(got.amount() == 120);


        // On the 16th, Bob should be a trusted introducer.
        t!("Jan 16, Bob");
        let n = Network::from_raw_certs(certs.iter().cloned(), p, jan16,
                                        &[ alice_fpr.clone() ])?;

        let got = n.authenticate(bob_uid.clone(),
                                 bob_fpr.clone(),
                                 120);
        assert!(got.amount() == 120);

        t!("Jan 16, Carol");
        let n = Network::from_raw_certs(certs.iter().cloned(), p, jan16,
                                        &[ alice_fpr.clone() ])?;
        let got = n.authenticate(carol_uid.clone(),
                                 carol_fpr.clone(),
                                 120);
        assert!(got.amount() == 0);

        eprintln!("{:?}", n);

        Ok(())
    }

    // Make sure we can pass a &Box<Backend> where a generic type
    // needs to implement Backend.
    #[test]
    fn backend_boxed() -> Result<()> {
        use crate::store::CertStore;

        let policy = StandardPolicy::new();

        struct Foo<'a, B>
        where B: Backend<'a>
        {
            backend: B,
            _a: std::marker::PhantomData<&'a ()>,
        }

        impl<'a, B> Foo<'a, B>
        where B: Backend<'a>
        {
            fn new(backend: B) -> Self
            {
                Foo {
                    backend,
                    _a: std::marker::PhantomData,
                }
            }

            fn count(&self) -> usize {
                self.backend.fingerprints().count()
            }
        }

        let backend = CertStore::from_certs(std::iter::empty(), &policy, None)?;
        let backend: Box<dyn Backend> = Box::new(backend);
        let foo = Foo::new(&backend);

        // Do something (anything) with the backend.
        assert_eq!(foo.count(), 0);

        Ok(())
    }

    // Make sure we can pass a &Box<Store> where a generic type
    // needs to implement Store.
    #[test]
    fn store_boxed() -> Result<()> {
        use crate::store::SynopsisSlice;

        struct Foo<S>
        where S: Store
        {
            backend: S,
        }

        impl<S> Foo<S>
        where S: Store
        {
            fn new(backend: S) -> Self
            {
                Foo {
                    backend,
                }
            }

            fn count(&self) -> usize {
                self.backend.iter_fingerprints().count()
            }
        }

        let backend = SynopsisSlice::new(&[], &[], std::time::SystemTime::now())?;
        let backend: Box<dyn Store> = Box::new(backend);
        let foo = Foo::new(&backend);

        // Do something (anything) with the backend.
        assert_eq!(foo.count(), 0);

        let _n = NetworkBuilder::rootless(backend).build();

        Ok(())
    }

    // Make sure we can pass a &Box<Store> where a generic type
    // needs to implement Store.
    #[test]
    fn store_backend_boxed() -> Result<()> {
        use crate::store::CertStore;

        let policy = StandardPolicy::new();

        struct Foo<'a, B>
        where B: StorePlusBackend<'a>
        {
            backend: B,
            _a: std::marker::PhantomData<&'a ()>,
        }

        impl<'a, B> Foo<'a, B>
        where B: StorePlusBackend<'a>
        {
            fn new(backend: B) -> Self
            {
                Foo {
                    backend,
                    _a: std::marker::PhantomData,
                }
            }

            fn count(&self) -> usize {
                self.backend.fingerprints().count()
            }

            fn count_synopses(&self) -> usize {
                self.backend.iter_fingerprints().count()
            }
        }

        let backend = CertStore::from_certs(std::iter::empty(), &policy, None)?;
        let backend: Box<dyn StorePlusBackend> = Box::new(backend);
        let foo = Foo::new(&backend);

        // Do something (anything) with the backend.
        assert_eq!(foo.count(), 0);
        assert_eq!(foo.count_synopses(), 0);

        let n = NetworkBuilder::rootless(backend)
            .certification_network()
            .build();

        // Do something with n (anything).
        eprintln!("{:?}",
                  n.authenticate(
                      UserID::from("<alice@example.org>"),
                      "0123 4567 89AB CDEF 0123 4567 89AB CDEF"
                          .parse::<Fingerprint>().expect("valid"),
                      crate::FULLY_TRUSTED));

        Ok(())
    }
}
