diff --git a/Cargo.lock b/Cargo.lock index e5f309744cf..9aa8bcb382a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13808,6 +13808,7 @@ dependencies = [ "regex", "reqwest 0.13.5", "rgb", + "rustls 0.23.46", "same-file", "serde", "serde-binhum", @@ -13863,6 +13864,7 @@ dependencies = [ "paste", "path-util", "rand 0.10.3", + "rustls 0.23.46", "serde", "serde_json", "serde_with", diff --git a/Cargo.toml b/Cargo.toml index 8f86595c711..e784e9a4cca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -182,7 +182,7 @@ rust-s3 = { version = "0.38.0", default-features = false, features = [ "tags", "tokio-rustls-tls", ] } -rustls = "0.23.46" +rustls = { version = "0.23.46", default-features = false } rustrict = { version = "0.7.39", default-features = false, features = ["censor"] } rusty-money = "0.5.1" same-file = "1.0.6" diff --git a/apps/app-playground/src/main.rs b/apps/app-playground/src/main.rs index 73319911c24..9364af976b7 100644 --- a/apps/app-playground/src/main.rs +++ b/apps/app-playground/src/main.rs @@ -39,6 +39,7 @@ pub async fn authenticate_run() -> theseus::Result { async fn main() -> theseus::Result<()> { println!("Starting."); + theseus::install_crypto_provider(); let _log_guard = theseus::start_logger("ModrinthApp"); // Initialize state diff --git a/apps/app/Cargo.toml b/apps/app/Cargo.toml index e1754691de3..f8c9bb12d9f 100644 --- a/apps/app/Cargo.toml +++ b/apps/app/Cargo.toml @@ -52,6 +52,9 @@ zip = { workspace = true } workspace = true features = ["devtools", "macos-private-api", "protocol-asset"] +[dev-dependencies] +rustls = { workspace = true, features = ["std"] } + [build-dependencies] tauri-build = { workspace = true, features = ["codegen"] } diff --git a/apps/app/package.json b/apps/app/package.json index 8df4ce14582..f7c5d7dcaa5 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -6,6 +6,7 @@ "dev": "tauri dev --features export-app-events", "lint": "cargo clippy --all-targets --features updater", "lint:ancillary": "prettier --check .", + "test": "cargo nextest run --all-targets --no-fail-fast --locked --features updater", "fix": "cargo clippy --all-targets --features updater --fix --allow-dirty", "fix:ancillary": "prettier --write ." }, diff --git a/apps/app/src/main.rs b/apps/app/src/main.rs index 4f37cc8b5d6..78ead22e206 100644 --- a/apps/app/src/main.rs +++ b/apps/app/src/main.rs @@ -115,6 +115,8 @@ async fn set_restart_after_pending_update( // if Tauri app is called with arguments, then those arguments will be treated as commands // ie: deep links or filepaths for .mrpacks fn main() { + theseus::install_crypto_provider(); + let runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() @@ -491,3 +493,16 @@ fn main() { } } } + +#[cfg(test)] +mod tests { + /// Builds a TLS config the way crates relying on rustls's process-level + /// provider do (e.g. async-tungstenite for the friends socket), with the + /// app's full dependency graph. This only fails here, not in app-lib's + /// own tests, because a conflicting provider feature can come from + /// unifying app-lib's dependencies with the Tauri plugins'. + #[test] + fn rustls_process_provider_is_resolvable() { + let _ = rustls::ClientConfig::builder(); + } +} diff --git a/apps/labrinth/Cargo.toml b/apps/labrinth/Cargo.toml index 7169b8c6007..184e047e99e 100644 --- a/apps/labrinth/Cargo.toml +++ b/apps/labrinth/Cargo.toml @@ -95,7 +95,13 @@ regex = { workspace = true } reqwest = { workspace = true, features = ["http2", "json", "multipart", "rustls"] } rust_decimal = { workspace = true, features = ["serde-with-float", "serde-with-str"] } rust_iso3166 = { workspace = true } -rustls.workspace = true +rustls = { workspace = true, features = [ + "aws_lc_rs", + "logging", + "prefer-post-quantum", + "std", + "tls12", +] } rustrict = { workspace = true } rusty-money = { workspace = true } scalar_api_reference = { workspace = true, features = ["actix-web"] } diff --git a/packages/app-lib/Cargo.toml b/packages/app-lib/Cargo.toml index d510461d871..305f7854a0f 100644 --- a/packages/app-lib/Cargo.toml +++ b/packages/app-lib/Cargo.toml @@ -71,11 +71,12 @@ reqwest = { workspace = true, features = [ "http2", "json", "multipart", - "rustls", + "rustls-no-provider", "stream", "system-proxy", ] } rgb = { workspace = true } +rustls = { workspace = true, features = ["logging", "ring", "std", "tls12"] } same-file = { workspace = true } serde = { workspace = true, features = ["derive", "rc"] } serde-binhum = { workspace = true } diff --git a/packages/app-lib/src/lib.rs b/packages/app-lib/src/lib.rs index e368a16f893..0e2c04aace2 100644 --- a/packages/app-lib/src/lib.rs +++ b/packages/app-lib/src/lib.rs @@ -30,6 +30,14 @@ pub use logger::start_logger; pub use state::State; pub use util::fetch::DownloadReason; +/// Installs `ring` as the process-wide rustls crypto provider. +/// +/// Must be called before any TLS connection is made: reqwest is built with +/// `rustls-no-provider` and the friends socket relies on the process default. +pub fn install_crypto_provider() { + let _ = rustls::crypto::ring::default_provider().install_default(); +} + pub fn launcher_user_agent() -> String { const LAUNCHER_BASE_USER_AGENT: &str = concat!("modrinth/theseus/", env!("CARGO_PKG_VERSION"),);