mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-23 14:08:43 +00:00
Add opt --root-ceritificates
& env BINSTALL_HTTPS_ROOT_CERTS
(#820)
for specifying root ceritificates used for https connnections. And remove old environment variable `CARGO_HTTP_CAINFO`, `SSL_CERT_FILE` and `SSL_CERT_PATH` to avoid accidentally setting them, especially in CI env. Also: - Rm fn `binstalk_downloader::Certificate::from_env` - Enable feature `env` of dep `clap` in `crates/bin` - Add new dep `file-format` v0.14.0 to `crates/bin` - Use `file-format` to determine pem/der file format when loading root certs - Rm fn `binstalk_downloader::Certificate::open` and enum `binstalk_downloader::OpenCertificateError` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
467ba0d854
commit
7bc4d4a5c6
6 changed files with 67 additions and 62 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -361,6 +361,7 @@ dependencies = [
|
|||
"crates_io_api",
|
||||
"dirs",
|
||||
"embed-resource",
|
||||
"file-format",
|
||||
"fs-lock",
|
||||
"log",
|
||||
"miette",
|
||||
|
@ -727,6 +728,12 @@ dependencies = [
|
|||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "file-format"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d645737d3dda11cbf14905e9b943a1bd578cdcb751709b581a924ea9b9b18b5c"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.20"
|
||||
|
|
|
@ -24,9 +24,10 @@ pkg-fmt = "zip"
|
|||
[dependencies]
|
||||
binstalk = { path = "../binstalk", version = "0.8.0", default-features = false }
|
||||
binstalk-manifests = { path = "../binstalk-manifests", version = "0.3.0" }
|
||||
clap = { version = "4.1.6", features = ["derive"] }
|
||||
clap = { version = "4.1.6", features = ["derive", "env"] }
|
||||
crates_io_api = { version = "0.8.1", default-features = false }
|
||||
dirs = "4.0.0"
|
||||
file-format = { version = "0.14.0", default-features = false }
|
||||
fs-lock = { version = "0.1.0", path = "../fs-lock" }
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
miette = "5.5.0"
|
||||
|
|
|
@ -203,6 +203,11 @@ pub struct Args {
|
|||
#[clap(help_heading = "Options", long, value_enum, value_name = "VERSION")]
|
||||
pub min_tls_version: Option<TLSVersion>,
|
||||
|
||||
/// Specify the root certificates to use for https connnections,
|
||||
/// in addition to default system-wide ones.
|
||||
#[clap(help_heading = "Options", long, env = "BINSTALL_HTTPS_ROOT_CERTS")]
|
||||
pub root_certificates: Vec<PathBuf>,
|
||||
|
||||
/// Print logs in json format to be parsable.
|
||||
#[clap(help_heading = "Options", long)]
|
||||
pub json_output: bool,
|
||||
|
@ -313,7 +318,7 @@ pub fn parse() -> Args {
|
|||
// Filter extraneous arg when invoked by cargo
|
||||
// `cargo run -- --help` gives ["target/debug/cargo-binstall", "--help"]
|
||||
// `cargo binstall --help` gives ["/home/ryan/.cargo/bin/cargo-binstall", "binstall", "--help"]
|
||||
let mut args: Vec<OsString> = std::env::args_os().collect();
|
||||
let mut args: Vec<OsString> = env::args_os().collect();
|
||||
let args = if args.get(1).map(|arg| arg == "binstall").unwrap_or_default() {
|
||||
// Equivalent to
|
||||
//
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::{fs, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use binstalk::{
|
||||
errors::BinstallError,
|
||||
|
@ -17,6 +22,7 @@ use binstalk::{
|
|||
};
|
||||
use binstalk_manifests::cargo_toml_binstall::PkgOverride;
|
||||
use crates_io_api::AsyncClient as CratesIoApiClient;
|
||||
use file_format::FileFormat;
|
||||
use log::LevelFilter;
|
||||
use miette::{miette, Result, WrapErr};
|
||||
use tokio::task::block_in_place;
|
||||
|
@ -77,15 +83,7 @@ pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -
|
|||
args.min_tls_version.map(|v| v.into()),
|
||||
Duration::from_millis(rate_limit.duration.get()),
|
||||
rate_limit.request_count,
|
||||
["CARGO_HTTP_CAINFO", "SSL_CERT_FILE", "SSL_CERT_PATH"]
|
||||
.into_iter()
|
||||
.filter_map(|env_name| match Certificate::from_env(env_name) {
|
||||
Ok(option) => option,
|
||||
Err(err) => {
|
||||
warn!("Failed to load root certificate specified by env {env_name}: {err}",);
|
||||
None
|
||||
}
|
||||
}),
|
||||
read_root_certs(args.root_certificates),
|
||||
)
|
||||
.map_err(BinstallError::from)?;
|
||||
|
||||
|
@ -180,6 +178,49 @@ pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn do_read_root_cert(path: &Path) -> Result<Option<Certificate>, BinstallError> {
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
let mut file = fs::File::open(path)?;
|
||||
let file_format = FileFormat::from_reader(&mut file)?;
|
||||
|
||||
let open_cert = match file_format {
|
||||
FileFormat::PemCertificate => Certificate::from_pem,
|
||||
FileFormat::DerCertificate => Certificate::from_der,
|
||||
_ => {
|
||||
warn!(
|
||||
"Unable to load {}: Expected pem or der ceritificate but found {file_format}",
|
||||
path.display()
|
||||
);
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
// Move file back to its head
|
||||
file.rewind()?;
|
||||
|
||||
let mut buffer = Vec::with_capacity(200);
|
||||
file.read_to_end(&mut buffer)?;
|
||||
|
||||
open_cert(&buffer).map_err(From::from).map(Some)
|
||||
}
|
||||
|
||||
fn read_root_certs(root_certificate_paths: Vec<PathBuf>) -> impl Iterator<Item = Certificate> {
|
||||
root_certificate_paths
|
||||
.into_iter()
|
||||
.filter_map(|path| match do_read_root_cert(&path) {
|
||||
Ok(optional_cert) => optional_cert,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"Failed to load root certificate at {}: {err}",
|
||||
path.display()
|
||||
);
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Return (install_path, manifests, temp_dir)
|
||||
fn compute_paths_and_load_manifests(
|
||||
roots: Option<PathBuf>,
|
||||
|
|
|
@ -23,7 +23,7 @@ mod delay_request;
|
|||
use delay_request::DelayRequest;
|
||||
|
||||
mod certificate;
|
||||
pub use certificate::{Certificate, OpenCertificateError};
|
||||
pub use certificate::Certificate;
|
||||
|
||||
const MAX_RETRY_DURATION: Duration = Duration::from_secs(120);
|
||||
const MAX_RETRY_COUNT: u8 = 3;
|
||||
|
|
|
@ -1,60 +1,11 @@
|
|||
use std::{env, ffi::OsStr, fs, io, path::Path};
|
||||
|
||||
use compact_str::CompactString;
|
||||
use reqwest::tls;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
use super::ReqwestError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum OpenCertificateError {
|
||||
#[error(transparent)]
|
||||
Reqwest(#[from] ReqwestError),
|
||||
|
||||
#[error(transparent)]
|
||||
Io(#[from] io::Error),
|
||||
|
||||
#[error("Expected extension .pem or .der, but found {0:#?}")]
|
||||
UnknownExtensions(Option<CompactString>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Certificate(pub(super) tls::Certificate);
|
||||
|
||||
impl Certificate {
|
||||
/// Open Certificate with path specified by the environment variable `name`
|
||||
pub fn from_env(name: impl AsRef<OsStr>) -> Result<Option<Self>, OpenCertificateError> {
|
||||
Self::from_env_inner(name.as_ref())
|
||||
}
|
||||
|
||||
fn from_env_inner(name: &OsStr) -> Result<Option<Self>, OpenCertificateError> {
|
||||
env::var_os(name)
|
||||
.map(|value| Self::open_inner(Path::new(&value)))
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Open Certificate on disk and automatically detect its format based on
|
||||
/// its extension.
|
||||
pub fn open(path: impl AsRef<Path>) -> Result<Self, OpenCertificateError> {
|
||||
Self::open_inner(path.as_ref())
|
||||
}
|
||||
|
||||
fn open_inner(path: &Path) -> Result<Self, OpenCertificateError> {
|
||||
let ext = path.extension();
|
||||
|
||||
let f = if ext == Some(OsStr::new("pem")) {
|
||||
Self::from_pem
|
||||
} else if ext == Some(OsStr::new("der")) {
|
||||
Self::from_der
|
||||
} else {
|
||||
return Err(OpenCertificateError::UnknownExtensions(
|
||||
ext.map(|os_str| os_str.to_string_lossy().into()),
|
||||
));
|
||||
};
|
||||
|
||||
Ok(f(fs::read(path)?)?)
|
||||
}
|
||||
|
||||
/// Create a Certificate from a binary DER encoded certificate
|
||||
pub fn from_der(der: impl AsRef<[u8]>) -> Result<Self, ReqwestError> {
|
||||
tls::Certificate::from_der(der.as_ref()).map(Self)
|
||||
|
|
Loading…
Add table
Reference in a new issue