wreq 6.0.0-rc.29

An ergonomic Rust HTTP Client with TLS fingerprint
use btls::x509::store::{X509Store, X509StoreBuilder};

use super::{Certificate, CertificateInput};
use crate::{Error, Result};

pub fn parse_certs<'c, I>(
    certs: I,
    parser: fn(&'c [u8]) -> crate::Result<Certificate>,
) -> Result<X509Store>
where
    I: IntoIterator,
    I::Item: Into<CertificateInput<'c>>,
{
    let mut store = X509StoreBuilder::new().map_err(Error::tls)?;
    let certs = filter_map_certs(certs, parser);
    process_certs(certs.into_iter(), &mut store)?;
    Ok(store.build())
}

pub fn parse_certs_with_stack<C, F>(certs: C, parse: F) -> Result<X509Store>
where
    C: AsRef<[u8]>,
    F: Fn(C) -> Result<Vec<Certificate>>,
{
    let mut store = X509StoreBuilder::new().map_err(Error::tls)?;
    let certs = parse(certs)?;
    process_certs(certs.into_iter(), &mut store)?;
    Ok(store.build())
}

pub fn process_certs<I>(iter: I, store: &mut X509StoreBuilder) -> Result<()>
where
    I: Iterator<Item = Certificate>,
{
    let mut valid_count = 0;
    let mut invalid_count = 0;
    for cert in iter {
        if let Err(_err) = store.add_cert(cert.0) {
            invalid_count += 1;
            warn!("tls failed to parse certificate: {:?}", _err);
        } else {
            valid_count += 1;
        }
    }

    if valid_count == 0 && invalid_count > 0 {
        return Err(Error::builder("invalid certificate"));
    }

    Ok(())
}

pub fn filter_map_certs<'c, I>(
    certs: I,
    parser: fn(&'c [u8]) -> Result<Certificate>,
) -> impl Iterator<Item = Certificate>
where
    I: IntoIterator,
    I::Item: Into<CertificateInput<'c>>,
{
    certs
        .into_iter()
        .map(Into::into)
        .filter_map(move |data| match data.with_parser(parser) {
            Ok(cert) => Some(cert),
            Err(_err) => {
                warn!("tls failed to parse certificate: {:?}", _err);
                None
            }
        })
}