Skip to content

Commit

Permalink
Merge #1483
Browse files Browse the repository at this point in the history
1483: Add support for custom TLS certificate authority bundle r=messense a=messense

Custom TLS CA can be configured via one of the `MATURIN_CA_BUNDLE`, `REQUESTS_CA_BUNDLE` and `CURL_CA_BUNDLE` env vars.

Closes #1418

Co-authored-by: messense <messense@icloud.com>
  • Loading branch information
bors[bot] and messense authored Feb 16, 2023
2 parents 83e6b70 + 57193fc commit 6a16f7f
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 33 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ bytesize = { version = "1.0.1", optional = true }
configparser = { version = "3.0.0", optional = true }
multipart = { version = "0.18.0", features = ["client"], default-features = false, optional = true }
ureq = { version = "2.6.1", features = ["gzip", "socks-proxy"], default-features = false, optional = true }
native-tls-crate = { package = "native-tls", version = "0.2.8", optional = true }
native-tls = { version = "0.2.8", optional = true }
rustls = { version = "0.20.8", optional = true }
rustls-pemfile = { version = "1.0.1", optional = true }
keyring = { version = "1.1.1", optional = true }

[dev-dependencies]
Expand All @@ -105,8 +107,8 @@ upload = ["ureq", "multipart", "configparser", "bytesize", "dialoguer/password"]
# keyring doesn't support *BSD so it's not enabled in `full` by default
password-storage = ["upload", "keyring"]

rustls = ["ureq/tls", "cargo-xwin/rustls-tls"]
native-tls = ["ureq/native-tls", "native-tls-crate", "cargo-xwin/native-tls"]
rustls = ["dep:rustls", "ureq?/tls", "cargo-xwin?/rustls-tls", "dep:rustls-pemfile"]
native-tls = ["dep:native-tls", "ureq?/native-tls", "cargo-xwin?/native-tls", "dep:rustls-pemfile"]

