diff --git a/.changes/load-cert-mobile.md b/.changes/load-cert-mobile.md new file mode 100644 index 000000000000..156c9ec66ebf --- /dev/null +++ b/.changes/load-cert-mobile.md @@ -0,0 +1,5 @@ +--- +"tauri": minor:feat +--- + +Load root certificate from CLI-set environment variable and use it on the mobile dev server proxy. diff --git a/.changes/mobile-dev-root-cert.md b/.changes/mobile-dev-root-cert.md new file mode 100644 index 000000000000..fac2a06f4449 --- /dev/null +++ b/.changes/mobile-dev-root-cert.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": minor:feat +"@tauri-apps/cli": minor:feat +--- + +Added `--root-certificate-path` option to `android dev` and `ios dev` to be able to connect to HTTPS dev servers. diff --git a/crates/tauri-cli/src/mobile/android/dev.rs b/crates/tauri-cli/src/mobile/android/dev.rs index 70f361748508..054d6fc26e32 100644 --- a/crates/tauri-cli/src/mobile/android/dev.rs +++ b/crates/tauri-cli/src/mobile/android/dev.rs @@ -34,7 +34,7 @@ use cargo_mobile2::{ target::TargetTrait, }; -use std::env::set_current_dir; +use std::{env::set_current_dir, path::PathBuf}; #[derive(Debug, Clone, Parser)] #[clap( @@ -96,6 +96,9 @@ pub struct Options { /// Specify port for the built-in dev server for static files. Defaults to 1430. #[clap(long, env = "TAURI_CLI_PORT")] pub port: Option, + /// Path to the certificate file used by your dev server. Required when using HTTPS. + #[clap(long, env = "TAURI_DEV_ROOT_CERTIFICATE_PATH")] + pub root_certificate_path: Option, } impl From for DevOptions { @@ -129,6 +132,13 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { delete_codegen_vars(); + // setup env additions before calling env() + if let Some(root_certificate_path) = &options.root_certificate_path { + std::env::set_var( + "TAURI_DEV_ROOT_CERTIFICATE", + std::fs::read_to_string(root_certificate_path).context("failed to read certificate file")?, + ); + } let tauri_config = get_tauri_config( tauri_utils::platform::Target::Android, diff --git a/crates/tauri-cli/src/mobile/ios/dev.rs b/crates/tauri-cli/src/mobile/ios/dev.rs index 38569b814297..7522bf465fe7 100644 --- a/crates/tauri-cli/src/mobile/ios/dev.rs +++ b/crates/tauri-cli/src/mobile/ios/dev.rs @@ -32,7 +32,7 @@ use cargo_mobile2::{ opts::{NoiseLevel, Profile}, }; -use std::env::set_current_dir; +use std::{env::set_current_dir, path::PathBuf}; const PHYSICAL_IPHONE_DEV_WARNING: &str = "To develop on physical phones you need the `--host` option (not required for Simulators). See the documentation for more information: https://v2.tauri.app/develop/#development-server"; @@ -101,6 +101,9 @@ pub struct Options { /// Specify port for the built-in dev server for static files. Defaults to 1430. #[clap(long, env = "TAURI_CLI_PORT")] pub port: Option, + /// Path to the certificate file used by your dev server. Required when using HTTPS. + #[clap(long, env = "TAURI_DEV_ROOT_CERTIFICATE_PATH")] + pub root_certificate_path: Option, } impl From for DevOptions { @@ -133,6 +136,14 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { } fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { + // setup env additions before calling env() + if let Some(root_certificate_path) = &options.root_certificate_path { + std::env::set_var( + "TAURI_DEV_ROOT_CERTIFICATE", + std::fs::read_to_string(root_certificate_path).context("failed to read certificate file")?, + ); + } + let env = env()?; let device = if options.open { None diff --git a/crates/tauri/src/protocol/tauri.rs b/crates/tauri/src/protocol/tauri.rs index 14f91a34a579..7da5e9469fab 100644 --- a/crates/tauri/src/protocol/tauri.rs +++ b/crates/tauri/src/protocol/tauri.rs @@ -114,7 +114,42 @@ fn get_response( decoded_path.trim_start_matches('/') ); - let mut proxy_builder = reqwest::ClientBuilder::new() + let mut client = reqwest::ClientBuilder::new(); + + if url.starts_with("https://") { + // we can't load env vars at runtime, gotta embed them in the lib + if let Some(cert_pem) = option_env!("TAURI_DEV_ROOT_CERTIFICATE") { + #[cfg(any( + feature = "native-tls", + feature = "native-tls-vendored", + feature = "rustls-tls" + ))] + { + log::info!("adding dev server root certificate"); + client = client.add_root_certificate( + reqwest::Certificate::from_pem(cert_pem.as_bytes()) + .expect("failed to parse TAURI_DEV_ROOT_CERTIFICATE"), + ); + } + + #[cfg(not(any( + feature = "native-tls", + feature = "native-tls-vendored", + feature = "rustls-tls" + )))] + { + log::warn!( + "the dev root-certificate-path option was provided, but you must enable one of the following Tauri features in Cargo.toml: native-tls, native-tls-vendored, rustls-tls" + ); + } + } else { + log::warn!( + "loading HTTPS URL; you might need to provide a certificate via the `dev --root-certificate-path` option. You must enable one of the following Tauri features in Cargo.toml: native-tls, native-tls-vendored, rustls-tls" + ); + } + } + + let mut proxy_builder = client .build() .unwrap() .request(request.method().clone(), &url);