use crate::*;
use tauri::Manager as _;
use tauri_plugin_fs::FsExt as _;
pub fn convert_rid_to_bytes(rid: tauri::ResourceId) -> Vec<u8> {
let rid: u32 = rid;
rid.to_be_bytes().to_vec()
}
pub fn resolve_path<R: tauri::Runtime>(
webview: &tauri::Webview<R>,
global_scope: &tauri::ipc::GlobalScope<Scope>,
command_scope: &tauri::ipc::CommandScope<Scope>,
config: &PluginConfig,
path: tauri_plugin_fs::SafeFilePath,
base_dir: Option<tauri::path::BaseDirectory>,
) -> Result<std::path::PathBuf> {
let path = path.into_path()?;
let path = if let Some(base_dir) = base_dir {
webview.path().resolve(&path, base_dir)?
} else {
path.to_path_buf()
};
let fs_scope = webview.try_fs_scope();
let scope = tauri::scope::fs::Scope::new(
webview,
&tauri::utils::config::FsScope::Scope {
allow: global_scope
.allows()
.iter()
.filter_map(|e| e.path.clone())
.chain(command_scope.allows().iter().filter_map(|e| e.path.clone()))
.collect(),
deny: global_scope
.denies()
.iter()
.filter_map(|e| e.path.clone())
.chain(command_scope.denies().iter().filter_map(|e| e.path.clone()))
.collect(),
require_literal_leading_dot: config.require_literal_leading_dot,
},
)?;
let require_literal_leading_dot = config.require_literal_leading_dot.unwrap_or(cfg!(unix));
if is_forbidden(&scope, &path, require_literal_leading_dot) {
return Err(Error::with(format!("forbidden path: {}", path.display())));
}
if fs_scope.as_ref().is_some_and(|s| is_forbidden(&s, &path, require_literal_leading_dot)) {
return Err(Error::with(format!("forbidden path: {}", path.display())));
}
if scope.is_allowed(&path) {
return Ok(path)
}
if fs_scope.as_ref().is_some_and(|s| s.is_allowed(&path)) {
return Ok(path)
}
if cfg!(debug_assertions) {
Err(Error::with(format!(
"forbidden path: {}, maybe it is not allowed on the scope configuration in your capability file",
path.display()
)))
}
else {
Err(Error::with(format!("forbidden path: {}", path.display())))
}
}
fn is_forbidden<P: AsRef<std::path::Path>>(
scope: &tauri::fs::Scope,
path: P,
require_literal_leading_dot: bool,
) -> bool {
let path = path.as_ref();
let path = if path.is_symlink() {
match std::fs::read_link(path) {
Ok(p) => p,
Err(_) => return false,
}
} else {
path.to_path_buf()
};
let path = if !path.exists() {
crate::Result::Ok(path)
} else {
std::fs::canonicalize(path).map_err(Into::into)
};
if let Ok(path) = path {
let path: std::path::PathBuf = path.components().collect();
scope.forbidden_patterns().iter().any(|p| {
p.matches_path_with(
&path,
glob::MatchOptions {
require_literal_separator: true,
require_literal_leading_dot,
..Default::default()
},
)
})
} else {
false
}
}
impl tauri::ipc::ScopeObject for Scope {
type Error = Error;
fn deserialize<R: tauri::Runtime>(
app: &tauri::AppHandle<R>,
raw: tauri::utils::acl::Value,
) -> Result<Self> {
let path = serde_json::from_value(raw.into()).map(|raw| match raw {
ScopeSchema::Value(path) => path,
ScopeSchema::Object { path } => path,
})?;
use tauri::Manager as _;
match app.path().parse(path) {
Ok(path) => Ok(Self { path: Some(path) }),
Err(err) => Err(err.into()),
}
}
}