chore: edition 2024

This commit is contained in:
Lucas Nogueira
2026-09-26 15:36:22 -03:00
parent b517cc7e85
commit 3d8a3c877b
100 changed files with 276 additions and 253 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ glob = "0.3"
zbus = "5.9" zbus = "5.9"
[workspace.package] [workspace.package]
edition = "2021" edition = "2024"
authors = ["Tauri Programme within The Commons Conservancy"] authors = ["Tauri Programme within The Commons Conservancy"]
license = "Apache-2.0 OR MIT" license = "Apache-2.0 OR MIT"
rust-version = "1.90" rust-version = "1.90"
+1 -1
View File
@@ -3,7 +3,7 @@ name = "api"
publish = false publish = false
version = "2.0.49" version = "2.0.49"
description = "An example Tauri Application showcasing the api" description = "An example Tauri Application showcasing the api"
edition = "2021" edition = "2024"
rust-version = { workspace = true } rust-version = { workspace = true }
license = "Apache-2.0 OR MIT" license = "Apache-2.0 OR MIT"
+3 -4
View File
@@ -8,8 +8,8 @@ mod tray;
use serde::Serialize; use serde::Serialize;
use tauri::{ use tauri::{
webview::{PageLoadEvent, WebviewWindowBuilder},
App, AppHandle, Emitter, Listener, RunEvent, WebviewUrl, App, AppHandle, Emitter, Listener, RunEvent, WebviewUrl,
webview::{PageLoadEvent, WebviewWindowBuilder},
}; };
#[derive(Clone, Serialize)] #[derive(Clone, Serialize)]
@@ -204,12 +204,11 @@ pub fn run() {
app.run(move |_app_handle, _event| { app.run(move |_app_handle, _event| {
#[cfg(desktop)] #[cfg(desktop)]
if let RunEvent::ExitRequested { code, api, .. } = &_event { if let RunEvent::ExitRequested { code, api, .. } = &_event
if code.is_none() { && code.is_none() {
// Keep the event loop running even if all windows are closed // Keep the event loop running even if all windows are closed
// This allow us to catch system tray events when there is no window // This allow us to catch system tray events when there is no window
api.prevent_exit(); api.prevent_exit();
} }
}
}) })
} }
+1 -1
View File
@@ -4,9 +4,9 @@
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use tauri::{ use tauri::{
Manager, Runtime, WebviewUrl, WebviewWindowBuilder,
menu::{Menu, MenuItem}, menu::{Menu, MenuItem},
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
Manager, Runtime, WebviewUrl, WebviewWindowBuilder,
}; };
pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> { pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
+2 -3
View File
@@ -11,11 +11,10 @@
#![cfg(not(any(target_os = "android", target_os = "ios")))] #![cfg(not(any(target_os = "android", target_os = "ios")))]
use auto_launch::{AutoLaunch, AutoLaunchBuilder}; use auto_launch::{AutoLaunch, AutoLaunchBuilder};
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
use tauri::{ use tauri::{
command, Manager, Runtime, State, command,
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
Manager, Runtime, State,
}; };
use std::env::current_exe; use std::env::current_exe;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for the result type returned by this crate's functions. /// Alias for the result type returned by this crate's functions.
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+1 -1
View File
@@ -9,8 +9,8 @@
#![cfg(mobile)] #![cfg(mobile)]
use tauri::{ use tauri::{
plugin::{Builder, PluginHandle, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, PluginHandle, TauriPlugin},
}; };
pub use models::*; pub use models::*;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for a [`Result`](std::result::Result) with the error type [`Error`]. /// Alias for a [`Result`](std::result::Result) with the error type [`Error`].
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+1 -1
View File
@@ -10,8 +10,8 @@
use serde::Serialize; use serde::Serialize;
use tauri::{ use tauri::{
plugin::{Builder, PluginHandle, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, PluginHandle, TauriPlugin},
}; };
pub use models::*; pub use models::*;
+1 -1
View File
@@ -12,8 +12,8 @@
)] )]
use tauri::{ use tauri::{
plugin::{Builder, PluginApi, TauriPlugin},
AppHandle, Manager, Runtime, State, AppHandle, Manager, Runtime, State,
plugin::{Builder, PluginApi, TauriPlugin},
}; };
mod config; mod config;
+3 -4
View File
@@ -3,9 +3,9 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use clap::{ use clap::{
Arg as ClapArg, ArgAction, ArgMatches, Command,
builder::{PossibleValue, PossibleValuesParser}, builder::{PossibleValue, PossibleValuesParser},
error::ErrorKind, error::ErrorKind,
Arg as ClapArg, ArgAction, ArgMatches, Command,
}; };
use serde::Serialize; use serde::Serialize;
use serde_json::Value; use serde_json::Value;
@@ -134,8 +134,8 @@ fn get_matches_internal(config: &Config, matches: &ArgMatches) -> Matches {
let mut cli_matches = Matches::default(); let mut cli_matches = Matches::default();
map_matches(config, matches, &mut cli_matches); map_matches(config, matches, &mut cli_matches);
if let Some((subcommand_name, subcommand_matches)) = matches.subcommand() { if let Some((subcommand_name, subcommand_matches)) = matches.subcommand()
if let Some(subcommand_config) = config && let Some(subcommand_config) = config
.subcommands .subcommands
.as_ref() .as_ref()
.and_then(|s| s.get(subcommand_name)) .and_then(|s| s.get(subcommand_name))
@@ -145,7 +145,6 @@ fn get_matches_internal(config: &Config, matches: &ArgMatches) -> Matches {
get_matches_internal(subcommand_config, subcommand_matches), get_matches_internal(subcommand_config, subcommand_matches),
); );
} }
}
cli_matches cli_matches
} }
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use tauri::{command, image::JsImage, AppHandle, Manager, ResourceId, Runtime, State, Webview}; use tauri::{AppHandle, Manager, ResourceId, Runtime, State, Webview, command, image::JsImage};
use crate::{Clipboard, Result}; use crate::{Clipboard, Result};
+1 -1
View File
@@ -4,7 +4,7 @@
use arboard::ImageData; use arboard::ImageData;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tauri::{image::Image, plugin::PluginApi, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, image::Image, plugin::PluginApi};
use std::{borrow::Cow, sync::Mutex}; use std::{borrow::Cow, sync::Mutex};
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for `Result<T, Error>` used throughout this crate. /// Alias for `Result<T, Error>` used throughout this crate.
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+1 -1
View File
@@ -10,8 +10,8 @@
)] )]
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Manager, RunEvent, Runtime, Manager, RunEvent, Runtime,
plugin::{Builder, TauriPlugin},
}; };
#[cfg(desktop)] #[cfg(desktop)]
+1 -1
View File
@@ -5,9 +5,9 @@
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
AppHandle, Runtime,
image::Image, image::Image,
plugin::{PluginApi, PluginHandle}, plugin::{PluginApi, PluginHandle},
AppHandle, Runtime,
}; };
use std::borrow::Cow; use std::borrow::Cow;
@@ -5,7 +5,7 @@ description = "A Tauri App"
authors = ["you"] authors = ["you"]
license = "" license = ""
repository = "" repository = ""
edition = "2021" edition = "2024"
rust-version = "1.90" rust-version = "1.90"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use tauri::{command, AppHandle, Runtime, State, Window}; use tauri::{AppHandle, Runtime, State, Window, command};
use crate::{DeepLink, Result}; use crate::{DeepLink, Result};
+5 -4
View File
@@ -50,7 +50,9 @@ impl AssociatedDomain {
} }
if self.scheme.iter().any(|s| s == "http") && !self.scheme.iter().any(|s| s == "https") if self.scheme.iter().any(|s| s == "http") && !self.scheme.iter().any(|s| s == "https")
{ {
eprintln!("Warning: AppLink uses only 'http' — allowed on Android but not secure for production."); eprintln!(
"Warning: AppLink uses only 'http' — allowed on Android but not secure for production."
);
} }
} }
@@ -68,13 +70,12 @@ where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let opt = Option::<String>::deserialize(deserializer)?; let opt = Option::<String>::deserialize(deserializer)?;
if let Some(ref host) = opt { if let Some(ref host) = opt
if let Some((scheme, _)) = host.split_once("://") { && let Some((scheme, _)) = host.split_once("://") {
return Err(serde::de::Error::custom(format!( return Err(serde::de::Error::custom(format!(
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix" "host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
))); )));
} }
}
Ok(opt) Ok(opt)
} }
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for a [`Result`](std::result::Result) with the error type [`Error`]. /// Alias for a [`Result`](std::result::Result) with the error type [`Error`].
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+13 -12
View File
@@ -11,8 +11,8 @@
//! calling those methods returns [`Error::UnsupportedPlatform`]. //! calling those methods returns [`Error::UnsupportedPlatform`].
use tauri::{ use tauri::{
plugin::{Builder, PluginApi, TauriPlugin},
AppHandle, EventId, Listener, Manager, Runtime, AppHandle, EventId, Listener, Manager, Runtime,
plugin::{Builder, PluginApi, TauriPlugin},
}; };
mod commands; mod commands;
@@ -33,8 +33,8 @@ fn init_deep_link<R: Runtime>(
let _api = api; let _api = api;
use tauri::{ use tauri::{
ipc::{Channel, InvokeResponseBody},
Emitter, Emitter,
ipc::{Channel, InvokeResponseBody},
}; };
let handle = _api.register_android_plugin(PLUGIN_IDENTIFIER, "DeepLinkPlugin")?; let handle = _api.register_android_plugin(PLUGIN_IDENTIFIER, "DeepLinkPlugin")?;
@@ -94,7 +94,7 @@ fn init_deep_link<R: Runtime>(
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
mod imp { mod imp {
use tauri::{ipc::Channel, plugin::PluginHandle, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, ipc::Channel, plugin::PluginHandle};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -172,7 +172,7 @@ mod imp {
use std::sync::Mutex; use std::sync::Mutex;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use std::{ use std::{
fs::{create_dir_all, File}, fs::{File, create_dir_all},
io::Write, io::Write,
process::Command, process::Command,
}; };
@@ -223,7 +223,9 @@ mod imp {
current.replace(vec![url.clone()]); current.replace(vec![url.clone()]);
let _ = self.app.emit("deep-link://new-url", vec![url]); let _ = self.app.emit("deep-link://new-url", vec![url]);
} else if cfg!(debug_assertions) { } else if cfg!(debug_assertions) {
tracing::warn!("argument {url} does not match any configured deep link scheme; skipping it"); tracing::warn!(
"argument {url} does not match any configured deep link scheme; skipping it"
);
} }
} }
} }
@@ -414,11 +416,10 @@ mod imp {
let mimeapps_path = self.app.path().config_dir()?.join("mimeapps.list"); let mimeapps_path = self.app.path().config_dir()?.join("mimeapps.list");
if mimeapps_path.exists() { if mimeapps_path.exists() {
let mut mimeapps = ini::Ini::load_from_file(&mimeapps_path)?; let mut mimeapps = ini::Ini::load_from_file(&mimeapps_path)?;
if let Some(section) = mimeapps.section_mut(Some("Default Applications")) { if let Some(section) = mimeapps.section_mut(Some("Default Applications"))
if section.get(&mime_type).unwrap_or_default() == file_name { && section.get(&mime_type).unwrap_or_default() == file_name {
section.remove(&mime_type); section.remove(&mime_type);
} }
}
mimeapps.write_to_file(&mimeapps_path)?; mimeapps.write_to_file(&mimeapps_path)?;
} }
@@ -558,16 +559,16 @@ impl<R: Runtime> DeepLink<R> {
/// ///
/// Use `get_current` on app load to check whether your app was started via a deep link. /// Use `get_current` on app load to check whether your app was started via a deep link.
pub fn on_open_url<F: Fn(OpenUrlEvent) + Send + Sync + 'static>(&self, f: F) -> EventId { pub fn on_open_url<F: Fn(OpenUrlEvent) + Send + Sync + 'static>(&self, f: F) -> EventId {
let event_id = self.app.listen("deep-link://new-url", move |event| {
self.app.listen("deep-link://new-url", move |event| {
if let Ok(urls) = serde_json::from_str(event.payload()) { if let Ok(urls) = serde_json::from_str(event.payload()) {
f(OpenUrlEvent { f(OpenUrlEvent {
id: event.id(), id: event.id(),
urls, urls,
}) })
} }
}); })
event_id
} }
} }
+7 -10
View File
@@ -5,7 +5,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{command, Manager, Runtime, State, Window}; use tauri::{Manager, Runtime, State, Window, command};
use tauri_plugin_fs::FsExt; use tauri_plugin_fs::FsExt;
use crate::{ use crate::{
@@ -171,14 +171,13 @@ pub(crate) async fn open<R: Runtime>(
) )
} else { } else {
let folder = dialog_builder.blocking_pick_folder(); let folder = dialog_builder.blocking_pick_folder();
if let Some(folder) = &folder { if let Some(folder) = &folder
if let Ok(path) = folder.clone().into_path() { && let Ok(path) = folder.clone().into_path() {
if let Some(s) = window.try_fs_scope() { if let Some(s) = window.try_fs_scope() {
s.allow_directory(&path, options.recursive)?; s.allow_directory(&path, options.recursive)?;
} }
tauri_scope.allow_directory(&path, options.directory)?; tauri_scope.allow_directory(&path, options.directory)?;
} }
}
OpenResponse::Folder(folder.map(|p| p.simplified())) OpenResponse::Folder(folder.map(|p| p.simplified()))
} }
} }
@@ -204,14 +203,13 @@ pub(crate) async fn open<R: Runtime>(
let tauri_scope = window.state::<tauri::scope::Scopes>(); let tauri_scope = window.state::<tauri::scope::Scopes>();
let file = dialog_builder.blocking_pick_file(); let file = dialog_builder.blocking_pick_file();
if let Some(file) = &file { if let Some(file) = &file
if let Ok(path) = file.clone().into_path() { && let Ok(path) = file.clone().into_path() {
if let Some(s) = window.try_fs_scope() { if let Some(s) = window.try_fs_scope() {
s.allow_file(&path)?; s.allow_file(&path)?;
} }
tauri_scope.allow_file(&path)?; tauri_scope.allow_file(&path)?;
} }
}
OpenResponse::File(file.map(|f| f.simplified())) OpenResponse::File(file.map(|f| f.simplified()))
}; };
Ok(res) Ok(res)
@@ -246,14 +244,13 @@ pub(crate) async fn save<R: Runtime>(
let tauri_scope = window.state::<tauri::scope::Scopes>(); let tauri_scope = window.state::<tauri::scope::Scopes>();
let path = dialog_builder.blocking_save_file(); let path = dialog_builder.blocking_save_file();
if let Some(p) = &path { if let Some(p) = &path
if let Ok(path) = p.clone().into_path() { && let Ok(path) = p.clone().into_path() {
if let Some(s) = window.try_fs_scope() { if let Some(s) = window.try_fs_scope() {
s.allow_file(&path)?; s.allow_file(&path)?;
} }
tauri_scope.allow_file(&path)?; tauri_scope.allow_file(&path)?;
} }
}
Ok(path.map(|p| p.simplified())) Ok(path.map(|p| p.simplified()))
} }
+2 -2
View File
@@ -11,9 +11,9 @@
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
use rfd::{AsyncFileDialog, AsyncMessageDialog}; use rfd::{AsyncFileDialog, AsyncMessageDialog};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, plugin::PluginApi};
use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder}; use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, models::*};
pub fn init<R: Runtime, C: DeserializeOwned>( pub fn init<R: Runtime, C: DeserializeOwned>(
app: &AppHandle<R>, app: &AppHandle<R>,
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for `Result<T, Error>` used throughout this crate. /// Alias for `Result<T, Error>` used throughout this crate.
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+1 -1
View File
@@ -16,8 +16,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, TauriPlugin},
}; };
use std::{ use std::{
+2 -2
View File
@@ -2,10 +2,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{de::DeserializeOwned, Deserialize}; use serde::{Deserialize, de::DeserializeOwned};
use tauri::{ use tauri::{
plugin::{PluginApi, PluginHandle},
AppHandle, Runtime, AppHandle, Runtime,
plugin::{PluginApi, PluginHandle},
}; };
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogResult}; use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogResult};
+2 -2
View File
@@ -3,9 +3,9 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, plugin::PluginApi};
use crate::{models::*, FilePath, OpenOptions}; use crate::{FilePath, OpenOptions, models::*};
const PLUGIN_IDENTIFIER: &str = "com.plugin.fs"; const PLUGIN_IDENTIFIER: &str = "com.plugin.fs";
+20 -7
View File
@@ -6,10 +6,10 @@
use serde::{Deserialize, Serialize, Serializer}; use serde::{Deserialize, Serialize, Serializer};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use tauri::{ use tauri::{
Manager, Resource, ResourceId, Runtime, Webview,
ipc::{CommandScope, GlobalScope}, ipc::{CommandScope, GlobalScope},
path::BaseDirectory, path::BaseDirectory,
utils::config::FsScope, utils::config::FsScope,
Manager, Resource, ResourceId, Runtime, Webview,
}; };
use std::{ use std::{
@@ -23,7 +23,7 @@ use std::{
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
use crate::{scope::Entry, Error, SafeFilePath}; use crate::{Error, SafeFilePath, scope::Entry};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum CommandError { pub enum CommandError {
@@ -175,7 +175,9 @@ impl<R: Runtime> Drop for FileHandle<R> {
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone())); .stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
security_scoped_resources.remove(url.as_str()); security_scoped_resources.remove(url.as_str());
} else { } else {
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)"); log::debug!(
"Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)"
);
} }
} }
} }
@@ -251,7 +253,9 @@ impl<R: Runtime> Drop for PathHandle<R> {
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone())); .stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
security_scoped_resources.remove(url.as_str()); security_scoped_resources.remove(url.as_str());
} else { } else {
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)"); log::debug!(
"Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)"
);
} }
} }
} }
@@ -1530,7 +1534,10 @@ pub fn resolve_path<R: Runtime>(
unsafe { unsafe {
let success = ns_url.startAccessingSecurityScopedResource(); let success = ns_url.startAccessingSecurityScopedResource();
if success { if success {
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str()); log::debug!(
"Started accessing security-scoped resource for URL: {} (via resolve_path)",
url.as_str()
);
// Track it so we know to clean it up // Track it so we know to clean it up
security_scoped_resources.track_manually(url.as_str().to_string()); security_scoped_resources.track_manually(url.as_str().to_string());
} else { } else {
@@ -1541,10 +1548,16 @@ pub fn resolve_path<R: Runtime>(
} }
} }
} else { } else {
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str()); log::debug!(
"Failed to create NSURL from URL: {}, ignoring security-scoped resource access request",
url.as_str()
);
} }
} else { } else {
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str()); log::debug!(
"Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping",
url.as_str()
);
} }
} }
} }
+4 -6
View File
@@ -190,11 +190,10 @@ impl<'de> serde::Deserialize<'de> for SafeFilePath {
impl FromStr for FilePath { impl FromStr for FilePath {
type Err = Infallible; type Err = Infallible;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
if let Ok(url) = url::Url::from_str(s) { if let Ok(url) = url::Url::from_str(s)
if url.scheme().len() != 1 { && url.scheme().len() != 1 {
return Ok(Self::Url(url)); return Ok(Self::Url(url));
} }
}
Ok(Self::Path(PathBuf::from(s))) Ok(Self::Path(PathBuf::from(s)))
} }
} }
@@ -202,11 +201,10 @@ impl FromStr for FilePath {
impl FromStr for SafeFilePath { impl FromStr for SafeFilePath {
type Err = Error; type Err = Error;
fn from_str(s: &str) -> Result<Self> { fn from_str(s: &str) -> Result<Self> {
if let Ok(url) = url::Url::from_str(s) { if let Ok(url) = url::Url::from_str(s)
if url.scheme().len() != 1 { && url.scheme().len() != 1 {
return Ok(Self::Url(url)); return Ok(Self::Url(url));
} }
}
SafePathBuf::new(s.into()) SafePathBuf::new(s.into())
.map(SafeFilePath::Path) .map(SafeFilePath::Path)
+5 -2
View File
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, plugin::PluginApi};
use crate::{FilePath, OpenOptions}; use crate::{FilePath, OpenOptions};
@@ -69,7 +69,10 @@ impl<R: Runtime> Fs<R> {
} }
} }
} else { } else {
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url_string); log::debug!(
"Failed to create NSURL from URL: {}, ignoring security-scoped resource access request",
url_string
);
} }
// Convert URL to path and open the file // Convert URL to path and open the file
+1 -1
View File
@@ -22,10 +22,10 @@ use std::sync::Mutex;
use serde::Deserialize; use serde::Deserialize;
use tauri::{ use tauri::{
AppHandle, DragDropEvent, Manager, RunEvent, Runtime, WindowEvent,
ipc::ScopeObject, ipc::ScopeObject,
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
utils::{acl::Value, config::FsScope}, utils::{acl::Value, config::FsScope},
AppHandle, DragDropEvent, Manager, RunEvent, Runtime, WindowEvent,
}; };
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
+4 -4
View File
@@ -3,20 +3,20 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher}; use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use notify_debouncer_full::{new_debouncer, DebouncedEvent, Debouncer, RecommendedCache}; use notify_debouncer_full::{DebouncedEvent, Debouncer, RecommendedCache, new_debouncer};
use serde::Deserialize; use serde::Deserialize;
use tauri::{ use tauri::{
Manager, Resource, ResourceId, Runtime, Webview,
ipc::{Channel, CommandScope, GlobalScope}, ipc::{Channel, CommandScope, GlobalScope},
path::BaseDirectory, path::BaseDirectory,
Manager, Resource, ResourceId, Runtime, Webview,
}; };
use std::time::Duration; use std::time::Duration;
use crate::{ use crate::{
commands::{resolve_path, CommandResult},
scope::Entry,
SafeFilePath, SafeFilePath,
commands::{CommandResult, resolve_path},
scope::Entry,
}; };
#[allow(unused)] #[allow(unused)]
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use tauri::{command, ipc::Channel, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, command, ipc::Channel};
use crate::{GeolocationExt, PermissionStatus, PermissionType, Position, PositionOptions, Result}; use crate::{GeolocationExt, PermissionStatus, PermissionType, Position, PositionOptions, Result};
+2 -2
View File
@@ -2,11 +2,11 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{de::DeserializeOwned, Serialize}; use serde::{Serialize, de::DeserializeOwned};
use tauri::{ use tauri::{
AppHandle, Runtime,
ipc::{Channel, InvokeResponseBody}, ipc::{Channel, InvokeResponseBody},
plugin::PluginApi, plugin::PluginApi,
AppHandle, Runtime,
}; };
use crate::models::*; use crate::models::*;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for the result type returned by the geolocation APIs. /// Alias for the result type returned by the geolocation APIs.
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+1 -1
View File
@@ -9,8 +9,8 @@
//! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`PermissionStatus`], [`PositionOptions`]. //! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`PermissionStatus`], [`PositionOptions`].
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, TauriPlugin},
}; };
pub use models::*; pub use models::*;
+2 -2
View File
@@ -2,11 +2,11 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{de::DeserializeOwned, Serialize}; use serde::{Serialize, de::DeserializeOwned};
use tauri::{ use tauri::{
AppHandle, Runtime,
ipc::{Channel, InvokeResponseBody}, ipc::{Channel, InvokeResponseBody},
plugin::{PluginApi, PluginHandle}, plugin::{PluginApi, PluginHandle},
AppHandle, Runtime,
}; };
use crate::models::*; use crate::models::*;
+2 -2
View File
@@ -22,14 +22,14 @@ use std::{
use global_hotkey::GlobalHotKeyEvent; use global_hotkey::GlobalHotKeyEvent;
pub use global_hotkey::{ pub use global_hotkey::{
hotkey::{Code, HotKey as Shortcut, Modifiers},
GlobalHotKeyEvent as ShortcutEvent, HotKeyState as ShortcutState, GlobalHotKeyEvent as ShortcutEvent, HotKeyState as ShortcutState,
hotkey::{Code, HotKey as Shortcut, Modifiers},
}; };
use serde::Serialize; use serde::Serialize;
use tauri::{ use tauri::{
AppHandle, Manager, Runtime, State,
ipc::Channel, ipc::Channel,
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
AppHandle, Manager, Runtime, State,
}; };
mod error; mod error;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use tauri::{command, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, command};
use crate::{HapticsExt, ImpactFeedbackStyle, NotificationFeedbackType, Result}; use crate::{HapticsExt, ImpactFeedbackStyle, NotificationFeedbackType, Result};
+1 -1
View File
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime}; use tauri::{AppHandle, Runtime, plugin::PluginApi};
use crate::models::*; use crate::models::*;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for a [`std::result::Result`] with the error type [`Error`]. /// Alias for a [`std::result::Result`] with the error type [`Error`].
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+1 -1
View File
@@ -9,8 +9,8 @@
//! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`ImpactFeedbackStyle`], [`NotificationFeedbackType`]. //! - **specta**: Add support for [`specta::specta`](https://docs.rs/specta/2.0.0-rc.25/specta/attr.specta.html) on structs like [`ImpactFeedbackStyle`], [`NotificationFeedbackType`].
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, TauriPlugin},
}; };
pub use models::*; pub use models::*;
+2 -2
View File
@@ -2,10 +2,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{de::DeserializeOwned, Serialize}; use serde::{Serialize, de::DeserializeOwned};
use tauri::{ use tauri::{
plugin::{PluginApi, PluginHandle},
AppHandle, Runtime, AppHandle, Runtime,
plugin::{PluginApi, PluginHandle},
}; };
use crate::models::*; use crate::models::*;
+20 -13
View File
@@ -4,20 +4,20 @@
use std::{future::Future, pin::Pin, str::FromStr, sync::Arc, time::Duration}; use std::{future::Future, pin::Pin, str::FromStr, sync::Arc, time::Duration};
use http::{header, HeaderMap, HeaderName, HeaderValue, Method, StatusCode}; use http::{HeaderMap, HeaderName, HeaderValue, Method, StatusCode, header};
use reqwest::{redirect::Policy, NoProxy}; use reqwest::{NoProxy, redirect::Policy};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
Manager, ResourceId, ResourceTable, Runtime, State, Webview,
async_runtime::Mutex, async_runtime::Mutex,
command, command,
ipc::{CommandScope, GlobalScope}, ipc::{CommandScope, GlobalScope},
Manager, ResourceId, ResourceTable, Runtime, State, Webview,
}; };
use tokio::sync::oneshot::{channel, Receiver, Sender}; use tokio::sync::oneshot::{Receiver, Sender, channel};
use crate::{ use crate::{
scope::{Entry, Scope},
Error, Http, Result, Error, Http, Result,
scope::{Entry, Scope},
}; };
const HTTP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); const HTTP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
@@ -257,8 +257,12 @@ pub async fn fetch<R: Runtime>(
if is_unsafe_header(&name) { if is_unsafe_header(&name) {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
eprintln!("[\x1b[33mWARNING\x1b[0m] Skipping {name} header as it is a forbidden header per fetch spec https://fetch.spec.whatwg.org/#terminology-headers"); eprintln!(
eprintln!("[\x1b[33mWARNING\x1b[0m] if keeping the header is a desired behavior, you can enable `unsafe-headers` feature flag in your Cargo.toml"); "[\x1b[33mWARNING\x1b[0m] Skipping {name} header as it is a forbidden header per fetch spec https://fetch.spec.whatwg.org/#terminology-headers"
);
eprintln!(
"[\x1b[33mWARNING\x1b[0m] if keeping the header is a desired behavior, you can enable `unsafe-headers` feature flag in your Cargo.toml"
);
} }
continue; continue;
} }
@@ -294,7 +298,9 @@ pub async fn fetch<R: Runtime>(
{ {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
eprintln!("[\x1b[33mWARNING\x1b[0m] using dangerous settings requires `dangerous-settings` feature flag in your Cargo.toml"); eprintln!(
"[\x1b[33mWARNING\x1b[0m] using dangerous settings requires `dangerous-settings` feature flag in your Cargo.toml"
);
} }
let _ = danger_config; let _ = danger_config;
return Err(Error::DangerousSettings); return Err(Error::DangerousSettings);
@@ -342,8 +348,8 @@ pub async fn fetch<R: Runtime>(
} }
// ensure we have an Origin header set // ensure we have an Origin header set
if cfg!(not(feature = "unsafe-headers")) || !headers.contains_key(header::ORIGIN) { if (cfg!(not(feature = "unsafe-headers")) || !headers.contains_key(header::ORIGIN))
if let Ok(url) = webview.url() { && let Ok(url) = webview.url() {
// The url crate returns OpaqueOrigin for tauri://localhost which serializes to "null" // The url crate returns OpaqueOrigin for tauri://localhost which serializes to "null"
let origin = if url.scheme() == "tauri" { let origin = if url.scheme() == "tauri" {
"tauri://localhost".to_string() "tauri://localhost".to_string()
@@ -352,7 +358,6 @@ pub async fn fetch<R: Runtime>(
}; };
headers.append(header::ORIGIN, HeaderValue::from_str(&origin)?); headers.append(header::ORIGIN, HeaderValue::from_str(&origin)?);
} }
}
// In case empty origin is passed, remove it. Some services do not like Origin header // In case empty origin is passed, remove it. Some services do not like Origin header
// so this way we can remove it in explicit way. The default behaviour is still to set it // so this way we can remove it in explicit way. The default behaviour is still to set it
@@ -593,8 +598,10 @@ mod tests {
Some(location) => format!( Some(location) => format!(
"HTTP/1.1 302 Found\r\nLocation: {location}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" "HTTP/1.1 302 Found\r\nLocation: {location}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
), ),
None => "HTTP/1.1 200 OK\r\nContent-Length: 6\r\nConnection: close\r\n\r\nsecret" None => {
.to_string(), "HTTP/1.1 200 OK\r\nContent-Length: 6\r\nConnection: close\r\n\r\nsecret"
.to_string()
}
}; };
let _ = stream.write_all(response.as_bytes()); let _ = stream.write_all(response.as_bytes());
+1 -1
View File
@@ -61,8 +61,8 @@
pub use reqwest; pub use reqwest;
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, TauriPlugin},
}; };
pub use config::Config; pub use config::Config;
+1 -1
View File
@@ -6,7 +6,7 @@
use std::{ use std::{
path::PathBuf, path::PathBuf,
sync::{mpsc::Receiver, Mutex}, sync::{Mutex, mpsc::Receiver},
}; };
use cookie_store::{CookieStore, RawCookie, RawCookieParseError}; use cookie_store::{CookieStore, RawCookie, RawCookieParseError};
+14 -10
View File
@@ -154,11 +154,13 @@ mod tests {
assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap())); assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
assert!(scope.is_allowed(&"http://localhost:8080/file.png#head".parse().unwrap())); assert!(scope.is_allowed(&"http://localhost:8080/file.png#head".parse().unwrap()));
assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap())); assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap()));
assert!(scope.is_allowed( assert!(
&"http://localhost:8080/assets/file.png?width=100&height=200" scope.is_allowed(
.parse() &"http://localhost:8080/assets/file.png?width=100&height=200"
.unwrap() .parse()
)); .unwrap()
)
);
assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap())); assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap()));
} }
@@ -172,11 +174,13 @@ mod tests {
assert!(scope.is_allowed(&"http://something.else#tauri".parse().unwrap())); assert!(scope.is_allowed(&"http://something.else#tauri".parse().unwrap()));
assert!(scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap())); assert!(scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap()));
assert!(scope.is_allowed(&"http://something.else?rel=tauri".parse().unwrap())); assert!(scope.is_allowed(&"http://something.else?rel=tauri".parse().unwrap()));
assert!(scope.is_allowed( assert!(
&"http://something.else/path/to/file.mp4?start=500" scope.is_allowed(
.parse() &"http://something.else/path/to/file.mp4?start=500"
.unwrap() .parse()
)); .unwrap()
)
);
assert!(!scope.is_allowed(&"https://something.else".parse().unwrap())); assert!(!scope.is_allowed(&"https://something.else".parse().unwrap()));
+1 -1
View File
@@ -15,8 +15,8 @@ use std::collections::HashMap;
use http::Uri; use http::Uri;
use tauri::{ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin},
Runtime, Runtime,
plugin::{Builder as PluginBuilder, TauriPlugin},
}; };
use tiny_http::{Header, Response as HttpResponse, Server}; use tiny_http::{Header, Response as HttpResponse, Server};
+5 -5
View File
@@ -27,12 +27,12 @@ use std::{
iter::FromIterator, iter::FromIterator,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use tauri::{
plugin::{self, TauriPlugin},
Manager, Runtime,
};
use tauri::{AppHandle, Emitter}; use tauri::{AppHandle, Emitter};
use time::{macros::format_description, OffsetDateTime}; use tauri::{
Manager, Runtime,
plugin::{self, TauriPlugin},
};
use time::{OffsetDateTime, macros::format_description};
pub use fern; pub use fern;
pub use log; pub use log;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for a [`std::result::Result`] with the error type [`Error`]. /// Alias for a [`std::result::Result`] with the error type [`Error`].
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+1 -1
View File
@@ -14,8 +14,8 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
plugin::{Builder, PluginHandle, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, PluginHandle, TauriPlugin},
}; };
pub use models::*; pub use models::*;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use tauri::{command, plugin::PermissionState, AppHandle, Runtime, State}; use tauri::{AppHandle, Runtime, State, command, plugin::PermissionState};
use crate::{Notification, NotificationData, Result}; use crate::{Notification, NotificationData, Result};
+1 -1
View File
@@ -4,8 +4,8 @@
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tauri::{ use tauri::{
plugin::{PermissionState, PluginApi},
AppHandle, Runtime, AppHandle, Runtime,
plugin::{PermissionState, PluginApi},
}; };
use crate::NotificationBuilder; use crate::NotificationBuilder;
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{ser::Serializer, Serialize}; use serde::{Serialize, ser::Serializer};
/// Alias for a [`std::result::Result`] with the error type set to [`Error`]. /// Alias for a [`std::result::Result`] with the error type set to [`Error`].
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
+3 -3
View File
@@ -14,13 +14,13 @@
)] )]
use serde::Serialize; use serde::Serialize;
#[cfg(mobile)]
use tauri::plugin::PluginHandle;
#[cfg(desktop)] #[cfg(desktop)]
use tauri::AppHandle; use tauri::AppHandle;
#[cfg(mobile)]
use tauri::plugin::PluginHandle;
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, TauriPlugin},
}; };
pub use models::*; pub use models::*;
+2 -2
View File
@@ -2,10 +2,10 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{de::DeserializeOwned, Deserialize}; use serde::{Deserialize, de::DeserializeOwned};
use tauri::{ use tauri::{
plugin::{PermissionState, PluginApi, PluginHandle},
AppHandle, Runtime, AppHandle, Runtime,
plugin::{PermissionState, PluginApi, PluginHandle},
}; };
use crate::models::*; use crate::models::*;
+4 -4
View File
@@ -4,7 +4,7 @@
use std::{collections::HashMap, fmt::Display}; use std::{collections::HashMap, fmt::Display};
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
use url::Url; use url::Url;
@@ -188,11 +188,11 @@ pub enum Schedule {
// custom ISO-8601 serialization that does not use 6 digits for years. // custom ISO-8601 serialization that does not use 6 digits for years.
mod iso8601 { mod iso8601 {
use serde::{ser::Error as _, Serialize, Serializer}; use serde::{Serialize, Serializer, ser::Error as _};
use time::{ use time::{
format_description::well_known::iso8601::{Config, EncodedConfig},
format_description::well_known::Iso8601,
OffsetDateTime, OffsetDateTime,
format_description::well_known::Iso8601,
format_description::well_known::iso8601::{Config, EncodedConfig},
}; };
const SERDE_CONFIG: EncodedConfig = Config::DEFAULT.encode(); const SERDE_CONFIG: EncodedConfig = Config::DEFAULT.encode();
+2 -2
View File
@@ -5,11 +5,11 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tauri::{ use tauri::{
ipc::{CommandScope, GlobalScope},
AppHandle, Runtime, AppHandle, Runtime,
ipc::{CommandScope, GlobalScope},
}; };
use crate::{scope::Scope, Error, OpenerExt}; use crate::{Error, OpenerExt, scope::Scope};
#[tauri::command] #[tauri::command]
pub async fn open_url<R: Runtime>( pub async fn open_url<R: Runtime>(
+1 -1
View File
@@ -13,7 +13,7 @@
use std::path::Path; use std::path::Path;
use tauri::{plugin::TauriPlugin, Manager, Runtime}; use tauri::{Manager, Runtime, plugin::TauriPlugin};
#[cfg(mobile)] #[cfg(mobile)]
use tauri::plugin::PluginHandle; use tauri::plugin::PluginHandle;
+3 -3
View File
@@ -93,18 +93,18 @@ mod imp {
use windows::Win32::UI::Shell::Common::ITEMIDLIST; use windows::Win32::UI::Shell::Common::ITEMIDLIST;
use windows::{ use windows::{
core::{w, HSTRING, PCWSTR},
Win32::{ Win32::{
Foundation::ERROR_FILE_NOT_FOUND, Foundation::ERROR_FILE_NOT_FOUND,
System::Com::CoInitialize, System::Com::CoInitialize,
UI::{ UI::{
Shell::{ Shell::{
ILCreateFromPathW, ILFree, SHOpenFolderAndSelectItems, ShellExecuteExW, ILCreateFromPathW, ILFree, SHELLEXECUTEINFOW, SHOpenFolderAndSelectItems,
SHELLEXECUTEINFOW, ShellExecuteExW,
}, },
WindowsAndMessaging::SW_SHOWNORMAL, WindowsAndMessaging::SW_SHOWNORMAL,
}, },
}, },
core::{HSTRING, PCWSTR, w},
}; };
pub fn reveal_items_in_dir(paths: &[PathBuf]) -> crate::Result<()> { pub fn reveal_items_in_dir(paths: &[PathBuf]) -> crate::Result<()> {
+2 -2
View File
@@ -8,9 +8,9 @@ use std::{
sync::Arc, sync::Arc,
}; };
use tauri::{ipc::ScopeObject, utils::acl::Value, AppHandle, Manager, Runtime}; use tauri::{AppHandle, Manager, Runtime, ipc::ScopeObject, utils::acl::Value};
use crate::{scope_entry::EntryRaw, Error}; use crate::{Error, scope_entry::EntryRaw};
pub use crate::scope_entry::Application; pub use crate::scope_entry::Application;
+1 -1
View File
@@ -10,7 +10,7 @@ use std::{
path::{Component, Path, PathBuf, Prefix, PrefixComponent}, path::{Component, Path, PathBuf, Prefix, PrefixComponent},
}; };
use windows::{core::HSTRING, Win32::Storage::FileSystem::GetFullPathNameW}; use windows::{Win32::Storage::FileSystem::GetFullPathNameW, core::HSTRING};
pub fn absolute_and_check_exists(path: &Path) -> io::Result<PathBuf> { pub fn absolute_and_check_exists(path: &Path) -> io::Result<PathBuf> {
let path = absolute(path)?; let path = absolute(path)?;
+2 -2
View File
@@ -12,10 +12,10 @@
use std::fmt::Display; use std::fmt::Display;
pub use os_info::Version; pub use os_info::Version;
use serialize_to_javascript::{default_template, DefaultTemplate, Template}; use serialize_to_javascript::{DefaultTemplate, Template, default_template};
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Runtime, Runtime,
plugin::{Builder, TauriPlugin},
}; };
mod commands; mod commands;
+4 -5
View File
@@ -17,13 +17,13 @@ use aho_corasick::AhoCorasick;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder, TauriPlugin},
}; };
use tauri_plugin_fs::FsExt; use tauri_plugin_fs::FsExt;
use std::{ use std::{
fs::{create_dir_all, File}, fs::{File, create_dir_all},
io::Write, io::Write,
path::Path, path::Path,
}; };
@@ -198,8 +198,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
// We will still save some semi-broken values because the scope events are quite spammy and we don't want to reduce runtime performance any further. // We will still save some semi-broken values because the scope events are quite spammy and we don't want to reduce runtime performance any further.
let ac = AhoCorasick::new(PATTERNS).unwrap(/* This should be impossible to fail since we're using a small static input */); let ac = AhoCorasick::new(PATTERNS).unwrap(/* This should be impossible to fail since we're using a small static input */);
if let Some(fs_scope) = &fs_scope { if let Some(fs_scope) = &fs_scope
if fs_scope_state_path.exists() { && fs_scope_state_path.exists() {
let scope: Scope = std::fs::read(&fs_scope_state_path) let scope: Scope = std::fs::read(&fs_scope_state_path)
.map_err(Error::from) .map_err(Error::from)
.and_then(|scope| bincode::deserialize(&scope).map_err(Into::into)) .and_then(|scope| bincode::deserialize(&scope).map_err(Into::into))
@@ -218,7 +218,6 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
// This is needed to fix broken .peristed-scope files in case the app doesn't update the scope itself. // This is needed to fix broken .peristed-scope files in case the app doesn't update the scope itself.
save_scopes(fs_scope, &app_dir, &fs_scope_state_path); save_scopes(fs_scope, &app_dir, &fs_scope_state_path);
} }
}
#[cfg(feature = "protocol-asset")] #[cfg(feature = "protocol-asset")]
if asset_scope_state_path.exists() { if asset_scope_state_path.exists() {
+2 -2
View File
@@ -21,12 +21,12 @@ mod ext;
pub use ext::*; pub use ext::*;
use tauri::{ use tauri::{
plugin::{self, TauriPlugin},
Result, Runtime, Result, Runtime,
plugin::{self, TauriPlugin},
}; };
#[cfg(feature = "tray-icon")] #[cfg(feature = "tray-icon")]
use tauri::{tray::TrayIconEvent, AppHandle, Manager, PhysicalPosition, PhysicalSize}; use tauri::{AppHandle, Manager, PhysicalPosition, PhysicalSize, tray::TrayIconEvent};
#[cfg(feature = "tray-icon")] #[cfg(feature = "tray-icon")]
struct Tray(std::sync::Mutex<Option<(PhysicalPosition<f64>, PhysicalSize<f64>)>>); struct Tray(std::sync::Mutex<Option<(PhysicalPosition<f64>, PhysicalSize<f64>)>>);
+1 -1
View File
@@ -10,8 +10,8 @@
)] )]
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
Runtime, Runtime,
plugin::{Builder, TauriPlugin},
}; };
mod commands; mod commands;
+2 -2
View File
@@ -7,16 +7,16 @@ use std::{collections::HashMap, future::Future, path::PathBuf, pin::Pin, string:
use encoding_rs::Encoding; use encoding_rs::Encoding;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
ipc::{Channel, CommandScope, GlobalScope},
Manager, Runtime, State, Window, Manager, Runtime, State, Window,
ipc::{Channel, CommandScope, GlobalScope},
}; };
#[allow(deprecated)] #[allow(deprecated)]
use crate::open::Program; use crate::open::Program;
use crate::{ use crate::{
Shell,
process::{CommandEvent, TerminatedPayload}, process::{CommandEvent, TerminatedPayload},
scope::ExecuteArgs, scope::ExecuteArgs,
Shell,
}; };
type ChildId = u32; type ChildId = u32;
+1 -1
View File
@@ -19,8 +19,8 @@ use std::{
use process::{Command, CommandChild}; use process::{Command, CommandChild};
use regex::Regex; use regex::Regex;
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin},
AppHandle, Manager, RunEvent, Runtime, AppHandle, Manager, RunEvent, Runtime,
plugin::{Builder, TauriPlugin},
}; };
mod commands; mod commands;
+2 -2
View File
@@ -20,10 +20,10 @@ use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x0800_0000; const CREATE_NO_WINDOW: u32 = 0x0800_0000;
const NEWLINE_BYTE: u8 = b'\n'; const NEWLINE_BYTE: u8 = b'\n';
use tauri::async_runtime::{block_on as block_on_task, channel, Receiver, Sender}; use tauri::async_runtime::{Receiver, Sender, block_on as block_on_task, channel};
pub use encoding_rs::Encoding; pub use encoding_rs::Encoding;
use os_pipe::{pipe, PipeReader, PipeWriter}; use os_pipe::{PipeReader, PipeWriter, pipe};
use serde::Serialize; use serde::Serialize;
use shared_child::SharedChild; use shared_child::SharedChild;
use tauri::utils::platform; use tauri::utils::platform;
+11 -7
View File
@@ -9,8 +9,8 @@ use crate::open::Program;
use crate::process::Command; use crate::process::Command;
use regex::Regex; use regex::Regex;
use tauri::ipc::ScopeObject;
use tauri::Manager; use tauri::Manager;
use tauri::ipc::ScopeObject;
/// Allowed representation of `Execute` command arguments. /// Allowed representation of `Execute` command arguments.
#[derive(Debug, Clone, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
@@ -162,8 +162,8 @@ pub enum Error {
/// The sidecar program validated but failed to find the sidecar path. /// The sidecar program validated but failed to find the sidecar path.
#[error( #[error(
"The scoped sidecar command was validated, but failed to create the path to the command: {0}" "The scoped sidecar command was validated, but failed to create the path to the command: {0}"
)] )]
Sidecar(String), Sidecar(String),
/// The named command was not found in the scoped config. /// The named command was not found in the scoped config.
@@ -172,12 +172,14 @@ pub enum Error {
/// A command variable has no value set in the arguments. /// A command variable has no value set in the arguments.
#[error( #[error(
"Scoped command argument at position {0} must match regex validation {1} but it was not found" "Scoped command argument at position {0} must match regex validation {1} but it was not found"
)] )]
MissingVar(usize, String), MissingVar(usize, String),
/// At least one argument did not pass input validation. /// At least one argument did not pass input validation.
#[error("Scoped command argument at position {index} was found, but failed regex validation {validation}")] #[error(
"Scoped command argument at position {index} was found, but failed regex validation {validation}"
)]
Validation { Validation {
/// Index of the variable. /// Index of the variable.
index: usize, index: usize,
@@ -214,7 +216,9 @@ impl OpenScope {
}); });
} }
} else { } else {
log::warn!("open() command called but the plugin configuration denies calls from JavaScript; set `tauri.conf.json > plugins > shell > open` to true or a validation regex string"); log::warn!(
"open() command called but the plugin configuration denies calls from JavaScript; set `tauri.conf.json > plugins > shell > open` to true or a validation regex string"
);
return Err(Error::Validation { return Err(Error::Validation {
index: 0, index: 0,
validation: "tauri^".to_string(), // purposefully impossible regex validation: "tauri^".to_string(), // purposefully impossible regex
+1 -1
View File
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde::{de::Error as DeError, Deserialize, Deserializer}; use serde::{Deserialize, Deserializer, de::Error as DeError};
use std::path::PathBuf; use std::path::PathBuf;
@@ -4,7 +4,7 @@ version = "0.1.0"
description = "A Tauri App" description = "A Tauri App"
authors = ["You"] authors = ["You"]
repository = "" repository = ""
edition = "2021" edition = "2024"
rust-version = "1.90" rust-version = "1.90"
[dependencies] [dependencies]
+1 -1
View File
@@ -15,7 +15,7 @@
)] )]
#![cfg(not(any(target_os = "android", target_os = "ios")))] #![cfg(not(any(target_os = "android", target_os = "ios")))]
use tauri::{plugin::TauriPlugin, AppHandle, Manager, Runtime}; use tauri::{AppHandle, Manager, Runtime, plugin::TauriPlugin};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
#[path = "platform_impl/windows.rs"] #[path = "platform_impl/windows.rs"]
@@ -7,8 +7,8 @@ use crate::semver_compat::semver_compat_string;
use crate::SingleInstanceCallback; use crate::SingleInstanceCallback;
use tauri::{ use tauri::{
plugin::{self, TauriPlugin},
AppHandle, Manager, RunEvent, Runtime, AppHandle, Manager, RunEvent, Runtime,
plugin::{self, TauriPlugin},
}; };
use zbus::{blocking::Connection, interface, names::WellKnownName}; use zbus::{blocking::Connection, interface, names::WellKnownName};
@@ -101,12 +101,11 @@ pub fn init<R: Runtime>(
} }
pub fn destroy<R: Runtime, M: Manager<R>>(manager: &M) { pub fn destroy<R: Runtime, M: Manager<R>>(manager: &M) {
if let Some(connection) = manager.try_state::<ConnectionHandle>() { if let Some(connection) = manager.try_state::<ConnectionHandle>()
if let Some(dbus_name) = manager && let Some(dbus_name) = manager
.try_state::<DBusName>() .try_state::<DBusName>()
.and_then(|name| WellKnownName::try_from(name.0.clone()).ok()) .and_then(|name| WellKnownName::try_from(name.0.clone()).ok())
{ {
let _ = connection.0.release_name(dbus_name); let _ = connection.0.release_name(dbus_name);
} }
}
} }
@@ -8,12 +8,12 @@ use std::{
path::PathBuf, path::PathBuf,
}; };
use crate::SingleInstanceCallback;
#[cfg(feature = "semver")] #[cfg(feature = "semver")]
use crate::semver_compat::semver_compat_string; use crate::semver_compat::semver_compat_string;
use crate::SingleInstanceCallback;
use tauri::{ use tauri::{
plugin::{self, TauriPlugin},
AppHandle, Config, Manager, RunEvent, Runtime, AppHandle, Config, Manager, RunEvent, Runtime,
plugin::{self, TauriPlugin},
}; };
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
@@ -8,20 +8,20 @@ use crate::semver_compat::semver_compat_string;
use crate::SingleInstanceCallback; use crate::SingleInstanceCallback;
use std::ffi::CStr; use std::ffi::CStr;
use tauri::{ use tauri::{
plugin::{self, TauriPlugin},
AppHandle, Manager, RunEvent, Runtime, AppHandle, Manager, RunEvent, Runtime,
plugin::{self, TauriPlugin},
}; };
use windows_sys::Win32::{ use windows_sys::Win32::{
Foundation::{CloseHandle, GetLastError, ERROR_ALREADY_EXISTS, HWND, LPARAM, LRESULT, WPARAM}, Foundation::{CloseHandle, ERROR_ALREADY_EXISTS, GetLastError, HWND, LPARAM, LRESULT, WPARAM},
System::{ System::{
DataExchange::COPYDATASTRUCT, DataExchange::COPYDATASTRUCT,
LibraryLoader::GetModuleHandleW, LibraryLoader::GetModuleHandleW,
Threading::{CreateMutexW, ReleaseMutex}, Threading::{CreateMutexW, ReleaseMutex},
}, },
UI::WindowsAndMessaging::{ UI::WindowsAndMessaging::{
self as w32wm, AllowSetForegroundWindow, CreateWindowExW, DefWindowProcW, DestroyWindow, self as w32wm, AllowSetForegroundWindow, CREATESTRUCTW, CreateWindowExW, DefWindowProcW,
FindWindowW, GetWindowThreadProcessId, RegisterClassExW, SendMessageW, CREATESTRUCTW, DestroyWindow, FindWindowW, GWL_STYLE, GWLP_USERDATA, GetWindowThreadProcessId,
GWLP_USERDATA, GWL_STYLE, WINDOW_LONG_PTR_INDEX, WM_COPYDATA, WM_CREATE, WM_DESTROY, RegisterClassExW, SendMessageW, WINDOW_LONG_PTR_INDEX, WM_COPYDATA, WM_CREATE, WM_DESTROY,
WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT,
WS_OVERLAPPED, WS_POPUP, WS_VISIBLE, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
}, },
+1 -1
View File
@@ -5,7 +5,7 @@
use indexmap::IndexMap; use indexmap::IndexMap;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
use sqlx::migrate::Migrator; use sqlx::migrate::Migrator;
use tauri::{command, AppHandle, Runtime, State}; use tauri::{AppHandle, Runtime, State, command};
use crate::{DbInstances, DbPool, Error, LastInsertId, Migrations}; use crate::{DbInstances, DbPool, Error, LastInsertId, Migrations};
+1 -1
View File
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
use sqlx::{mysql::MySqlValueRef, TypeInfo, Value, ValueRef}; use sqlx::{TypeInfo, Value, ValueRef, mysql::MySqlValueRef};
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time}; use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
use crate::Error; use crate::Error;
+1 -1
View File
@@ -4,7 +4,7 @@
use rust_decimal::prelude::ToPrimitive; use rust_decimal::prelude::ToPrimitive;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
use sqlx::{postgres::PgValueRef, TypeInfo, Value, ValueRef}; use sqlx::{TypeInfo, Value, ValueRef, postgres::PgValueRef};
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time}; use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
use uuid::Uuid; use uuid::Uuid;
+1 -1
View File
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
use sqlx::{sqlite::SqliteValueRef, TypeInfo, Value, ValueRef}; use sqlx::{TypeInfo, Value, ValueRef, sqlite::SqliteValueRef};
use time::{Date, PrimitiveDateTime, Time}; use time::{Date, PrimitiveDateTime, Time};
use crate::Error; use crate::Error;
+4 -2
View File
@@ -33,8 +33,8 @@ use sqlx::{
migrate::{Migration as SqlxMigration, MigrationSource, MigrationType, Migrator}, migrate::{Migration as SqlxMigration, MigrationSource, MigrationType, Migrator},
}; };
use tauri::{ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin},
Manager, RunEvent, Runtime, Manager, RunEvent, Runtime,
plugin::{Builder as PluginBuilder, TauriPlugin},
}; };
use tokio::sync::{Mutex, RwLock}; use tokio::sync::{Mutex, RwLock};
@@ -158,7 +158,9 @@ impl Builder {
/// connected to in that case. /// connected to in that case.
pub fn new() -> Self { pub fn new() -> Self {
#[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgres")))] #[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgres")))]
eprintln!("No sql driver enabled. Please set at least one of the \"sqlite\", \"mysql\", \"postgres\" feature flags."); eprintln!(
"No sql driver enabled. Please set at least one of the \"sqlite\", \"mysql\", \"postgres\" feature flags."
);
Self::default() Self::default()
} }
+1 -1
View File
@@ -8,7 +8,7 @@ use std::fs::create_dir_all;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))] #[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
use sqlx::{migrate::MigrateDatabase, Column, Executor, Pool, Row}; use sqlx::{Column, Executor, Pool, Row, migrate::MigrateDatabase};
#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))] #[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgres"))]
use tauri::Manager; use tauri::Manager;
use tauri::{AppHandle, Runtime}; use tauri::{AppHandle, Runtime};
@@ -5,7 +5,7 @@ description = "A Tauri App"
authors = ["you"] authors = ["you"]
license = "" license = ""
repository = "" repository = ""
edition = "2021" edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+4 -5
View File
@@ -18,10 +18,10 @@ use std::{
sync::{Arc, RwLock}, sync::{Arc, RwLock},
time::Duration, time::Duration,
}; };
pub use store::{resolve_store_path, DeserializeFn, SerializeFn, Store, StoreBuilder}; pub use store::{DeserializeFn, SerializeFn, Store, StoreBuilder, resolve_store_path};
use tauri::{ use tauri::{
plugin::{self, TauriPlugin},
AppHandle, Manager, ResourceId, RunEvent, Runtime, State, AppHandle, Manager, ResourceId, RunEvent, Runtime, State,
plugin::{self, TauriPlugin},
}; };
mod error; mod error;
@@ -470,11 +470,10 @@ impl Builder {
let collection = app_handle.state::<StoreState>(); let collection = app_handle.state::<StoreState>();
let stores = collection.stores.read().unwrap(); let stores = collection.stores.read().unwrap();
for (path, rid) in stores.iter() { for (path, rid) in stores.iter() {
if let Ok(store) = app_handle.resources_table().get::<Store<R>>(*rid) { if let Ok(store) = app_handle.resources_table().get::<Store<R>>(*rid)
if let Err(err) = store.save() { && let Err(err) = store.save() {
tracing::error!("failed to save store {path:?} with error {err:?}"); tracing::error!("failed to save store {path:?} with error {err:?}");
} }
}
} }
} }
}) })
+2 -2
View File
@@ -11,10 +11,10 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
time::Duration, time::Duration,
}; };
use tauri::{path::BaseDirectory, AppHandle, Emitter, Manager, Resource, ResourceId, Runtime}; use tauri::{AppHandle, Emitter, Manager, Resource, ResourceId, Runtime, path::BaseDirectory};
use tokio::{ use tokio::{
select, select,
sync::mpsc::{unbounded_channel, UnboundedSender}, sync::mpsc::{UnboundedSender, unbounded_channel},
time::sleep, time::sleep,
}; };
+2 -2
View File
@@ -45,8 +45,8 @@ fn create_or_get_salt(salt: &mut [u8], salt_path: &Path) {
salt.clone_from_slice(&tmp); salt.clone_from_slice(&tmp);
} else { } else {
// Generate new salt // Generate new salt
let mut gen = ChaCha20Rng::from_os_rng(); let mut rng = ChaCha20Rng::from_os_rng();
gen.fill_bytes(salt); rng.fill_bytes(salt);
std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold") std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold")
} }
} }
+5 -6
View File
@@ -23,18 +23,18 @@ use std::{
use crypto::keys::bip39; use crypto::keys::bip39;
use iota_stronghold::{ use iota_stronghold::{
Client, Location,
procedures::{ procedures::{
BIP39Generate, BIP39Recover, Curve, Ed25519Sign, KeyType as StrongholdKeyType, BIP39Generate, BIP39Recover, Curve, Ed25519Sign, KeyType as StrongholdKeyType,
MnemonicLanguage, PublicKey, Slip10Derive, Slip10DeriveInput, Slip10Generate, MnemonicLanguage, PublicKey, Slip10Derive, Slip10DeriveInput, Slip10Generate,
StrongholdProcedure, StrongholdProcedure,
}, },
Client, Location,
}; };
use serde::{de::Visitor, Deserialize, Deserializer}; use serde::{Deserialize, Deserializer, de::Visitor};
use stronghold::{Error, Result, Stronghold}; use stronghold::{Error, Result, Stronghold};
use tauri::{ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin},
Manager, Runtime, State, Manager, Runtime, State,
plugin::{Builder as PluginBuilder, TauriPlugin},
}; };
use zeroize::{Zeroize, Zeroizing}; use zeroize::{Zeroize, Zeroizing};
@@ -270,12 +270,11 @@ async fn destroy(
snapshot_path: PathBuf, snapshot_path: PathBuf,
) -> Result<()> { ) -> Result<()> {
let mut collection = collection.0.lock().unwrap(); let mut collection = collection.0.lock().unwrap();
if let Some(stronghold) = collection.remove(&snapshot_path) { if let Some(stronghold) = collection.remove(&snapshot_path)
if let Err(e) = stronghold.save() { && let Err(e) = stronghold.save() {
collection.insert(snapshot_path, stronghold); collection.insert(snapshot_path, stronghold);
return Err(e); return Err(e);
} }
}
Ok(()) Ok(())
} }
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::{Result, Update, UpdaterExt};
use http::{HeaderMap, HeaderName, HeaderValue}; use http::{HeaderMap, HeaderName, HeaderValue};
use serde::Serialize; use serde::Serialize;
use tauri::{ipc::Channel, Manager, Resource, ResourceId, Runtime, Webview}; use tauri::{Manager, Resource, ResourceId, Runtime, Webview, ipc::Channel};
use std::{str::FromStr, time::Duration}; use std::{str::FromStr, time::Duration};
use url::Url; use url::Url;
+6 -2
View File
@@ -204,8 +204,12 @@ pub(crate) fn validate_endpoints(
if url.scheme() != "https" { if url.scheme() != "https" {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
eprintln!("[\x1b[33mWARNING\x1b[0m] The updater endpoint \"{url}\" doesn't use `https` protocol. This is allowed in development but will fail in release builds."); eprintln!(
eprintln!("[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration"); "[\x1b[33mWARNING\x1b[0m] The updater endpoint \"{url}\" doesn't use `https` protocol. This is allowed in development but will fail in release builds."
);
eprintln!(
"[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration"
);
} }
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
return Err(crate::Error::InsecureTransportProtocol); return Err(crate::Error::InsecureTransportProtocol);
+7 -5
View File
@@ -25,7 +25,9 @@ pub enum Error {
#[error("Could not fetch a valid release JSON from the remote")] #[error("Could not fetch a valid release JSON from the remote")]
ReleaseNotFound, ReleaseNotFound,
/// Unsupported app architecture. /// Unsupported app architecture.
#[error("Unsupported application architecture, expected one of `x86`, `x86_64`, `arm` or `aarch64`.")] #[error(
"Unsupported application architecture, expected one of `x86`, `x86_64`, `arm` or `aarch64`."
)]
UnsupportedArch, UnsupportedArch,
/// Operating system is not supported. /// Operating system is not supported.
#[error("Unsupported OS, expected one of `linux`, `darwin` or `windows`.")] #[error("Unsupported OS, expected one of `linux`, `darwin` or `windows`.")]
@@ -43,9 +45,7 @@ pub enum Error {
#[error("the platform `{0}` was not found in the response `platforms` object")] #[error("the platform `{0}` was not found in the response `platforms` object")]
TargetNotFound(String), TargetNotFound(String),
/// Neither the platform nor the fallback platform was found in the updater JSON response. /// Neither the platform nor the fallback platform was found in the updater JSON response.
#[error( #[error("None of the fallback platforms `{0:?}` were found in the response `platforms` object")]
"None of the fallback platforms `{0:?}` were found in the response `platforms` object"
)]
TargetsNotFound(Vec<String>), TargetsNotFound(Vec<String>),
/// Download failed /// Download failed
#[error("`{0}`")] #[error("`{0}`")]
@@ -57,7 +57,9 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
Base64(#[from] base64::DecodeError), Base64(#[from] base64::DecodeError),
/// UTF8 Errors in signature. /// UTF8 Errors in signature.
#[error("The signature {0} could not be decoded, please check if it is a valid base64 string. The signature must be the contents of the `.sig` file generated by the Tauri bundler, as a string.")] #[error(
"The signature {0} could not be decoded, please check if it is a valid base64 string. The signature must be the contents of the `.sig` file generated by the Tauri bundler, as a string."
)]
SignatureUtf8(String), SignatureUtf8(String),
#[cfg(all(target_os = "windows", feature = "zip"))] #[cfg(all(target_os = "windows", feature = "zip"))]
/// `zip` errors. /// `zip` errors.
+1 -1
View File
@@ -24,8 +24,8 @@ use std::{ffi::OsString, sync::Arc};
use http::{HeaderMap, HeaderName, HeaderValue}; use http::{HeaderMap, HeaderName, HeaderValue};
use semver::Version; use semver::Version;
use tauri::{ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin},
Manager, Runtime, Manager, Runtime,
plugin::{Builder as PluginBuilder, TauriPlugin},
}; };
mod commands; mod commands;
+15 -21
View File
@@ -17,28 +17,28 @@ use std::ffi::OsStr;
use base64::Engine; use base64::Engine;
use futures_util::StreamExt; use futures_util::StreamExt;
use http::{header::ACCEPT, HeaderName}; use http::{HeaderName, header::ACCEPT};
use minisign_verify::{PublicKey, Signature}; use minisign_verify::{PublicKey, Signature};
use percent_encoding::{AsciiSet, CONTROLS}; use percent_encoding::{AsciiSet, CONTROLS};
use reqwest::{ use reqwest::{
header::{HeaderMap, HeaderValue},
ClientBuilder, StatusCode, ClientBuilder, StatusCode,
header::{HeaderMap, HeaderValue},
}; };
use semver::Version; use semver::Version;
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize, de::Error as DeError};
use tauri::{ use tauri::{
AppHandle, Resource, Runtime,
utils::{ utils::{
config::BundleType, config::BundleType,
platform::{bundle_type, current_exe}, platform::{bundle_type, current_exe},
}, },
AppHandle, Resource, Runtime,
}; };
use time::OffsetDateTime; use time::OffsetDateTime;
use url::Url; use url::Url;
use crate::{ use crate::{
error::{Error, Result},
Config, Config,
error::{Error, Result},
}; };
const UPDATER_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); const UPDATER_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
@@ -937,8 +937,8 @@ impl Update {
/// └── ... /// └── ...
fn install_inner(&self, bytes: &[u8]) -> Result<()> { fn install_inner(&self, bytes: &[u8]) -> Result<()> {
use windows_sys::{ use windows_sys::{
w,
Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_SHOW}, Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_SHOW},
w,
}; };
let updater_type = self.extract(bytes)?; let updater_type = self.extract(bytes)?;
@@ -1185,8 +1185,8 @@ impl Update {
let decoder = flate2::read::GzDecoder::new(archive); let decoder = flate2::read::GzDecoder::new(archive);
let mut archive = tar::Archive::new(decoder); let mut archive = tar::Archive::new(decoder);
for mut entry in archive.entries()?.flatten() { for mut entry in archive.entries()?.flatten() {
if let Ok(path) = entry.path() { if let Ok(path) = entry.path()
if path.extension() == Some(OsStr::new("AppImage")) { && path.extension() == Some(OsStr::new("AppImage")) {
// if something went wrong during the extraction, we should restore previous app // if something went wrong during the extraction, we should restore previous app
if let Err(err) = entry.unpack(&self.extract_path) { if let Err(err) = entry.unpack(&self.extract_path) {
std::fs::rename(tmp_app_image, &self.extract_path)?; std::fs::rename(tmp_app_image, &self.extract_path)?;
@@ -1195,7 +1195,6 @@ impl Update {
// early finish we have everything we need here // early finish we have everything we need here
return Ok(()); return Ok(());
} }
}
} }
// if we have not returned early we should restore the backup // if we have not returned early we should restore the backup
std::fs::rename(tmp_app_image, &self.extract_path)?; std::fs::rename(tmp_app_image, &self.extract_path)?;
@@ -1289,20 +1288,17 @@ impl Update {
.arg(install_arg) .arg(install_arg)
.arg(pkg_path) .arg(pkg_path)
.status() .status()
{ && status.success() {
if status.success() {
log::debug!("installed {pkg_path:?} with pkexec"); log::debug!("installed {pkg_path:?} with pkexec");
return Ok(()); return Ok(());
} }
}
// 2. Try zenity or kdialog for a graphical sudo experience // 2. Try zenity or kdialog for a graphical sudo experience
if let Ok(password) = self.get_password_graphically() { if let Ok(password) = self.get_password_graphically()
if self.install_with_sudo(pkg_path, &password, install_cmd, install_arg)? { && self.install_with_sudo(pkg_path, &password, install_cmd, install_arg)? {
log::debug!("installed {pkg_path:?} with GUI sudo"); log::debug!("installed {pkg_path:?} with GUI sudo");
return Ok(()); return Ok(());
} }
}
// 3. Final fallback: terminal sudo // 3. Final fallback: terminal sudo
let status = std::process::Command::new("sudo") let status = std::process::Command::new("sudo")
@@ -1329,22 +1325,20 @@ impl Update {
]) ])
.output(); .output();
if let Ok(output) = zenity_result { if let Ok(output) = zenity_result
if output.status.success() { && output.status.success() {
return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()); return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string());
} }
}
// Fall back to kdialog if zenity fails or isn't available // Fall back to kdialog if zenity fails or isn't available
let kdialog_result = std::process::Command::new("kdialog") let kdialog_result = std::process::Command::new("kdialog")
.args(["--password", "Enter your password to install the update:"]) .args(["--password", "Enter your password to install the update:"])
.output(); .output();
if let Ok(output) = kdialog_result { if let Ok(output) = kdialog_result
if output.status.success() { && output.status.success() {
return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()); return Ok(String::from_utf8_lossy(&output.stdout).trim().to_string());
} }
}
Err(Error::AuthenticationFailed) Err(Error::AuthenticationFailed)
} }
@@ -818,7 +818,8 @@ fn run_update_cases(
if code != expected_exit_code { if code != expected_exit_code {
panic!( panic!(
"failed to run app bundled as {}, expected exit code {expected_exit_code}, got {code}", bundle_target.name() "failed to run app bundled as {}, expected exit code {expected_exit_code}, got {code}",
bundle_target.name()
); );
} }
#[cfg(windows)] #[cfg(windows)]
@@ -32,7 +32,7 @@ fn npm_command() -> Command {
} }
mod v1 { mod v1 {
use super::{npm_command, BundleTarget, UPDATER_PRIVATE_KEY}; use super::{BundleTarget, UPDATER_PRIVATE_KEY, npm_command};
use serde::Serialize; use serde::Serialize;
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
@@ -3,7 +3,7 @@ workspace = {}
[package] [package]
name = "app-updater-v1" name = "app-updater-v1"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2024"
[build-dependencies] [build-dependencies]
tauri-build = { version = "1", features = [] } tauri-build = { version = "1", features = [] }
+2 -3
View File
@@ -21,12 +21,11 @@ mod transfer_stats;
use transfer_stats::TransferStats; use transfer_stats::TransferStats;
use futures_util::TryStreamExt; use futures_util::TryStreamExt;
use serde::{ser::Serializer, Deserialize, Serialize}; use serde::{Deserialize, Serialize, ser::Serializer};
use tauri::{ use tauri::{
command, Runtime, command,
ipc::Channel, ipc::Channel,
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
Runtime,
}; };
use tokio::{ use tokio::{
fs::File, fs::File,
@@ -2,7 +2,7 @@
name = "websocket-example" name = "websocket-example"
version = "0.1.0" version = "0.1.0"
description = "A Tauri App" description = "A Tauri App"
edition = "2021" edition = "2024"
[dependencies] [dependencies]
serde = { workspace = true } serde = { workspace = true }
+5 -5
View File
@@ -18,13 +18,13 @@
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png" html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
)] )]
use futures_util::{stream::SplitSink, SinkExt, StreamExt}; use futures_util::{SinkExt, StreamExt, stream::SplitSink};
use http::header::{HeaderName, HeaderValue}; use http::header::{HeaderName, HeaderValue};
use serde::{ser::Serializer, Deserialize, Serialize}; use serde::{Deserialize, Serialize, ser::Serializer};
use tauri::{ use tauri::{
Manager, Runtime, State, Window,
ipc::Channel, ipc::Channel,
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
Manager, Runtime, State, Window,
}; };
use tokio::{net::TcpStream, sync::Mutex}; use tokio::{net::TcpStream, sync::Mutex};
#[cfg(any( #[cfg(any(
@@ -40,12 +40,12 @@ use tokio_tungstenite::connect_async_tls_with_config;
)))] )))]
use tokio_tungstenite::connect_async_with_config; use tokio_tungstenite::connect_async_with_config;
use tokio_tungstenite::{ use tokio_tungstenite::{
Connector, MaybeTlsStream, WebSocketStream,
tungstenite::{ tungstenite::{
Message,
client::IntoClientRequest, client::IntoClientRequest,
protocol::{CloseFrame as ProtocolCloseFrame, WebSocketConfig}, protocol::{CloseFrame as ProtocolCloseFrame, WebSocketConfig},
Message,
}, },
Connector, MaybeTlsStream, WebSocketStream,
}; };
use std::collections::HashMap; use std::collections::HashMap;
+1 -1
View File
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::{AppHandleExt, StateFlags, WindowExt}; use crate::{AppHandleExt, StateFlags, WindowExt};
use tauri::{command, AppHandle, Manager, Runtime}; use tauri::{AppHandle, Manager, Runtime, command};
fn get_state_flags<R: Runtime>( fn get_state_flags<R: Runtime>(
app: &AppHandle<R>, app: &AppHandle<R>,
+1 -1
View File
@@ -13,9 +13,9 @@
use bitflags::bitflags; use bitflags::bitflags;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::{ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin},
AppHandle, Manager, Monitor, PhysicalPosition, PhysicalSize, RunEvent, Runtime, WebviewWindow, AppHandle, Manager, Monitor, PhysicalPosition, PhysicalSize, RunEvent, Runtime, WebviewWindow,
Window, WindowEvent, Window, WindowEvent,
plugin::{Builder as PluginBuilder, TauriPlugin},
}; };
use std::{ use std::{