mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-25 11:43:06 +03:00
refactor(core): load APPIMAGE and APPDIR env vars on startup [TRI-007] [TRI-041]
This commit is contained in:
parent
4de285c396
commit
7209fdf732
5
.changes/core-env.md
Normal file
5
.changes/core-env.md
Normal file
@ -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.
|
@ -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<std::ffi::OsString>,
|
||||
/// The APPDIR environment variable.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub appdir: Option<std::ffi::OsString>,
|
||||
}
|
||||
|
||||
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<T> = std::result::Result<T, Error>;
|
||||
|
||||
|
@ -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<String> {
|
||||
/// `${exe_dir}/../lib/${exe_name}`.
|
||||
///
|
||||
/// On MacOS, it's `${exe_dir}../Resources` (inside .app).
|
||||
pub fn resource_dir(package_info: &PackageInfo) -> crate::Result<PathBuf> {
|
||||
pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> crate::Result<PathBuf> {
|
||||
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<PathBuf> {
|
||||
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 {
|
||||
|
@ -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<P: AsRef<Path>>(
|
||||
config: &Config,
|
||||
package_info: &PackageInfo,
|
||||
env: &Env,
|
||||
path: P,
|
||||
dir: Option<BaseDirectory>,
|
||||
) -> crate::api::Result<PathBuf> {
|
||||
@ -113,7 +115,7 @@ pub fn resolve_path<P: AsRef<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<PathBuf> {
|
||||
}
|
||||
|
||||
/// Returns the path to the resource directory of this app.
|
||||
pub fn resource_dir(package_info: &PackageInfo) -> Option<PathBuf> {
|
||||
crate::utils::platform::resource_dir(package_info).ok()
|
||||
pub fn resource_dir(package_info: &PackageInfo, env: &Env) -> Option<PathBuf> {
|
||||
crate::utils::platform::resource_dir(package_info, env).ok()
|
||||
}
|
||||
|
||||
/// Returns the path to the suggested directory for your app config files.
|
||||
|
@ -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<PathBuf> {
|
||||
#[allow(unused_variables)]
|
||||
pub fn current_binary(env: &Env) -> Option<PathBuf> {
|
||||
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<PathBuf> {
|
||||
}
|
||||
|
||||
/// 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");
|
||||
|
@ -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<R: Runtime> GlobalWindowEvent<R> {
|
||||
/// The path resolver is a helper for the application-specific [`crate::api::path`] APIs.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PathResolver {
|
||||
env: Env,
|
||||
config: Arc<Config>,
|
||||
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<PathBuf> {
|
||||
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::<Env>().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::<Env>().inner().clone()
|
||||
}
|
||||
|
||||
/// The application's asset resolver.
|
||||
pub fn asset_resolver(&self) -> AssetResolver<R> {
|
||||
AssetResolver {
|
||||
@ -990,6 +997,8 @@ impl<R: Runtime> Builder<R> {
|
||||
},
|
||||
};
|
||||
|
||||
app.manage(Env::default());
|
||||
|
||||
#[cfg(feature = "system-tray")]
|
||||
if let Some(system_tray) = self.system_tray {
|
||||
let mut ids = HashMap::new();
|
||||
|
@ -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)
|
||||
}),
|
||||
|
@ -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<R: Runtime>(
|
||||
self,
|
||||
window: Window<R>,
|
||||
config: Arc<Config>,
|
||||
package_info: &PackageInfo,
|
||||
) -> crate::Result<InvokeResponse> {
|
||||
let env = window.state::<Env>().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<DirOperationOptions>,
|
||||
) -> crate::Result<Vec<dir::DiskEntry>> {
|
||||
@ -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<FileOperationOptions>,
|
||||
) -> 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<DirOperationOptions>,
|
||||
) -> 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<DirOperationOptions>,
|
||||
) -> 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<FileOperationOptions>,
|
||||
) -> 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<FileOperationOptions>,
|
||||
) -> 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<FileOperationOptions>,
|
||||
@ -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<FileOperationOptions>,
|
||||
@ -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<FileOperationOptions>,
|
||||
) -> crate::Result<String> {
|
||||
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<FileOperationOptions>,
|
||||
) -> crate::Result<Vec<u8>> {
|
||||
file::read_binary(resolve_path(
|
||||
config,
|
||||
package_info,
|
||||
env,
|
||||
path,
|
||||
options.and_then(|o| o.dir),
|
||||
)?)
|
||||
|
@ -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<Invo
|
||||
}
|
||||
|
||||
#[cfg(notification_all)]
|
||||
pub fn is_permission_granted(
|
||||
pub fn is_permission_granted<R: Runtime>(
|
||||
window: &Window<R>,
|
||||
config: &Config,
|
||||
package_info: &PackageInfo,
|
||||
) -> crate::Result<InvokeResponse> {
|
||||
let settings = crate::settings::read_settings(config, package_info);
|
||||
let settings =
|
||||
crate::settings::read_settings(config, package_info, window.state::<Env>().inner());
|
||||
if let Some(allow_notification) = settings.allow_notification {
|
||||
Ok(allow_notification.into())
|
||||
} else {
|
||||
@ -102,7 +104,8 @@ pub fn request_permission<R: Runtime>(
|
||||
config: &Config,
|
||||
package_info: &PackageInfo,
|
||||
) -> crate::Result<String> {
|
||||
let mut settings = crate::settings::read_settings(config, package_info);
|
||||
let mut settings =
|
||||
crate::settings::read_settings(config, package_info, window.state::<Env>().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<R: Runtime>(
|
||||
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::<Env>().inner(),
|
||||
settings,
|
||||
)?;
|
||||
|
||||
if answer {
|
||||
Ok(PERMISSION_GRANTED.to_string())
|
||||
|
@ -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<R: Runtime>(
|
||||
self,
|
||||
window: Window<R>,
|
||||
config: Arc<Config>,
|
||||
package_info: &PackageInfo,
|
||||
) -> crate::Result<InvokeResponse> {
|
||||
#[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::<Env>().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<BaseDirectory>,
|
||||
) -> crate::Result<PathBuf> {
|
||||
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)]
|
||||
|
@ -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<InvokeResponse> {
|
||||
pub fn run<R: Runtime>(self, window: Window<R>) -> crate::Result<InvokeResponse> {
|
||||
match self {
|
||||
Self::Relaunch => Ok({
|
||||
restart();
|
||||
restart(&window.state());
|
||||
().into()
|
||||
}),
|
||||
Self::Exit { exit_code } => {
|
||||
|
@ -108,7 +108,7 @@ pub use {
|
||||
self::utils::{
|
||||
assets::Assets,
|
||||
config::{Config, WindowUrl},
|
||||
PackageInfo,
|
||||
Env, PackageInfo,
|
||||
},
|
||||
self::window::{Monitor, Window},
|
||||
};
|
||||
|
@ -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<PathBuf> {
|
||||
fn get_settings_path(
|
||||
config: &Config,
|
||||
package_info: &PackageInfo,
|
||||
env: &Env,
|
||||
) -> crate::api::Result<PathBuf> {
|
||||
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))
|
||||
|
@ -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<PathBuf>,
|
||||
}
|
||||
|
||||
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<String>,
|
||||
/// 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<String> {
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
@ -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<R: Runtime>(
|
||||
window: Window<R>,
|
||||
) {
|
||||
if let Some(endpoints) = updater_config.endpoints.clone() {
|
||||
let env = window.state::<Env>().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<R: Runtime>(
|
||||
let window = window.clone();
|
||||
let window_isolation = window.clone();
|
||||
let pubkey = pubkey.clone();
|
||||
let env = window.state::<Env>().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::<Env>().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);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -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),
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user