diff --git a/Cargo.lock b/Cargo.lock index 2e909ee5..8b190f23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4362,6 +4362,7 @@ dependencies = [ name = "tauri-plugin-persisted-scope" version = "0.1.0" dependencies = [ + "aho-corasick", "bincode", "log", "serde", diff --git a/plugins/persisted-scope/Cargo.toml b/plugins/persisted-scope/Cargo.toml index 7bc30228..fa6784c2 100644 --- a/plugins/persisted-scope/Cargo.toml +++ b/plugins/persisted-scope/Cargo.toml @@ -15,6 +15,7 @@ serde_json.workspace = true tauri.workspace = true log.workspace = true thiserror.workspace = true +aho-corasick = "0.7" bincode = "1" [features] diff --git a/plugins/persisted-scope/src/lib.rs b/plugins/persisted-scope/src/lib.rs index ef0625ba..6698f278 100644 --- a/plugins/persisted-scope/src/lib.rs +++ b/plugins/persisted-scope/src/lib.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +use aho_corasick::AhoCorasick; use serde::{Deserialize, Serialize}; use tauri::{ plugin::{Builder, TauriPlugin}, @@ -14,6 +15,8 @@ use std::{ }; const SCOPE_STATE_FILENAME: &str = ".persisted-scope"; +const PATTERNS: &[&str] = &["[?]", "[[]", "[]]", "[*]"]; +const REPLACE_WITH: &[&str] = &["?", "[", "]", "*"]; #[derive(Debug, thiserror::Error)] enum Error { @@ -45,6 +48,29 @@ pub fn init() -> TauriPlugin { if let Some(app_dir) = app_dir { let scope_state_path = app_dir.join(SCOPE_STATE_FILENAME); + // We need to filter out glob pattern paths from the scope configs to not pollute the scope with incorrect paths. + // We can't plainly filter for `*` because `*` is valid in paths on unix. + let initial_fs_allowed: Vec = fs_scope + .allowed_patterns() + .into_iter() + .map(|p| p.to_string()) + .collect(); + let initial_asset_allowed: Vec = asset_protocol_scope + .allowed_patterns() + .into_iter() + .map(|p| p.to_string()) + .collect(); + let initial_fs_forbidden: Vec = fs_scope + .forbidden_patterns() + .into_iter() + .map(|p| p.to_string()) + .collect(); + let initial_asset_forbidden: Vec = asset_protocol_scope + .forbidden_patterns() + .into_iter() + .map(|p| p.to_string()) + .collect(); + let _ = fs_scope.forbid_file(&scope_state_path); #[cfg(feature = "protocol-asset")] let _ = asset_protocol_scope.forbid_file(&scope_state_path); @@ -55,19 +81,29 @@ pub fn init() -> TauriPlugin { .and_then(|scope| bincode::deserialize(&scope).map_err(Into::into)) .unwrap_or_default(); for allowed in &scope.allowed_paths { - // allows the path as is - let _ = fs_scope.allow_file(allowed); + if !initial_fs_allowed.contains(&allowed) { + let _ = fs_scope.allow_file(&allowed); + } #[cfg(feature = "protocol-asset")] - let _ = asset_protocol_scope.allow_file(allowed); + if !initial_asset_allowed.contains(&allowed) { + let _ = asset_protocol_scope.allow_file(&allowed); + } } for forbidden in &scope.forbidden_patterns { // forbid the path as is - let _ = fs_scope.forbid_file(forbidden); + if !initial_fs_forbidden.contains(&forbidden) { + let _ = fs_scope.forbid_file(&forbidden); + } #[cfg(feature = "protocol-asset")] - let _ = asset_protocol_scope.forbid_file(forbidden); + if !initial_asset_forbidden.contains(&forbidden) { + let _ = asset_protocol_scope.forbid_file(&forbidden); + } } } + // We could also "fix" the paths on app start if we notice any runtime performance problems. + let ac = AhoCorasick::new_auto_configured(PATTERNS); + fs_scope.listen(move |event| { let fs_scope = app.fs_scope(); if let FsScopeEvent::PathAllowed(_) = event { @@ -75,18 +111,17 @@ pub fn init() -> TauriPlugin { allowed_paths: fs_scope .allowed_patterns() .into_iter() - .map(|p| p.to_string()) + .map(|p| ac.replace_all(p.as_str(), REPLACE_WITH)) .collect(), forbidden_patterns: fs_scope .forbidden_patterns() .into_iter() - .map(|p| p.to_string()) + .map(|p| ac.replace_all(p.as_str(), REPLACE_WITH)) .collect(), }; - let scope_state_path = scope_state_path.clone(); let _ = create_dir_all(&app_dir) - .and_then(|_| File::create(scope_state_path)) + .and_then(|_| File::create(&scope_state_path)) .map_err(Error::Io) .and_then(|mut f| { f.write_all(&bincode::serialize(&scope).map_err(Error::from)?)