diff --git a/.changes/core-env.md b/.changes/core-env.md new file mode 100644 index 000000000..328d91833 --- /dev/null +++ b/.changes/core-env.md @@ -0,0 +1,5 @@ +--- +"tauri": patch +--- + +The `process`, `path` and `updater` APIs now takes a `tauri::Env` argument, used to force environment variables load on startup to prevent env var update attacks. diff --git a/core/tauri-utils/src/lib.rs b/core/tauri-utils/src/lib.rs index 3597ecd75..6569045e5 100644 --- a/core/tauri-utils/src/lib.rs +++ b/core/tauri-utils/src/lib.rs @@ -37,6 +37,28 @@ impl PackageInfo { } } +/// Information about environment variables. +#[derive(Debug, Clone)] +pub struct Env { + /// The APPIMAGE environment variable. + #[cfg(target_os = "linux")] + pub appimage: Option, + /// The APPDIR environment variable. + #[cfg(target_os = "linux")] + pub appdir: Option, +} + +impl Default for Env { + fn default() -> Self { + Self { + #[cfg(target_os = "linux")] + appimage: std::env::var_os("APPIMAGE"), + #[cfg(target_os = "linux")] + appdir: std::env::var_os("APPDIR"), + } + } +} + /// The result type of `tauri-utils`. pub type Result = std::result::Result; diff --git a/core/tauri-utils/src/platform.rs b/core/tauri-utils/src/platform.rs index e6e5cabea..c2eeee95d 100644 --- a/core/tauri-utils/src/platform.rs +++ b/core/tauri-utils/src/platform.rs @@ -4,12 +4,9 @@ //! Platform helper functions. -use std::{ - env, - path::{PathBuf, MAIN_SEPARATOR}, -}; +use std::path::{PathBuf, MAIN_SEPARATOR}; -use crate::PackageInfo; +use crate::{Env, PackageInfo}; /// Try to determine the current target triple. /// @@ -76,7 +73,7 @@ pub fn target_triple() -> crate::Result { /// `${exe_dir}/../lib/${exe_name}`. /// /// On MacOS, it's `${exe_dir}../Resources` (inside .app). -pub fn resource_dir(package_info: &PackageInfo) -> crate::Result { +pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> crate::Result { let exe = std::env::current_exe()?; let exe_dir = exe.parent().expect("failed to get exe directory"); let curr_dir = exe_dir.display().to_string(); @@ -93,10 +90,11 @@ pub fn resource_dir(package_info: &PackageInfo) -> crate::Result { if curr_dir.ends_with("/data/usr/bin") { // running from the deb bundle dir Ok(exe_dir.join(format!("../lib/{}", package_info.package_name()))) - } else if let Ok(appdir) = env::var("APPDIR") { + } else if let Some(appdir) = &env.appdir { + let appdir: &std::path::Path = appdir.as_ref(); Ok(PathBuf::from(format!( "{}/usr/lib/{}", - appdir, + appdir.display(), package_info.package_name() ))) } else { diff --git a/core/tauri/src/api/path.rs b/core/tauri/src/api/path.rs index b79408f03..7242ddd45 100644 --- a/core/tauri/src/api/path.rs +++ b/core/tauri/src/api/path.rs @@ -9,7 +9,7 @@ use std::{ path::{Component, Path, PathBuf}, }; -use crate::{Config, PackageInfo}; +use crate::{Config, Env, PackageInfo}; use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -83,6 +83,7 @@ pub enum BaseDirectory { /// authors: "tauri", /// description: "a tauri test", /// }, +/// &Default::default(), /// "path/to/something", /// Some(BaseDirectory::Config) /// ).expect("failed to resolve path"); @@ -91,6 +92,7 @@ pub enum BaseDirectory { pub fn resolve_path>( config: &Config, package_info: &PackageInfo, + env: &Env, path: P, dir: Option, ) -> crate::api::Result { @@ -113,7 +115,7 @@ pub fn resolve_path>( BaseDirectory::Runtime => runtime_dir(), BaseDirectory::Template => template_dir(), BaseDirectory::Video => video_dir(), - BaseDirectory::Resource => resource_dir(package_info), + BaseDirectory::Resource => resource_dir(package_info, env), BaseDirectory::App => app_dir(config), BaseDirectory::Current => Some(env::current_dir()?), BaseDirectory::Log => log_dir(config), @@ -229,8 +231,8 @@ pub fn video_dir() -> Option { } /// Returns the path to the resource directory of this app. -pub fn resource_dir(package_info: &PackageInfo) -> Option { - crate::utils::platform::resource_dir(package_info).ok() +pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> Option { + crate::utils::platform::resource_dir(package_info, env).ok() } /// Returns the path to the suggested directory for your app config files. diff --git a/core/tauri/src/api/process.rs b/core/tauri/src/api/process.rs index fb3a55b47..1e6175786 100644 --- a/core/tauri/src/api/process.rs +++ b/core/tauri/src/api/process.rs @@ -4,6 +4,8 @@ //! Types and functions related to child processes management. +use crate::Env; + use std::{ env, path::PathBuf, @@ -16,12 +18,13 @@ mod command; pub use command::*; /// Gets the current binary. -pub fn current_binary() -> Option { +#[allow(unused_variables)] +pub fn current_binary(env: &Env) -> Option { let mut current_binary = None; // if we are running with an APP Image, we should return the app image path #[cfg(target_os = "linux")] - if let Some(app_image_path) = env::var_os("APPIMAGE") { + if let Some(app_image_path) = &env.appimage { current_binary = Some(PathBuf::from(app_image_path)); } @@ -37,8 +40,8 @@ pub fn current_binary() -> Option { } /// Restarts the process. -pub fn restart() { - if let Some(path) = current_binary() { +pub fn restart(env: &Env) { + if let Some(path) = current_binary(env) { StdCommand::new(path) .spawn() .expect("application failed to start"); diff --git a/core/tauri/src/app.rs b/core/tauri/src/app.rs index 8d4bfac15..95d719809 100644 --- a/core/tauri/src/app.rs +++ b/core/tauri/src/app.rs @@ -19,8 +19,8 @@ use crate::{ Dispatch, ExitRequestedEventAction, RunEvent, Runtime, }, sealed::{ManagerBase, RuntimeOrDispatch}, - utils::assets::Assets, utils::config::{Config, WindowUrl}, + utils::{assets::Assets, Env}, Context, Invoke, InvokeError, InvokeResponse, Manager, StateManager, Window, }; @@ -150,6 +150,7 @@ impl GlobalWindowEvent { /// The path resolver is a helper for the application-specific [`crate::api::path`] APIs. #[derive(Debug, Clone)] pub struct PathResolver { + env: Env, config: Arc, package_info: PackageInfo, } @@ -157,7 +158,7 @@ pub struct PathResolver { impl PathResolver { /// Returns the path to the resource directory of this app. pub fn resource_dir(&self) -> Option { - crate::api::path::resource_dir(&self.package_info) + crate::api::path::resource_dir(&self.package_info, &self.env) } /// Returns the path to the suggested directory for your app config files. @@ -407,6 +408,7 @@ macro_rules! shared_app_impl { /// The path resolver for the application. pub fn path_resolver(&self) -> PathResolver { PathResolver { + env: self.state::().inner().clone(), config: self.manager.config(), package_info: self.manager.package_info().clone(), } @@ -432,6 +434,11 @@ macro_rules! shared_app_impl { self.manager.package_info() } + /// Gets the managed [`Env`]. + pub fn env(&self) -> Env { + self.state::().inner().clone() + } + /// The application's asset resolver. pub fn asset_resolver(&self) -> AssetResolver { AssetResolver { @@ -990,6 +997,8 @@ impl Builder { }, }; + app.manage(Env::default()); + #[cfg(feature = "system-tray")] if let Some(system_tray) = self.system_tray { let mut ids = HashMap::new(); diff --git a/core/tauri/src/endpoints.rs b/core/tauri/src/endpoints.rs index d63cbb9ca..42a55eee9 100644 --- a/core/tauri/src/endpoints.rs +++ b/core/tauri/src/endpoints.rs @@ -75,17 +75,21 @@ impl Module { .and_then(|r| r.json) .map_err(InvokeError::from) }), - Self::Process(cmd) => resolver - .respond_async(async move { cmd.run().and_then(|r| r.json).map_err(InvokeError::from) }), + Self::Process(cmd) => resolver.respond_async(async move { + cmd + .run(window) + .and_then(|r| r.json) + .map_err(InvokeError::from) + }), Self::Fs(cmd) => resolver.respond_async(async move { cmd - .run(config, &package_info) + .run(window, config, &package_info) .and_then(|r| r.json) .map_err(InvokeError::from) }), Self::Path(cmd) => resolver.respond_async(async move { cmd - .run(config, &package_info) + .run(window, config, &package_info) .and_then(|r| r.json) .map_err(InvokeError::from) }), diff --git a/core/tauri/src/endpoints/file_system.rs b/core/tauri/src/endpoints/file_system.rs index 08a29a313..f5e57b83e 100644 --- a/core/tauri/src/endpoints/file_system.rs +++ b/core/tauri/src/endpoints/file_system.rs @@ -8,7 +8,7 @@ use crate::{ dir, file, path::{resolve_path, BaseDirectory}, }, - Config, PackageInfo, + Config, Env, Manager, PackageInfo, Runtime, Window, }; use serde::{Deserialize, Serialize}; @@ -97,15 +97,17 @@ pub enum Cmd { impl Cmd { #[allow(unused_variables)] - pub fn run( + pub fn run( self, + window: Window, config: Arc, package_info: &PackageInfo, ) -> crate::Result { + let env = window.state::().inner(); match self { #[cfg(fs_read_text_file)] Self::ReadTextFile { path, options } => { - read_text_file(&config, package_info, path, options).map(Into::into) + read_text_file(&config, package_info, env, path, options).map(Into::into) } #[cfg(not(fs_read_text_file))] Self::ReadTextFile { .. } => Err(crate::Error::ApiNotAllowlisted( @@ -114,7 +116,7 @@ impl Cmd { #[cfg(fs_read_binary_file)] Self::ReadBinaryFile { path, options } => { - read_binary_file(&config, package_info, path, options).map(Into::into) + read_binary_file(&config, package_info, env, path, options).map(Into::into) } #[cfg(not(fs_read_binary_file))] Self::ReadBinaryFile { .. } => Err(crate::Error::ApiNotAllowlisted( @@ -126,7 +128,7 @@ impl Cmd { path, contents, options, - } => write_file(&config, package_info, path, contents, options).map(Into::into), + } => write_file(&config, package_info, env, path, contents, options).map(Into::into), #[cfg(not(fs_write_file))] Self::WriteFile { .. } => Err(crate::Error::ApiNotAllowlisted( "fs > writeFile".to_string(), @@ -137,7 +139,7 @@ impl Cmd { path, contents, options, - } => write_binary_file(&config, package_info, path, contents, options).map(Into::into), + } => write_binary_file(&config, package_info, env, path, contents, options).map(Into::into), #[cfg(not(fs_write_binary_file))] Self::WriteBinaryFile { .. } => Err(crate::Error::ApiNotAllowlisted( "writeBinaryFile".to_string(), @@ -145,7 +147,7 @@ impl Cmd { #[cfg(fs_read_dir)] Self::ReadDir { path, options } => { - read_dir(&config, package_info, path, options).map(Into::into) + read_dir(&config, package_info, env, path, options).map(Into::into) } #[cfg(not(fs_read_dir))] Self::ReadDir { .. } => Err(crate::Error::ApiNotAllowlisted("fs > readDir".to_string())), @@ -155,13 +157,13 @@ impl Cmd { source, destination, options, - } => copy_file(&config, package_info, source, destination, options).map(Into::into), + } => copy_file(&config, package_info, env, source, destination, options).map(Into::into), #[cfg(not(fs_copy_file))] Self::CopyFile { .. } => Err(crate::Error::ApiNotAllowlisted("fs > copyFile".to_string())), #[cfg(fs_create_dir)] Self::CreateDir { path, options } => { - create_dir(&config, package_info, path, options).map(Into::into) + create_dir(&config, package_info, env, path, options).map(Into::into) } #[cfg(not(fs_create_dir))] Self::CreateDir { .. } => Err(crate::Error::ApiNotAllowlisted( @@ -170,7 +172,7 @@ impl Cmd { #[cfg(fs_remove_dir)] Self::RemoveDir { path, options } => { - remove_dir(&config, package_info, path, options).map(Into::into) + remove_dir(&config, package_info, env, path, options).map(Into::into) } #[cfg(not(fs_remove_dir))] Self::RemoveDir { .. } => Err(crate::Error::ApiNotAllowlisted( @@ -179,7 +181,7 @@ impl Cmd { #[cfg(fs_remove_file)] Self::RemoveFile { path, options } => { - remove_file(&config, package_info, path, options).map(Into::into) + remove_file(&config, package_info, env, path, options).map(Into::into) } #[cfg(not(fs_remove_file))] Self::RemoveFile { .. } => Err(crate::Error::ApiNotAllowlisted( @@ -191,7 +193,7 @@ impl Cmd { old_path, new_path, options, - } => rename_file(&config, package_info, old_path, new_path, options).map(Into::into), + } => rename_file(&config, package_info, env, old_path, new_path, options).map(Into::into), #[cfg(not(fs_rename_file))] Self::RenameFile { .. } => Err(crate::Error::ApiNotAllowlisted( "fs > renameFile".to_string(), @@ -205,6 +207,7 @@ impl Cmd { pub fn read_dir( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, options: Option, ) -> crate::Result> { @@ -213,8 +216,11 @@ pub fn read_dir( } else { (false, None) }; - dir::read_dir(resolve_path(config, package_info, path, dir)?, recursive) - .map_err(crate::Error::FailedToExecuteApi) + dir::read_dir( + resolve_path(config, package_info, env, path, dir)?, + recursive, + ) + .map_err(crate::Error::FailedToExecuteApi) } /// Copies a file. @@ -222,14 +228,15 @@ pub fn read_dir( pub fn copy_file( config: &Config, package_info: &PackageInfo, + env: &Env, source: PathBuf, destination: PathBuf, options: Option, ) -> crate::Result<()> { let (src, dest) = match options.and_then(|o| o.dir) { Some(dir) => ( - resolve_path(config, package_info, source, Some(dir.clone()))?, - resolve_path(config, package_info, destination, Some(dir))?, + resolve_path(config, package_info, env, source, Some(dir.clone()))?, + resolve_path(config, package_info, env, destination, Some(dir))?, ), None => (source, destination), }; @@ -242,6 +249,7 @@ pub fn copy_file( pub fn create_dir( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, options: Option, ) -> crate::Result<()> { @@ -250,7 +258,7 @@ pub fn create_dir( } else { (false, None) }; - let resolved_path = resolve_path(config, package_info, path, dir)?; + let resolved_path = resolve_path(config, package_info, env, path, dir)?; if recursive { fs::create_dir_all(resolved_path)?; } else { @@ -265,6 +273,7 @@ pub fn create_dir( pub fn remove_dir( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, options: Option, ) -> crate::Result<()> { @@ -273,7 +282,7 @@ pub fn remove_dir( } else { (false, None) }; - let resolved_path = resolve_path(config, package_info, path, dir)?; + let resolved_path = resolve_path(config, package_info, env, path, dir)?; if recursive { fs::remove_dir_all(resolved_path)?; } else { @@ -288,10 +297,11 @@ pub fn remove_dir( pub fn remove_file( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, options: Option, ) -> crate::Result<()> { - let resolved_path = resolve_path(config, package_info, path, options.and_then(|o| o.dir))?; + let resolved_path = resolve_path(config, package_info, env, path, options.and_then(|o| o.dir))?; fs::remove_file(resolved_path)?; Ok(()) } @@ -301,14 +311,15 @@ pub fn remove_file( pub fn rename_file( config: &Config, package_info: &PackageInfo, + env: &Env, old_path: PathBuf, new_path: PathBuf, options: Option, ) -> crate::Result<()> { let (old, new) = match options.and_then(|o| o.dir) { Some(dir) => ( - resolve_path(config, package_info, old_path, Some(dir.clone()))?, - resolve_path(config, package_info, new_path, Some(dir))?, + resolve_path(config, package_info, env, old_path, Some(dir.clone()))?, + resolve_path(config, package_info, env, new_path, Some(dir))?, ), None => (old_path, new_path), }; @@ -320,6 +331,7 @@ pub fn rename_file( pub fn write_file( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, contents: String, options: Option, @@ -327,6 +339,7 @@ pub fn write_file( File::create(resolve_path( config, package_info, + env, path, options.and_then(|o| o.dir), )?) @@ -340,6 +353,7 @@ pub fn write_file( pub fn write_binary_file( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, contents: String, options: Option, @@ -350,6 +364,7 @@ pub fn write_binary_file( File::create(resolve_path( config, package_info, + env, path, options.and_then(|o| o.dir), )?) @@ -364,12 +379,14 @@ pub fn write_binary_file( pub fn read_text_file( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, options: Option, ) -> crate::Result { file::read_string(resolve_path( config, package_info, + env, path, options.and_then(|o| o.dir), )?) @@ -381,12 +398,14 @@ pub fn read_text_file( pub fn read_binary_file( config: &Config, package_info: &PackageInfo, + env: &Env, path: PathBuf, options: Option, ) -> crate::Result> { file::read_binary(resolve_path( config, package_info, + env, path, options.and_then(|o| o.dir), )?) diff --git a/core/tauri/src/endpoints/notification.rs b/core/tauri/src/endpoints/notification.rs index 8a3fa6baf..3126db707 100644 --- a/core/tauri/src/endpoints/notification.rs +++ b/core/tauri/src/endpoints/notification.rs @@ -6,7 +6,7 @@ use super::InvokeResponse; use serde::Deserialize; #[cfg(notification_all)] -use crate::api::notification::Notification; +use crate::{api::notification::Notification, Env, Manager}; use crate::{Config, PackageInfo, Runtime, Window}; use std::sync::Arc; @@ -55,7 +55,7 @@ impl Cmd { Self::Notification { .. } => Err(crate::Error::ApiNotAllowlisted("notification".to_string())), Self::IsNotificationPermissionGranted => { #[cfg(notification_all)] - return is_permission_granted(&config, package_info).map(Into::into); + return is_permission_granted(&window, &config, package_info).map(Into::into); #[cfg(not(notification_all))] Ok(false.into()) } @@ -84,11 +84,13 @@ pub fn send(options: NotificationOptions, config: &Config) -> crate::Result( + window: &Window, config: &Config, package_info: &PackageInfo, ) -> crate::Result { - let settings = crate::settings::read_settings(config, package_info); + let settings = + crate::settings::read_settings(config, package_info, window.state::().inner()); if let Some(allow_notification) = settings.allow_notification { Ok(allow_notification.into()) } else { @@ -102,7 +104,8 @@ pub fn request_permission( config: &Config, package_info: &PackageInfo, ) -> crate::Result { - let mut settings = crate::settings::read_settings(config, package_info); + let mut settings = + crate::settings::read_settings(config, package_info, window.state::().inner()); if let Some(allow_notification) = settings.allow_notification { return Ok(if allow_notification { PERMISSION_GRANTED.to_string() @@ -123,7 +126,12 @@ pub fn request_permission( let answer = rx.recv().unwrap(); settings.allow_notification = Some(answer); - crate::settings::write_settings(config, package_info, settings)?; + crate::settings::write_settings( + config, + package_info, + window.state::().inner(), + settings, + )?; if answer { Ok(PERMISSION_GRANTED.to_string()) diff --git a/core/tauri/src/endpoints/path.rs b/core/tauri/src/endpoints/path.rs index 1544bce4c..d30fcfcfa 100644 --- a/core/tauri/src/endpoints/path.rs +++ b/core/tauri/src/endpoints/path.rs @@ -3,7 +3,9 @@ // SPDX-License-Identifier: MIT use super::InvokeResponse; -use crate::{api::path::BaseDirectory, Config, PackageInfo}; +use crate::{api::path::BaseDirectory, Config, PackageInfo, Runtime, Window}; +#[cfg(path_all)] +use crate::{Env, Manager}; use serde::Deserialize; #[cfg(path_all)] use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR}; @@ -42,16 +44,22 @@ pub enum Cmd { impl Cmd { #[allow(unused_variables)] - pub fn run( + pub fn run( self, + window: Window, config: Arc, package_info: &PackageInfo, ) -> crate::Result { #[cfg(path_all)] return match self { - Cmd::ResolvePath { directory, path } => { - resolve_path_handler(&config, package_info, path, directory).map(Into::into) - } + Cmd::ResolvePath { directory, path } => resolve_path_handler( + &config, + package_info, + window.state::().inner(), + path, + directory, + ) + .map(Into::into), Cmd::Resolve { paths } => resolve(paths).map(Into::into), Cmd::Normalize { path } => normalize(path).map(Into::into), Cmd::Join { paths } => join(paths).map(Into::into), @@ -69,10 +77,11 @@ impl Cmd { pub fn resolve_path_handler( config: &Config, package_info: &PackageInfo, + env: &Env, path: String, directory: Option, ) -> crate::Result { - crate::api::path::resolve_path(config, package_info, path, directory).map_err(Into::into) + crate::api::path::resolve_path(config, package_info, env, path, directory).map_err(Into::into) } #[cfg(path_all)] diff --git a/core/tauri/src/endpoints/process.rs b/core/tauri/src/endpoints/process.rs index bb92d0331..e84caf2c3 100644 --- a/core/tauri/src/endpoints/process.rs +++ b/core/tauri/src/endpoints/process.rs @@ -5,7 +5,7 @@ use std::process::exit; use super::InvokeResponse; -use crate::api::process::restart; +use crate::{api::process::restart, Manager, Runtime, Window}; use serde::Deserialize; /// The API descriptor. @@ -20,10 +20,10 @@ pub enum Cmd { } impl Cmd { - pub fn run(self) -> crate::Result { + pub fn run(self, window: Window) -> crate::Result { match self { Self::Relaunch => Ok({ - restart(); + restart(&window.state()); ().into() }), Self::Exit { exit_code } => { diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index f32c6c003..b01faa99e 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -108,7 +108,7 @@ pub use { self::utils::{ assets::Assets, config::{Config, WindowUrl}, - PackageInfo, + Env, PackageInfo, }, self::window::{Monitor, Window}, }; diff --git a/core/tauri/src/settings.rs b/core/tauri/src/settings.rs index 82017e4c6..f61b15e71 100644 --- a/core/tauri/src/settings.rs +++ b/core/tauri/src/settings.rs @@ -11,7 +11,7 @@ use crate::{ file::read_binary, path::{resolve_path, BaseDirectory}, }, - Config, PackageInfo, + Config, Env, PackageInfo, }; use serde::{Deserialize, Serialize}; use std::{ @@ -30,10 +30,15 @@ pub struct Settings { } /// Gets the path to the settings file. -fn get_settings_path(config: &Config, package_info: &PackageInfo) -> crate::api::Result { +fn get_settings_path( + config: &Config, + package_info: &PackageInfo, + env: &Env, +) -> crate::api::Result { resolve_path( config, package_info, + env, ".tauri-settings", Some(BaseDirectory::App), ) @@ -44,9 +49,10 @@ fn get_settings_path(config: &Config, package_info: &PackageInfo) -> crate::api: pub(crate) fn write_settings( config: &Config, package_info: &PackageInfo, + env: &Env, settings: Settings, ) -> crate::Result<()> { - let settings_path = get_settings_path(config, package_info)?; + let settings_path = get_settings_path(config, package_info, env)?; let settings_folder = Path::new(&settings_path).parent().unwrap(); if !settings_folder.exists() { std::fs::create_dir(settings_folder)?; @@ -60,8 +66,8 @@ pub(crate) fn write_settings( } /// Reads the settings from the file system. -pub fn read_settings(config: &Config, package_info: &PackageInfo) -> Settings { - if let Ok(settings_path) = get_settings_path(config, package_info) { +pub fn read_settings(config: &Config, package_info: &PackageInfo, env: &Env) -> Settings { + if let Ok(settings_path) = get_settings_path(config, package_info, env) { if settings_path.exists() { read_binary(settings_path) .and_then(|settings| bincode::deserialize(&settings).map_err(Into::into)) diff --git a/core/tauri/src/updater/core.rs b/core/tauri/src/updater/core.rs index 7ce5e9243..024380a07 100644 --- a/core/tauri/src/updater/core.rs +++ b/core/tauri/src/updater/core.rs @@ -3,7 +3,10 @@ // SPDX-License-Identifier: MIT use super::error::{Error, Result}; -use crate::api::{file::Extract, version}; +use crate::{ + api::{file::Extract, version}, + Env, +}; use base64::decode; use http::StatusCode; use minisign_verify::{PublicKey, Signature}; @@ -171,6 +174,8 @@ impl RemoteRelease { #[derive(Debug)] pub struct UpdateBuilder<'a> { + /// Environment information. + pub env: Env, /// Current version we are running to compare with announced version pub current_version: &'a str, /// The URLs to checks updates. We suggest at least one fallback on a different domain. @@ -181,22 +186,17 @@ pub struct UpdateBuilder<'a> { pub executable_path: Option, } -impl<'a> Default for UpdateBuilder<'a> { - fn default() -> Self { +// Create new updater instance and return an Update +impl<'a> UpdateBuilder<'a> { + pub fn new(env: Env) -> Self { UpdateBuilder { + env, urls: Vec::new(), target: None, executable_path: None, current_version: env!("CARGO_PKG_VERSION"), } } -} - -// Create new updater instance and return an Update -impl<'a> UpdateBuilder<'a> { - pub fn new() -> Self { - UpdateBuilder::default() - } #[allow(dead_code)] pub fn url(mut self, url: String) -> Self { @@ -267,7 +267,7 @@ impl<'a> UpdateBuilder<'a> { }; // Get the extract_path from the provided executable_path - let extract_path = extract_path_from_executable(&executable_path); + let extract_path = extract_path_from_executable(&self.env, &executable_path); // Set SSL certs for linux if they aren't available. // We do not require to recheck in the download_and_install as we use @@ -357,6 +357,7 @@ impl<'a> UpdateBuilder<'a> { // create our new updater Ok(Update { + env: self.env, target, extract_path, should_update, @@ -372,12 +373,14 @@ impl<'a> UpdateBuilder<'a> { } } -pub fn builder<'a>() -> UpdateBuilder<'a> { - UpdateBuilder::new() +pub fn builder<'a>(env: Env) -> UpdateBuilder<'a> { + UpdateBuilder::new(env) } #[derive(Debug, Clone)] pub struct Update { + /// Environment information. + pub env: Env, /// Update description pub body: Option, /// Should we update or not @@ -418,7 +421,7 @@ impl Update { // be set with our APPIMAGE env variable, we don't need to do // anythin with it yet #[cfg(target_os = "linux")] - if env::var_os("APPIMAGE").is_none() { + if self.env.appimage.is_none() { return Err(Error::UnsupportedPlatform); } @@ -718,7 +721,7 @@ pub fn get_updater_target() -> Option { } /// Get the extract_path from the provided executable_path -pub fn extract_path_from_executable(executable_path: &Path) -> PathBuf { +pub fn extract_path_from_executable(env: &Env, executable_path: &Path) -> PathBuf { // Return the path of the current executable by default // Example C:\Program Files\My App\ let extract_path = executable_path @@ -748,7 +751,7 @@ pub fn extract_path_from_executable(executable_path: &Path) -> PathBuf { // We should use APPIMAGE exposed env variable // This is where our APPIMAGE should sit and should be replaced #[cfg(target_os = "linux")] - if let Some(app_image_path) = env::var_os("APPIMAGE") { + if let Some(app_image_path) = &env.appimage { return PathBuf::from(app_image_path); } @@ -905,9 +908,10 @@ mod test { #[cfg(target_os = "macos")] #[test] fn test_app_name_in_path() { - let executable = extract_path_from_executable(Path::new( - "/Applications/updater-example.app/Contents/MacOS/updater-example", - )); + let executable = extract_path_from_executable( + &crate::Env::default(), + Path::new("/Applications/updater-example.app/Contents/MacOS/updater-example"), + ); let app_name = macos_app_name_in_path(&executable); assert!(executable.ends_with("updater-example.app")); assert_eq!(app_name, "updater-example.app".to_string()); @@ -921,7 +925,7 @@ mod test { .with_body(generate_sample_raw_json()) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .current_version("0.0.0") .url(mockito::server_url()) .build()); @@ -940,7 +944,7 @@ mod test { .with_body(generate_sample_raw_json()) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .current_version("0.0.0") .url(mockito::server_url()) .build()); @@ -959,7 +963,7 @@ mod test { .with_body(generate_sample_raw_json()) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .current_version("0.0.0") .target("win64") .url(mockito::server_url()) @@ -985,7 +989,7 @@ mod test { .with_body(generate_sample_raw_json()) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .current_version("10.0.0") .url(mockito::server_url()) .build()); @@ -1008,7 +1012,7 @@ mod test { )) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .current_version("1.0.0") .url(format!( "{}/darwin/{{{{current_version}}}}", @@ -1035,7 +1039,7 @@ mod test { )) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .current_version("1.0.0") .url(format!( "{}/win64/{{{{current_version}}}}", @@ -1061,7 +1065,7 @@ mod test { )) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .current_version("10.0.0") .url(format!( "{}/darwin/{{{{current_version}}}}", @@ -1083,7 +1087,7 @@ mod test { .with_body(generate_sample_raw_json()) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .url("http://badurl.www.tld/1".into()) .url(mockito::server_url()) .current_version("0.0.1") @@ -1103,7 +1107,7 @@ mod test { .with_body(generate_sample_raw_json()) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .urls(&["http://badurl.www.tld/1".into(), mockito::server_url(),]) .current_version("0.0.1") .build()); @@ -1122,7 +1126,7 @@ mod test { .with_body(generate_sample_bad_json()) .create(); - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .url(mockito::server_url()) .current_version("0.0.1") .build()); @@ -1186,7 +1190,7 @@ mod test { let tmp_dir_path = tmp_dir_unwrap.path(); // configure the updater - let check_update = block!(builder() + let check_update = block!(builder(Default::default()) .url(mockito::server_url()) // It should represent the executable path, that's why we add my_app.exe in our // test path -- in production you shouldn't have to provide it diff --git a/core/tauri/src/updater/mod.rs b/core/tauri/src/updater/mod.rs index c31df31ad..180ac4d8f 100644 --- a/core/tauri/src/updater/mod.rs +++ b/core/tauri/src/updater/mod.rs @@ -336,7 +336,7 @@ use crate::{ api::{dialog::ask, process::restart}, runtime::Runtime, utils::config::UpdaterConfig, - Window, + Env, Manager, Window, }; use std::sync::mpsc::channel; @@ -381,8 +381,9 @@ pub(crate) async fn check_update_with_dialog( window: Window, ) { if let Some(endpoints) = updater_config.endpoints.clone() { + let env = window.state::().inner().clone(); // check updates - match self::core::builder() + match self::core::builder(env) .urls(&endpoints[..]) .current_version(&package_info.version) .build() @@ -448,8 +449,9 @@ pub(crate) fn listener( let window = window.clone(); let window_isolation = window.clone(); let pubkey = pubkey.clone(); + let env = window.state::().inner().clone(); - match self::core::builder() + match self::core::builder(env) .urls(&endpoints[..]) .current_version(&package_info.version) .build() @@ -558,13 +560,14 @@ Release Notes: updater.download_and_install(pubkey.clone()).await?; // Ask user if we need to restart the application + let env = window.state::().inner().clone(); ask( Some(&window), "Ready to Restart", "The installation was successful, do you want to restart the application now?", - |should_exit| { + move |should_exit| { if should_exit { - restart(); + restart(&env); } }, ); diff --git a/examples/resources/src-tauri/src/main.rs b/examples/resources/src-tauri/src/main.rs index 5840d0fde..e1e2b74e0 100644 --- a/examples/resources/src-tauri/src/main.rs +++ b/examples/resources/src-tauri/src/main.rs @@ -9,7 +9,7 @@ #[cfg(not(any(feature = "api-all", feature = "shell-all", feature = "shell-execute")))] fn main() { - eprintln!("Not supported without `api-all`, `shell-all` or `shell-execute`") + eprintln!("Not supported without `api-all`, `shell-all` and `shell-execute`") } #[cfg(any(feature = "api-all", feature = "shell-all", feature = "shell-execute"))] @@ -25,6 +25,7 @@ fn main() { let script_path = resolve_path( context.config(), context.package_info(), + &Default::default(), "assets/index.js", Some(BaseDirectory::Resource), )