Add rustls for TLS (#15810)

<!--
if this PR closes one or more issues, you can automatically link the PR
with
them by using one of the [*linking
keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword),
e.g.
- this PR should close #xxxx
- fixes #xxxx

you can also mention related issues, PRs or discussions!
-->

closes #14041

# Description

<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

This PR switches our default TLS backend from `native-tls` to `rustls`.
Cross-compiles, `musl`, and other targets build smoother because we drop
the OpenSSL requirement.

`native-tls` is still available as an opt-in on `nu-command` via the
`native-tls` feature.
WASM + `network` still fails for unrelated crates, but the OpenSSL
roadblock is gone.

# User-Facing Changes

<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

No changes to the Nushell API.

If you embed Nushell you now need to pick a
[`rustls::crypto::CryptoProvider`](https://docs.rs/rustls/0.23.27/rustls/crypto/struct.CryptoProvider.html)
at startup:

```rust
use nu_command::tls::CRYPTO_PROVIDER;

// common case
CRYPTO_PROVIDER.default();

// or supply your own
CRYPTO_PROVIDER.set(|| Ok(my_provider()));
```

# Tests + Formatting

<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the
tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

* 🟢 `toolkit fmt`
* 🟢 `toolkit clippy`
* 🟢 `toolkit test`
* 🟢 `toolkit test stdlib`

# After Submitting

<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
Piepmatz 2025-05-23 22:45:15 +02:00 committed by GitHub
parent 60cb13c493
commit cc8b623ff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 479 additions and 25 deletions

120
Cargo.lock generated
View File

@ -370,6 +370,29 @@ dependencies = [
"zeroize",
]
[[package]]
name = "aws-lc-rs"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7"
dependencies = [
"aws-lc-sys",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079"
dependencies = [
"bindgen 0.69.5",
"cc",
"cmake",
"dunce",
"fs_extra",
]
[[package]]
name = "aws-runtime"
version = "1.4.3"
@ -680,6 +703,29 @@ dependencies = [
"serde",
]
[[package]]
name = "bindgen"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"bitflags 2.6.0",
"cexpr",
"clang-sys",
"itertools 0.11.0",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.1.0",
"shlex",
"syn 2.0.90",
"which 4.4.2",
]
[[package]]
name = "bindgen"
version = "0.70.1"
@ -1069,6 +1115,15 @@ dependencies = [
"error-code",
]
[[package]]
name = "cmake"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
dependencies = [
"cc",
]
[[package]]
name = "codepage"
version = "0.1.2"
@ -2482,6 +2537,7 @@ dependencies = [
"tokio",
"tokio-rustls 0.26.1",
"tower-service",
"webpki-roots 0.26.8",
]
[[package]]
@ -2910,6 +2966,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.168"
@ -2972,7 +3034,7 @@ version = "0.14.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78a09b56be5adbcad5aa1197371688dc6bb249a26da3bca2011ee2fb987ebfb"
dependencies = [
"bindgen",
"bindgen 0.70.1",
"errno",
"libc",
]
@ -3563,7 +3625,7 @@ dependencies = [
"tempfile",
"unicode-segmentation",
"uuid",
"which",
"which 7.0.0",
]
[[package]]
@ -3719,6 +3781,8 @@ dependencies = [
"rstest",
"rstest_reuse",
"rusqlite",
"rustls 0.23.20",
"rustls-native-certs 0.8.1",
"scopeguard",
"serde",
"serde_json",
@ -3749,7 +3813,8 @@ dependencies = [
"v_htmlescape",
"wax",
"web-time",
"which",
"webpki-roots 1.0.0",
"which 7.0.0",
"windows 0.56.0",
"winreg",
]
@ -4059,7 +4124,7 @@ dependencies = [
"nu-utils",
"num-format",
"tempfile",
"which",
"which 7.0.0",
]
[[package]]
@ -5512,6 +5577,16 @@ dependencies = [
"yansi",
]
[[package]]
name = "prettyplease"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
dependencies = [
"proc-macro2",
"syn 2.0.90",
]
[[package]]
name = "print-positions"
version = "0.6.1"
@ -6028,6 +6103,7 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots 0.26.8",
"windows-registry",
]
@ -6272,6 +6348,8 @@ version = "0.23.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
dependencies = [
"aws-lc-rs",
"log",
"once_cell",
"ring",
"rustls-pki-types",
@ -6347,6 +6425,7 @@ version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@ -7648,10 +7727,13 @@ dependencies = [
"log",
"native-tls",
"once_cell",
"rustls 0.23.20",
"rustls-pki-types",
"serde",
"serde_json",
"socks",
"url",
"webpki-roots 0.26.8",
]
[[package]]
@ -8153,6 +8235,36 @@ dependencies = [
"url",
]
[[package]]
name = "webpki-roots"
version = "0.26.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webpki-roots"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix 0.38.42",
]
[[package]]
name = "which"
version = "7.0.0"

View File

@ -148,6 +148,8 @@ rstest = { version = "0.23", default-features = false }
rstest_reuse = "0.7"
rusqlite = "0.31"
rust-embed = "8.7.0"
rustls = "0.23"
rustls-native-certs = "0.8"
scopeguard = { version = "1.2.0" }
serde = { version = "1.0" }
serde_json = "1.0.97"
@ -164,7 +166,7 @@ tempfile = "3.20"
titlecase = "3.5"
toml = "0.8"
trash = "5.2"
update-informer = { version = "1.2.0", default-features = false, features = ["github", "native-tls", "ureq"] }
update-informer = { version = "1.2.0", default-features = false, features = ["github", "ureq"] }
umask = "2.1"
unicode-segmentation = "1.12"
unicode-width = "0.2"
@ -187,6 +189,7 @@ windows = "0.56"
windows-sys = "0.48"
winreg = "0.52"
memchr = "2.7.4"
webpki-roots = "1.0"
[workspace.lints.clippy]
# Warning: workspace lints affect library code as well as tests, so don't enable lints that would be too noisy in tests like that.
@ -202,7 +205,7 @@ nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.104.2" }
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.104.2" }
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.104.2", optional = true }
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.104.2" }
nu-command = { path = "./crates/nu-command", version = "0.104.2" }
nu-command = { path = "./crates/nu-command", version = "0.104.2", default-features = false, features = ["os"] }
nu-engine = { path = "./crates/nu-engine", version = "0.104.2" }
nu-explore = { path = "./crates/nu-explore", version = "0.104.2" }
nu-lsp = { path = "./crates/nu-lsp/", version = "0.104.2" }
@ -269,10 +272,14 @@ plugin = [
"nu-protocol/plugin",
]
native-tls = ["nu-command/native-tls"]
rustls-tls = ["nu-command/rustls-tls"]
default = [
"plugin",
"trash-support",
"sqlite",
"rustls-tls"
]
stable = ["default"]
# NOTE: individual features are also passed to `nu-cmd-lang` that uses them to generate the feature matrix in the `version` command

View File

@ -91,6 +91,8 @@ rusqlite = { workspace = true, features = [
"backup",
"chrono",
], optional = true }
rustls = { workspace = true, optional = true }
rustls-native-certs = { workspace = true, optional = true }
rmp = { workspace = true }
scopeguard = { workspace = true }
serde = { workspace = true, features = ["derive"] }
@ -108,7 +110,6 @@ ureq = { workspace = true, default-features = false, features = [
"charset",
"gzip",
"json",
"native-tls",
], optional = true }
url = { workspace = true }
uu_cp = { workspace = true, optional = true }
@ -131,6 +132,7 @@ which = { workspace = true, optional = true }
unicode-width = { workspace = true }
data-encoding = { version = "2.9.0", features = ["alloc"] }
web-time = { workspace = true }
webpki-roots = { workspace = true, optional = true }
[target.'cfg(windows)'.dependencies]
winreg = { workspace = true }
@ -165,7 +167,7 @@ features = [
workspace = true
[features]
default = ["os"]
default = ["os", "rustls-tls"]
os = [
# include other features
"js",
@ -197,11 +199,24 @@ js = ["getrandom", "getrandom/js", "rand", "uuid"]
# interface requires openssl which is not easy to embed into wasm,
# using rustls could solve this issue.
network = [
# these two don't require openssl
"multipart-rs",
"native-tls",
"update-informer/native-tls",
"ureq",
"uuid",
"ureq",
"update-informer"
]
native-tls = [
"dep:native-tls",
"update-informer/native-tls",
"ureq/native-tls",
]
rustls-tls = [
"dep:rustls",
"dep:rustls-native-certs",
"dep:webpki-roots",
"update-informer/rustls-tls",
"ureq/tls", # ureq 3 will has the feature rustls instead
]
plugin = ["nu-parser/plugin", "os"]

View File

@ -1,4 +1,4 @@
use crate::formats::value_to_json_value;
use crate::{formats::value_to_json_value, network::tls::tls};
use base64::{
Engine, alphabet,
engine::{GeneralPurpose, general_purpose::PAD},
@ -56,20 +56,9 @@ pub fn http_client(
engine_state: &EngineState,
stack: &mut Stack,
) -> Result<ureq::Agent, ShellError> {
let tls = native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(allow_insecure)
.build()
.map_err(|e| ShellError::GenericError {
error: format!("Failed to build network tls: {}", e),
msg: String::new(),
span: None,
help: None,
inner: vec![],
})?;
let mut agent_builder = ureq::builder()
.user_agent("nushell")
.tls_connector(std::sync::Arc::new(tls));
.tls_connector(std::sync::Arc::new(tls(allow_insecure)?));
if let RedirectMode::Manual | RedirectMode::Error = redirect_mode {
agent_builder = agent_builder.redirects(0);

View File

@ -2,6 +2,8 @@
mod http;
#[cfg(feature = "network")]
mod port;
#[cfg(feature = "network")]
pub mod tls;
mod url;
#[cfg(feature = "network")]
mod version_check;

View File

@ -0,0 +1,16 @@
use nu_protocol::ShellError;
use ureq::TlsConnector;
#[doc = include_str!("./tls.rustdoc.md")]
pub fn tls(allow_insecure: bool) -> Result<impl TlsConnector, ShellError> {
native_tls::TlsConnector::builder()
.danger_accept_invalid_certs(allow_insecure)
.build()
.map_err(|e| ShellError::GenericError {
error: format!("Failed to build network tls: {}", e),
msg: String::new(),
span: None,
help: None,
inner: vec![],
})
}

View File

@ -0,0 +1,251 @@
use std::{
ops::Deref,
sync::{Arc, LazyLock, OnceLock},
};
use nu_engine::command_prelude::IoError;
use nu_protocol::ShellError;
use rustls::{
DigitallySignedStruct, RootCertStore, SignatureScheme,
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
crypto::CryptoProvider,
pki_types::{CertificateDer, ServerName, UnixTime},
};
use ureq::TlsConnector;
// TODO: replace all these generic errors with proper errors
/// Stores the crypto provider used by `rustls`.
///
/// This struct lives in the [`CRYPTO_PROVIDER`] static.
/// It can't be created manually.
///
/// ## Purpose
///
/// Nushell does **not** use the global `rustls` crypto provider.
/// You **must** set a provider here—otherwise, any networking command
/// that uses `rustls` won't be able to build a TLS connector.
///
/// This only matters if the **`rustls-tls`** feature is enabled.
/// Builds with **`native-tls`** ignore this completely.
///
/// ## How to set the provider
///
/// * [`NuCryptoProvider::default`]
/// Uses a built-in provider that works with official `nu` builds.
/// This might change in future versions.
///
/// * [`NuCryptoProvider::set`]
/// Lets you provide your own `CryptoProvider` using a closure:
///
/// ```rust
/// use nu_command::tls::CRYPTO_PROVIDER;
///
/// // Call once at startup
/// CRYPTO_PROVIDER.set(|| Ok(rustls::crypto::aws_lc_rs::default_provider()));
/// ```
///
/// Only the first successful call takes effect. Later calls do nothing and return `false`.
#[derive(Debug)]
pub struct NuCryptoProvider(OnceLock<Result<Arc<CryptoProvider>, ShellError>>);
/// Global [`NuCryptoProvider`] instance.
///
/// When the **`rustls-tls`** feature is active, call
/// [`CRYPTO_PROVIDER.default()`](NuCryptoProvider::default) or
/// [`CRYPTO_PROVIDER.set(...)`](NuCryptoProvider::set) once at startup
/// to pick the [`CryptoProvider`] that [`rustls`] will use.
///
/// Later TLS code gets the provider using [`get`](NuCryptoProvider::get).
/// If no provider was set or the closure returned an error, `get` returns a [`ShellError`].
pub static CRYPTO_PROVIDER: NuCryptoProvider = NuCryptoProvider(OnceLock::new());
impl NuCryptoProvider {
/// Returns the current [`CryptoProvider`].
///
/// Comes from the first call to [`default`](Self::default) or [`set`](Self::set).
///
/// # Errors
/// - If no provider was set.
/// - If the `set` closure returned an error.
pub fn get(&self) -> Result<Arc<CryptoProvider>, ShellError> {
// we clone here as the Arc for Ok is super cheap and basically all APIs expect an owned
// ShellError, so we might as well clone here already
match self.0.get() {
Some(val) => val.clone(),
None => Err(ShellError::GenericError {
error: "tls crypto provider not found".to_string(),
msg: "no crypto provider for rustls was defined".to_string(),
span: None,
help: Some("ensure that nu_command::tls::CRYPTO_PROVIDER is set".to_string()),
inner: vec![],
}),
}
}
/// Sets a custom [`CryptoProvider`].
///
/// Call once at startup, before any TLS code runs.
/// The closure runs immediately and the result (either `Ok` or `Err`) is stored.
/// Returns whether the provider was stored successfully.
pub fn set(&self, f: impl FnOnce() -> Result<CryptoProvider, ShellError>) -> bool {
let value = f().map(Arc::new);
self.0.set(value).is_ok()
}
/// Sets a default [`CryptoProvider`] used in official `nu` builds.
///
/// Should work on most systems, but may not work in every setup.
/// If it fails, use [`set`](Self::set) to install a custom one.
/// Returns whether the provider was stored successfully.
pub fn default(&self) -> bool {
self.set(|| Ok(rustls::crypto::aws_lc_rs::default_provider()))
}
}
#[cfg(feature = "os")]
static ROOT_CERT_STORE: LazyLock<Result<Arc<RootCertStore>, ShellError>> = LazyLock::new(|| {
let mut roots = RootCertStore::empty();
let native_certs = rustls_native_certs::load_native_certs();
let errors: Vec<_> = native_certs
.errors
.into_iter()
.map(|err| match err.kind {
rustls_native_certs::ErrorKind::Io { inner, path } => ShellError::Io(
IoError::new_internal_with_path(inner, err.context, nu_protocol::location!(), path),
),
rustls_native_certs::ErrorKind::Os(error) => ShellError::GenericError {
error: error.to_string(),
msg: err.context.to_string(),
span: None,
help: None,
inner: vec![],
},
rustls_native_certs::ErrorKind::Pem(error) => ShellError::GenericError {
error: error.to_string(),
msg: err.context.to_string(),
span: None,
help: None,
inner: vec![],
},
_ => ShellError::GenericError {
error: String::from("unknown error loading native certs"),
msg: err.context.to_string(),
span: None,
help: None,
inner: vec![],
},
})
.collect();
if !errors.is_empty() {
return Err(ShellError::GenericError {
error: String::from("error loading native certs"),
msg: String::from("could not load native certs"),
span: None,
help: None,
inner: errors,
});
}
for cert in native_certs.certs {
roots.add(cert).map_err(|err| ShellError::GenericError {
error: err.to_string(),
msg: String::from("could not add root cert"),
span: None,
help: None,
inner: vec![],
})?;
}
Ok(Arc::new(roots))
});
#[cfg(not(feature = "os"))]
static ROOT_CERT_STORE: LazyLock<Result<Arc<RootCertStore>, ShellError>> = LazyLock::new(|| {
Ok(Arc::new(rustls::RootCertStore {
roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
}))
});
#[doc = include_str!("./tls.rustdoc.md")]
pub fn tls(allow_insecure: bool) -> Result<impl TlsConnector, ShellError> {
let crypto_provider = CRYPTO_PROVIDER.get()?;
let make_protocol_versions_error = |err: rustls::Error| ShellError::GenericError {
error: err.to_string(),
msg: "crypto provider is incompatible with protocol versions".to_string(),
span: None,
help: None,
inner: vec![],
};
let client_config = match allow_insecure {
false => rustls::ClientConfig::builder_with_provider(crypto_provider)
.with_safe_default_protocol_versions()
.map_err(make_protocol_versions_error)?
.with_root_certificates(ROOT_CERT_STORE.deref().clone()?)
.with_no_client_auth(),
true => rustls::ClientConfig::builder_with_provider(crypto_provider)
.with_safe_default_protocol_versions()
.map_err(make_protocol_versions_error)?
.dangerous()
.with_custom_certificate_verifier(Arc::new(UnsecureServerCertVerifier))
.with_no_client_auth(),
};
Ok(Arc::new(client_config))
}
#[derive(Debug)]
struct UnsecureServerCertVerifier;
impl ServerCertVerifier for UnsecureServerCertVerifier {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp_response: &[u8],
_now: UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
Ok(ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn verify_tls13_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
vec![
SignatureScheme::RSA_PKCS1_SHA1,
SignatureScheme::ECDSA_SHA1_Legacy,
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::ECDSA_NISTP521_SHA512,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
]
}
}

View File

@ -0,0 +1,26 @@
//! TLS support for networking commands.
//!
//! This module is available when the `network` feature is enabled. It requires
//! either the `native-tls` or `rustls-tls` feature to be selected.
//!
//! See [`tls`] for how to get a TLS connector.
#[cfg(feature = "native-tls")]
#[path = "impl_native_tls.rs"]
mod impl_tls;
#[cfg(feature = "rustls-tls")]
#[path = "impl_rustls.rs"]
mod impl_tls;
#[cfg(all(not(feature = "native-tls"), not(feature = "rustls-tls")))]
compile_error!(
"No TLS backend enabled. Please enable either the `native-tls` or `rustls-tls` feature."
);
#[cfg(all(feature = "native-tls", feature = "rustls-tls"))]
compile_error!(
"Multiple TLS backends enabled. Please enable only one of `native-tls` or `rustls-tls`, not both."
);
pub use impl_tls::*;

View File

@ -0,0 +1,31 @@
Provide a [`TlsConnector`] for [`ureq`].
This is used by Nushell's networking commands (`http`) to handle secure
(or optionally insecure) HTTP connections.
The returned connector enables `ureq` to perform HTTPS requests.
If `allow_insecure` is set to `true`, certificate verification is disabled.
This function is only available when the `network` feature is enabled,
and requires exactly one of the `native-tls` or `rustls-tls` features to
be active.
# With `native-tls`
When built with `native-tls`, this uses the platform TLS backend:
- OpenSSL on most Unix systems
- SChannel on Windows
These are mature and widely-deployed TLS implementations.
Expect strong platform integration.
# With `rustls-tls`
When built with `rustls-tls`, this uses the pure-Rust [`rustls`] library for TLS.
This has several benefits:
- Easier cross-compilation (no need for OpenSSL headers or linker setup)
- Works with `musl` targets out of the box
- Can be compiled to WASM
A [`NuCryptoProvider`] must be configured before calling this function.
Use [`CRYPTO_PROVIDER.default()`](NuCryptoProvider::default) or
[`CRYPTO_PROVIDER.set(...)`](NuCryptoProvider::set) to initialize it.

View File

@ -6,6 +6,8 @@ use update_informer::{
registry,
};
use super::tls::tls;
#[derive(Clone)]
pub struct VersionCheck;
@ -92,7 +94,7 @@ impl HttpClient for NativeTlsHttpClient {
headers: update_informer::http_client::HeaderMap,
) -> update_informer::Result<T> {
let agent = ureq::AgentBuilder::new()
.tls_connector(std::sync::Arc::new(native_tls::TlsConnector::new()?))
.tls_connector(std::sync::Arc::new(tls(false)?))
.build();
let mut req = agent.get(url).timeout(timeout);

View File

@ -82,6 +82,9 @@ fn main() -> Result<()> {
// TODO: make this conditional in the future
ctrlc_protection(&mut engine_state);
#[cfg(feature = "rustls-tls")]
nu_command::tls::CRYPTO_PROVIDER.default();
// Begin: Default NU_LIB_DIRS, NU_PLUGIN_DIRS
// Set default NU_LIB_DIRS and NU_PLUGIN_DIRS here before the env.nu is processed. If
// the env.nu file exists, these values will be overwritten, if it does not exist, or