|
@@ -3,7 +3,11 @@
|
|
// SPDX-License-Identifier: MIT
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
use crate::{
|
|
use crate::{
|
|
- api::{dir, file, path::BaseDirectory},
|
|
|
|
|
|
+ api::{
|
|
|
|
+ dir,
|
|
|
|
+ file::{self, SafePathBuf},
|
|
|
|
+ path::BaseDirectory,
|
|
|
|
+ },
|
|
scope::Scopes,
|
|
scope::Scopes,
|
|
Config, Env, Manager, PackageInfo, Runtime, Window,
|
|
Config, Env, Manager, PackageInfo, Runtime, Window,
|
|
};
|
|
};
|
|
@@ -26,29 +30,6 @@ use std::{
|
|
sync::Arc,
|
|
sync::Arc,
|
|
};
|
|
};
|
|
|
|
|
|
-#[derive(Clone, Debug)]
|
|
|
|
-pub struct SafePathBuf(std::path::PathBuf);
|
|
|
|
-
|
|
|
|
-impl AsRef<Path> for SafePathBuf {
|
|
|
|
- fn as_ref(&self) -> &Path {
|
|
|
|
- self.0.as_ref()
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl<'de> Deserialize<'de> for SafePathBuf {
|
|
|
|
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
|
|
- where
|
|
|
|
- D: Deserializer<'de>,
|
|
|
|
- {
|
|
|
|
- let path = std::path::PathBuf::deserialize(deserializer)?;
|
|
|
|
- if path.components().any(|x| matches!(x, Component::ParentDir)) {
|
|
|
|
- Err(DeError::custom("cannot traverse directory"))
|
|
|
|
- } else {
|
|
|
|
- Ok(SafePathBuf(path))
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/// The options for the directory functions on the file system API.
|
|
/// The options for the directory functions on the file system API.
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
pub struct DirOperationOptions {
|
|
pub struct DirOperationOptions {
|
|
@@ -71,7 +52,7 @@ pub struct FileOperationOptions {
|
|
/// The API descriptor.
|
|
/// The API descriptor.
|
|
#[derive(Deserialize, CommandModule)]
|
|
#[derive(Deserialize, CommandModule)]
|
|
#[serde(tag = "cmd", rename_all = "camelCase")]
|
|
#[serde(tag = "cmd", rename_all = "camelCase")]
|
|
-pub enum Cmd {
|
|
|
|
|
|
+pub(crate) enum Cmd {
|
|
/// The read binary file API.
|
|
/// The read binary file API.
|
|
ReadFile {
|
|
ReadFile {
|
|
path: SafePathBuf,
|
|
path: SafePathBuf,
|
|
@@ -138,7 +119,7 @@ impl Cmd {
|
|
options.and_then(|o| o.dir),
|
|
options.and_then(|o| o.dir),
|
|
)?;
|
|
)?;
|
|
file::read_binary(&resolved_path)
|
|
file::read_binary(&resolved_path)
|
|
- .with_context(|| format!("path: {}", resolved_path.0.display()))
|
|
|
|
|
|
+ .with_context(|| format!("path: {}", resolved_path.display()))
|
|
.map_err(Into::into)
|
|
.map_err(Into::into)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -156,7 +137,7 @@ impl Cmd {
|
|
options.and_then(|o| o.dir),
|
|
options.and_then(|o| o.dir),
|
|
)?;
|
|
)?;
|
|
file::read_string(&resolved_path)
|
|
file::read_string(&resolved_path)
|
|
- .with_context(|| format!("path: {}", resolved_path.0.display()))
|
|
|
|
|
|
+ .with_context(|| format!("path: {}", resolved_path.display()))
|
|
.map_err(Into::into)
|
|
.map_err(Into::into)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -175,7 +156,7 @@ impl Cmd {
|
|
options.and_then(|o| o.dir),
|
|
options.and_then(|o| o.dir),
|
|
)?;
|
|
)?;
|
|
File::create(&resolved_path)
|
|
File::create(&resolved_path)
|
|
- .with_context(|| format!("path: {}", resolved_path.0.display()))
|
|
|
|
|
|
+ .with_context(|| format!("path: {}", resolved_path.display()))
|
|
.map_err(Into::into)
|
|
.map_err(Into::into)
|
|
.and_then(|mut f| f.write_all(&contents).map_err(|err| err.into()))
|
|
.and_then(|mut f| f.write_all(&contents).map_err(|err| err.into()))
|
|
}
|
|
}
|
|
@@ -199,7 +180,7 @@ impl Cmd {
|
|
dir,
|
|
dir,
|
|
)?;
|
|
)?;
|
|
dir::read_dir(&resolved_path, recursive)
|
|
dir::read_dir(&resolved_path, recursive)
|
|
- .with_context(|| format!("path: {}", resolved_path.0.display()))
|
|
|
|
|
|
+ .with_context(|| format!("path: {}", resolved_path.display()))
|
|
.map_err(Into::into)
|
|
.map_err(Into::into)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -230,7 +211,7 @@ impl Cmd {
|
|
None => (source, destination),
|
|
None => (source, destination),
|
|
};
|
|
};
|
|
fs::copy(src.clone(), dest.clone())
|
|
fs::copy(src.clone(), dest.clone())
|
|
- .with_context(|| format!("source: {}, dest: {}", src.0.display(), dest.0.display()))?;
|
|
|
|
|
|
+ .with_context(|| format!("source: {}, dest: {}", src.display(), dest.display()))?;
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
@@ -254,10 +235,10 @@ impl Cmd {
|
|
)?;
|
|
)?;
|
|
if recursive {
|
|
if recursive {
|
|
fs::create_dir_all(&resolved_path)
|
|
fs::create_dir_all(&resolved_path)
|
|
- .with_context(|| format!("path: {}", resolved_path.0.display()))?;
|
|
|
|
|
|
+ .with_context(|| format!("path: {}", resolved_path.display()))?;
|
|
} else {
|
|
} else {
|
|
fs::create_dir(&resolved_path)
|
|
fs::create_dir(&resolved_path)
|
|
- .with_context(|| format!("path: {} (non recursive)", resolved_path.0.display()))?;
|
|
|
|
|
|
+ .with_context(|| format!("path: {} (non recursive)", resolved_path.display()))?;
|
|
}
|
|
}
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
@@ -283,10 +264,10 @@ impl Cmd {
|
|
)?;
|
|
)?;
|
|
if recursive {
|
|
if recursive {
|
|
fs::remove_dir_all(&resolved_path)
|
|
fs::remove_dir_all(&resolved_path)
|
|
- .with_context(|| format!("path: {}", resolved_path.0.display()))?;
|
|
|
|
|
|
+ .with_context(|| format!("path: {}", resolved_path.display()))?;
|
|
} else {
|
|
} else {
|
|
fs::remove_dir(&resolved_path)
|
|
fs::remove_dir(&resolved_path)
|
|
- .with_context(|| format!("path: {} (non recursive)", resolved_path.0.display()))?;
|
|
|
|
|
|
+ .with_context(|| format!("path: {} (non recursive)", resolved_path.display()))?;
|
|
}
|
|
}
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
@@ -306,7 +287,7 @@ impl Cmd {
|
|
options.and_then(|o| o.dir),
|
|
options.and_then(|o| o.dir),
|
|
)?;
|
|
)?;
|
|
fs::remove_file(&resolved_path)
|
|
fs::remove_file(&resolved_path)
|
|
- .with_context(|| format!("path: {}", resolved_path.0.display()))?;
|
|
|
|
|
|
+ .with_context(|| format!("path: {}", resolved_path.display()))?;
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
@@ -337,7 +318,7 @@ impl Cmd {
|
|
None => (old_path, new_path),
|
|
None => (old_path, new_path),
|
|
};
|
|
};
|
|
fs::rename(&old, &new)
|
|
fs::rename(&old, &new)
|
|
- .with_context(|| format!("old: {}, new: {}", old.0.display(), new.0.display()))
|
|
|
|
|
|
+ .with_context(|| format!("old: {}, new: {}", old.display(), new.display()))
|
|
.map_err(Into::into)
|
|
.map_err(Into::into)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -354,7 +335,10 @@ fn resolve_path<R: Runtime>(
|
|
match crate::api::path::resolve_path(config, package_info, env, &path, dir) {
|
|
match crate::api::path::resolve_path(config, package_info, env, &path, dir) {
|
|
Ok(path) => {
|
|
Ok(path) => {
|
|
if window.state::<Scopes>().fs.is_allowed(&path) {
|
|
if window.state::<Scopes>().fs.is_allowed(&path) {
|
|
- Ok(SafePathBuf(path))
|
|
|
|
|
|
+ Ok(
|
|
|
|
+ // safety: the path is resolved by Tauri so it is safe
|
|
|
|
+ unsafe { SafePathBuf::new_unchecked(path) },
|
|
|
|
+ )
|
|
} else {
|
|
} else {
|
|
Err(anyhow::anyhow!(
|
|
Err(anyhow::anyhow!(
|
|
crate::Error::PathNotAllowed(path).to_string()
|
|
crate::Error::PathNotAllowed(path).to_string()
|
|
@@ -362,7 +346,7 @@ fn resolve_path<R: Runtime>(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Err(e) => super::Result::<SafePathBuf>::Err(e.into())
|
|
Err(e) => super::Result::<SafePathBuf>::Err(e.into())
|
|
- .with_context(|| format!("path: {}, base dir: {:?}", path.0.display(), dir)),
|
|
|
|
|
|
+ .with_context(|| format!("path: {}, base dir: {:?}", path.display(), dir)),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -372,18 +356,6 @@ mod tests {
|
|
|
|
|
|
use quickcheck::{Arbitrary, Gen};
|
|
use quickcheck::{Arbitrary, Gen};
|
|
|
|
|
|
- use std::path::PathBuf;
|
|
|
|
-
|
|
|
|
- impl Arbitrary for super::SafePathBuf {
|
|
|
|
- fn arbitrary(g: &mut Gen) -> Self {
|
|
|
|
- Self(PathBuf::arbitrary(g))
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
|
|
|
- Box::new(self.0.shrink().map(SafePathBuf))
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
impl Arbitrary for BaseDirectory {
|
|
impl Arbitrary for BaseDirectory {
|
|
fn arbitrary(g: &mut Gen) -> Self {
|
|
fn arbitrary(g: &mut Gen) -> Self {
|
|
if bool::arbitrary(g) {
|
|
if bool::arbitrary(g) {
|