use reqwest::Client;
use crate::registry::{AnyRegistry, Registry};
pub trait RegistryState: Send + Sync {
type Registry: Registry + Send + Sync;
fn registry(&self) -> &Self::Registry;
fn upstream_api(&self) -> &str;
fn proxy_base_url(&self) -> &str;
fn client(&self) -> &Client;
}
#[derive(Clone)]
pub struct GenericProxyState {
client: Client,
proxy_base_url: String,
upstream_api: String,
registry: AnyRegistry,
}
impl GenericProxyState {
pub fn new(
proxy_base_url: String,
upstream_api: String,
registry: impl Registry + 'static,
) -> Self {
Self {
client: Client::builder()
.user_agent("cargo-overlay-registry/0.1.0")
.build()
.expect("Failed to create HTTP client"),
proxy_base_url,
upstream_api,
registry: AnyRegistry::new(registry),
}
}
}
impl RegistryState for GenericProxyState {
type Registry = AnyRegistry;
fn registry(&self) -> &Self::Registry {
&self.registry
}
fn upstream_api(&self) -> &str {
&self.upstream_api
}
fn proxy_base_url(&self) -> &str {
&self.proxy_base_url
}
fn client(&self) -> &Client {
&self.client
}
}
pub struct MitmCa {
ca_cert_pem: Vec<u8>,
ca_key_pair: rcgen::KeyPair,
ca_cert: rcgen::Certificate,
}
impl MitmCa {
pub fn new() -> Result<Self, rcgen::Error> {
use rcgen::{BasicConstraints, CertificateParams, DnType, IsCa, KeyPair, KeyUsagePurpose};
let mut params = CertificateParams::default();
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign];
params
.distinguished_name
.push(DnType::CommonName, "Cargo Overlay Registry CA");
params
.distinguished_name
.push(DnType::OrganizationName, "Cargo Overlay Registry");
let key_pair = KeyPair::generate()?;
let ca_cert = params.self_signed(&key_pair)?;
let ca_cert_pem = ca_cert.pem().into_bytes();
Ok(Self {
ca_cert_pem,
ca_key_pair: key_pair,
ca_cert,
})
}
pub fn ca_cert_pem(&self) -> &[u8] {
&self.ca_cert_pem
}
pub fn sign_domain_cert(&self, domain: &str) -> Result<(Vec<u8>, Vec<u8>), rcgen::Error> {
use rcgen::{CertificateParams, DnType, KeyPair, SanType};
let mut params = CertificateParams::default();
params.distinguished_name.push(DnType::CommonName, domain);
params.subject_alt_names = vec![SanType::DnsName(
domain
.try_into()
.map_err(|_| rcgen::Error::CouldNotParseCertificate)?,
)];
if !domain.starts_with("*.")
&& let Ok(wildcard) = format!("*.{}", domain).try_into()
{
params.subject_alt_names.push(SanType::DnsName(wildcard));
}
let key_pair = KeyPair::generate()?;
let cert = params.signed_by(&key_pair, &self.ca_cert, &self.ca_key_pair)?;
let cert_pem = cert.pem().into_bytes();
let key_pem = key_pair.serialize_pem().into_bytes();
Ok((cert_pem, key_pem))
}
}