Merge pull request #189 from NobodyXu/feature/https-only-mode

Feature: Support https only mode and min tls version
This commit is contained in:
Félix Saparelli 2022-06-23 21:23:08 +12:00 committed by GitHub
commit f25f6d2ce7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 5 deletions

1
Cargo.lock generated
View file

@ -145,6 +145,7 @@ dependencies = [
"guess_host_triple", "guess_host_triple",
"log", "log",
"miette", "miette",
"once_cell",
"reqwest", "reqwest",
"scopeguard", "scopeguard",
"semver", "semver",

View file

@ -30,6 +30,7 @@ flate2 = { version = "1.0.24", features = ["zlib-ng"], default-features = false
futures-util = { version = "0.3.21", default-features = false } futures-util = { version = "0.3.21", default-features = false }
log = "0.4.14" log = "0.4.14"
miette = { version = "4.7.1", features = ["fancy-no-backtrace"] } miette = { version = "4.7.1", features = ["fancy-no-backtrace"] }
once_cell = "1.12.0"
reqwest = { version = "0.11.11", features = [ "rustls-tls", "stream" ], default-features = false } reqwest = { version = "0.11.11", features = [ "rustls-tls", "stream" ], default-features = false }
scopeguard = "1.1.0" scopeguard = "1.1.0"
semver = "1.0.10" semver = "1.0.10"

View file

@ -20,3 +20,13 @@ cargo binstall --help >/dev/null
"./$1" binstall --log-level debug --manifest-path . --no-confirm cargo-binstall "./$1" binstall --log-level debug --manifest-path . --no-confirm cargo-binstall
# Test that the installed binaries can be run # Test that the installed binaries can be run
cargo binstall --help >/dev/null cargo binstall --help >/dev/null
# Install binaries using https-only-mode and specify min tls ver
"./$1" binstall \
--log-level debug \
--https-only-mode \
--min-tls-version tls1-3 \
--no-confirm \
cargo-binstall
# Test that the installed binaries can be run
cargo binstall --help >/dev/null

View file

@ -7,7 +7,9 @@ use tokio::task::JoinHandle;
use url::Url; use url::Url;
use super::Data; use super::Data;
use crate::{download_and_extract, remote_exists, BinstallError, PkgFmt}; use crate::{
download_and_extract, new_reqwest_client_builder, remote_exists, BinstallError, PkgFmt,
};
const BASE_URL: &str = "https://github.com/alsuren/cargo-quickinstall/releases/download"; const BASE_URL: &str = "https://github.com/alsuren/cargo-quickinstall/releases/download";
const STATS_URL: &str = "https://warehouse-clerk-tmp.vercel.app/api/crate"; const STATS_URL: &str = "https://warehouse-clerk-tmp.vercel.app/api/crate";
@ -89,7 +91,7 @@ impl QuickInstall {
let url = Url::parse(&stats_url)?; let url = Url::parse(&stats_url)?;
debug!("Sending installation report to quickinstall ({url})"); debug!("Sending installation report to quickinstall ({url})");
reqwest::Client::builder() new_reqwest_client_builder()
.user_agent(USER_AGENT) .user_agent(USER_AGENT)
.build()? .build()?
.request(Method::HEAD, url.clone()) .request(Method::HEAD, url.clone())

View file

@ -5,7 +5,8 @@ use bytes::Bytes;
use cargo_toml::Manifest; use cargo_toml::Manifest;
use futures_util::stream::Stream; use futures_util::stream::Stream;
use log::debug; use log::debug;
use reqwest::{Method, Response}; use once_cell::sync::OnceCell;
use reqwest::{Client, ClientBuilder, Method, Response};
use serde::Serialize; use serde::Serialize;
use tinytemplate::TinyTemplate; use tinytemplate::TinyTemplate;
use url::Url; use url::Url;
@ -27,6 +28,12 @@ mod stream_readable;
mod path_ext; mod path_ext;
pub use path_ext::*; pub use path_ext::*;
mod tls_version;
pub use tls_version::TLSVersion;
/// (enable https only mode, min TLS version_option)
pub static REQWESTGLOBALCONFIG: OnceCell<(bool, Option<TLSVersion>)> = OnceCell::new();
/// Load binstall metadata from the crate `Cargo.toml` at the provided path /// Load binstall metadata from the crate `Cargo.toml` at the provided path
pub fn load_manifest_path<P: AsRef<Path>>( pub fn load_manifest_path<P: AsRef<Path>>(
manifest_path: P, manifest_path: P,
@ -40,8 +47,30 @@ pub fn load_manifest_path<P: AsRef<Path>>(
Ok(manifest) Ok(manifest)
} }
pub fn new_reqwest_client_builder() -> ClientBuilder {
let mut builder = ClientBuilder::new();
if let Some((https_only, min_tls_ver_opt)) = REQWESTGLOBALCONFIG.get() {
builder = builder.https_only(*https_only);
if *https_only {
builder = builder.min_tls_version(reqwest::tls::Version::TLS_1_2);
}
if let Some(min_tls_ver) = *min_tls_ver_opt {
builder = builder.min_tls_version(min_tls_ver.into());
}
}
builder
}
pub fn new_reqwest_client() -> reqwest::Result<Client> {
new_reqwest_client_builder().build()
}
pub async fn remote_exists(url: Url, method: Method) -> Result<bool, BinstallError> { pub async fn remote_exists(url: Url, method: Method) -> Result<bool, BinstallError> {
let req = reqwest::Client::new() let req = new_reqwest_client()?
.request(method.clone(), url.clone()) .request(method.clone(), url.clone())
.send() .send()
.await .await
@ -54,7 +83,9 @@ async fn create_request(
) -> Result<impl Stream<Item = reqwest::Result<Bytes>>, BinstallError> { ) -> Result<impl Stream<Item = reqwest::Result<Bytes>>, BinstallError> {
debug!("Downloading from: '{url}'"); debug!("Downloading from: '{url}'");
reqwest::get(url.clone()) new_reqwest_client()?
.get(url.clone())
.send()
.await .await
.and_then(|r| r.error_for_status()) .and_then(|r| r.error_for_status())
.map_err(|err| BinstallError::Http { .map_err(|err| BinstallError::Http {

View file

@ -0,0 +1,17 @@
use clap::ArgEnum;
use reqwest::tls::Version;
#[derive(Debug, Copy, Clone, ArgEnum)]
pub enum TLSVersion {
Tls1_2,
Tls1_3,
}
impl From<TLSVersion> for Version {
fn from(ver: TLSVersion) -> Self {
match ver {
TLSVersion::Tls1_2 => Version::TLS_1_2,
TLSVersion::Tls1_3 => Version::TLS_1_3,
}
}
}

View file

@ -84,6 +84,17 @@ struct Options {
#[clap(long)] #[clap(long)]
no_cleanup: bool, no_cleanup: bool,
/// Enable https only mode.
///
/// When https only mode is enabled, it will also set
/// minimum TLS version to tls1_2.
#[clap(long)]
https_only_mode: bool,
/// Decide which TLS version to use.
#[clap(long, arg_enum)]
min_tls_version: Option<TLSVersion>,
/// Override manifest source. /// Override manifest source.
/// ///
/// This skips searching crates.io for a manifest and uses the specified path directly, useful /// This skips searching crates.io for a manifest and uses the specified path directly, useful
@ -177,6 +188,11 @@ async fn entry() -> Result<()> {
bin_dir: opts.bin_dir.take(), bin_dir: opts.bin_dir.take(),
}; };
// Initialize REQWESTGLOBALCONFIG
REQWESTGLOBALCONFIG
.set((opts.https_only_mode, opts.min_tls_version))
.unwrap();
// Setup logging // Setup logging
let mut log_config = ConfigBuilder::new(); let mut log_config = ConfigBuilder::new();
log_config.add_filter_ignore("hyper".to_string()); log_config.add_filter_ignore("hyper".to_string());