# cross compile using zig or xwin
cross-compile = ["zig", "xwin"]
Expand Down
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Respect `rustflags` settings in cargo configuration file in [#1405](https://github.com/PyO3/maturin/pull/1405)
* Bump MSRV to 1.63.0 in [#1407](https://github.com/PyO3/maturin/pull/1407)
* Add support for uniffi 0.23 in [#1481](https://github.com/PyO3/maturin/pull/1481)
* Add support for custom TLS certificate authority bundle in [#1483](https://github.com/PyO3/maturin/pull/1483)
* Add support for Emscripten in `generate-ci` command in [#1484](https://github.com/PyO3/maturin/pull/1484)
* Add support for linking with pyo3 in abi3 debug mode on Windows in [#1487](https://github.com/PyO3/maturin/pull/1487)

Expand Down
108 changes: 78 additions & 30 deletions src/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use fs_err::File;
use multipart::client::lazy::Multipart;
use regex::Regex;
use std::env;
#[cfg(any(feature = "native-tls", feature = "rustls"))]
use std::ffi::OsString;
use std::io;
use std::path::{Path, PathBuf};
use thiserror::Error;
Expand Down Expand Up @@ -84,7 +86,7 @@ pub enum UploadError {
/// TLS error
#[cfg(feature = "native-tls")]
#[error("TLS Error")]
TlsError(#[source] native_tls_crate::Error),
TlsError(#[source] native_tls::Error),
}

impl From<io::Error> for UploadError {
Expand All @@ -100,8 +102,8 @@ impl From<ureq::Error> for UploadError {
}

#[cfg(feature = "native-tls")]
impl From<native_tls_crate::Error> for UploadError {
fn from(error: native_tls_crate::Error) -> Self {
impl From<native_tls::Error> for UploadError {
fn from(error: native_tls::Error) -> Self {
UploadError::TlsError(error)
}
}
Expand Down Expand Up @@ -262,6 +264,78 @@ fn canonicalize_name(name: &str) -> String {
.to_lowercase()
}

fn http_proxy() -> Result<String, env::VarError> {
env::var("HTTPS_PROXY")
.or_else(|_| env::var("https_proxy"))
.or_else(|_| env::var("HTTP_PROXY"))
.or_else(|_| env::var("http_proxy"))
}

#[cfg(any(feature = "native-tls", feature = "rustls"))]
fn tls_ca_bundle() -> Option<OsString> {
env::var_os("MATURIN_CA_BUNDLE")
.or_else(|| env::var_os("REQUESTS_CA_BUNDLE"))
.or_else(|| env::var_os("CURL_CA_BUNDLE"))
}

// Prefer rustls if both native-tls and rustls features are enabled
#[cfg(all(feature = "native-tls", not(feature = "rustls")))]
#[allow(clippy::result_large_err)]
fn http_agent() -> Result<ureq::Agent, UploadError> {
use std::sync::Arc;

let mut builder = ureq::builder();
if let Ok(proxy) = http_proxy() {
let proxy = ureq::Proxy::new(proxy)?;
builder = builder.proxy(proxy);
};
let mut tls_builder = native_tls::TlsConnector::builder();
if let Some(ca_bundle) = tls_ca_bundle() {
let mut reader = io::BufReader::new(File::open(ca_bundle)?);
for cert in rustls_pemfile::certs(&mut reader)? {
tls_builder.add_root_certificate(native_tls::Certificate::from_pem(&cert)?);
}
}
builder = builder.tls_connector(Arc::new(tls_builder.build()?));
Ok(builder.build())
}

#[cfg(feature = "rustls")]
#[allow(clippy::result_large_err)]
fn http_agent() -> Result<ureq::Agent, UploadError> {
use std::sync::Arc;

let mut builder = ureq::builder();
if let Ok(proxy) = http_proxy() {
let proxy = ureq::Proxy::new(proxy)?;
builder = builder.proxy(proxy);
};
if let Some(ca_bundle) = tls_ca_bundle() {
let mut reader = io::BufReader::new(File::open(ca_bundle)?);
let certs = rustls_pemfile::certs(&mut reader)?;
let mut root_certs = rustls::RootCertStore::empty();
root_certs.add_parsable_certificates(&certs);
let client_config = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_certs)
.with_no_client_auth();
Ok(builder.tls_config(Arc::new(client_config)).build())
} else {
Ok(builder.build())
}
}

#[cfg(not(any(feature = "native-tls", feature = "rustls")))]
#[allow(clippy::result_large_err)]
fn http_agent() -> Result<ureq::Agent, UploadError> {
let mut builder = ureq::builder();
if let Ok(proxy) = http_proxy() {
let proxy = ureq::Proxy::new(proxy)?;
builder = builder.proxy(proxy);
};
Ok(builder.build())
}

/// Uploads a single wheel to the registry
#[allow(clippy::result_large_err)]
pub fn upload(registry: &Registry, wheel_path: &Path) -> Result<(), UploadError> {
Expand Down Expand Up @@ -339,35 +413,9 @@ pub fn upload(registry: &Registry, wheel_path: &Path) -> Result<(), UploadError>

form.add_stream("content", &wheel, Some(wheel_name), None);
let multipart_data = form.prepare().map_err(|e| e.error)?;

let encoded = base64::encode(format!("{}:{}", registry.username, registry.password));

let http_proxy = env::var("HTTPS_PROXY")
.or_else(|_| env::var("https_proxy"))
.or_else(|_| env::var("HTTP_PROXY"))
.or_else(|_| env::var("http_proxy"));

#[cfg(not(feature = "native-tls"))]
let agent = {
let mut builder = ureq::builder();
if let Ok(proxy) = http_proxy {
let proxy = ureq::Proxy::new(proxy)?;
builder = builder.proxy(proxy);
};
builder.build()
};

#[cfg(feature = "native-tls")]
let agent = {
use std::sync::Arc;
let mut builder =
ureq::builder().tls_connector(Arc::new(native_tls_crate::TlsConnector::new()?));
if let Ok(proxy) = http_proxy {
let proxy = ureq::Proxy::new(proxy)?;
builder = builder.proxy(proxy);
};
builder.build()
};
let agent = http_agent()?;

let response = agent
.post(registry.url.as_str())
Expand Down

0 comments on commit 6a16f7f

Please sign in to comment.