mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-09-14 20:55:26 +02:00
Merge remote-tracking branch 'origin/v2' into v3
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## [2.5.2]
|
||||
|
||||
- [`db9c5998`](https://github.com/tauri-apps/plugins-workspace/commit/db9c5998feff9384f9cbbefcbe0d45937c00a1fc) ([#3531](https://github.com/tauri-apps/plugins-workspace/pull/3531) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix missing `consumer-rules.pro` on Gradle v9.
|
||||
- [`f8053e65`](https://github.com/tauri-apps/plugins-workspace/commit/f8053e659e4ccd85c1f52833411ff8417cbc5e69) ([#3527](https://github.com/tauri-apps/plugins-workspace/pull/3527) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Documented Cargo feature flags in each plugin's crate-level documentation.
|
||||
- [`685610ae`](https://github.com/tauri-apps/plugins-workspace/commit/685610ae782b668770d412f42a5d52d2cc9e497e) ([#3507](https://github.com/tauri-apps/plugins-workspace/pull/3507) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix `fs:default` and `fs:read-app-specific-dirs-recursive` not giving any command scopes
|
||||
- [`3fb27bf1`](https://github.com/tauri-apps/plugins-workspace/commit/3fb27bf13a88dd1e5aa2cc933408be02b0eafc91) ([#3504](https://github.com/tauri-apps/plugins-workspace/pull/3504) by [@vasfvitor](https://github.com/tauri-apps/plugins-workspace/../../vasfvitor)) Fixed `deny-webview-data` has no effect, and on Linux, only deny access to the webview data paths instead of the entire `$APPLOCALDATA`
|
||||
|
||||
## \[2.5.1]
|
||||
|
||||
- [`ec054013`](https://github.com/tauri-apps/plugins-workspace/commit/ec0540138bece081e9a87982091947360e61987a) ([#3323](https://github.com/tauri-apps/plugins-workspace/pull/3323) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated dependency `toml` from 0.9 to 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.5.1"
|
||||
version = "2.5.2"
|
||||
description = "Access the file system."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
@@ -8,6 +8,13 @@ edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
links = "tauri-plugin-fs"
|
||||
exclude = [
|
||||
"/banner.png",
|
||||
"/guest-js",
|
||||
"/package.json",
|
||||
"/rollup.config.js",
|
||||
"/tsconfig.json",
|
||||
]
|
||||
|
||||
[package.metadata.platforms.support]
|
||||
windows = { level = "full", notes = "Apps installed via MSI or NSIS in `perMachine` and `both` mode require admin permissions for write access in `$RESOURCES` folder" }
|
||||
|
||||
@@ -14,15 +14,7 @@ android {
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-fs",
|
||||
"version": "2.5.1",
|
||||
"version": "2.5.2",
|
||||
"description": "Access the file system.",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
|
||||
@@ -22,7 +22,9 @@ the `mkdir` command.
|
||||
|
||||
This default permission set prevents access to critical components
|
||||
of the Tauri application by default.
|
||||
On Windows the webview data folder access is denied.
|
||||
|
||||
- On Windows the access to webview data folder `$APPLOCALDATA/EBWebView` is denied.
|
||||
- On Linux the access to webview data paths inside `$APPLOCALDATA` are denied.
|
||||
|
||||
#### This default permission set includes the following:
|
||||
|
||||
@@ -3701,8 +3703,19 @@ This denies access to dangerous Tauri relevant files and folders by default.
|
||||
</td>
|
||||
<td>
|
||||
|
||||
This denies read access to the
|
||||
`$APPLOCALDATA` folder on linux as the webview data and configuration values are stored here.
|
||||
This denies access to the following paths
|
||||
|
||||
- `$APPLOCALDATA/CacheStorage/**`
|
||||
- `$APPLOCALDATA/cookies`
|
||||
- `$APPLOCALDATA/hsts-storage.sqlite`
|
||||
- `$APPLOCALDATA/serviceworkers/**`
|
||||
- `$APPLOCALDATA/WebKitCache/**`
|
||||
- `$APPLOCALDATA/databases/**`
|
||||
- `$APPLOCALDATA/localstorage/**`
|
||||
- `$APPLOCALDATA/mediakeys/**`
|
||||
- `$APPLOCALDATA/storage/**`
|
||||
|
||||
on linux as the webview data and configuration values are stored here.
|
||||
Allowing access can lead to sensitive information disclosure and should be well considered.
|
||||
|
||||
</td>
|
||||
@@ -3716,7 +3729,7 @@ Allowing access can lead to sensitive information disclosure and should be well
|
||||
</td>
|
||||
<td>
|
||||
|
||||
This denies read access to the
|
||||
This denies access to the
|
||||
`$APPLOCALDATA/EBWebView` folder on windows as the webview data and configuration values are stored here.
|
||||
Allowing access can lead to sensitive information disclosure and should be well considered.
|
||||
|
||||
@@ -3745,7 +3758,7 @@ This enables all read related commands without any pre-configured accessible pat
|
||||
<td>
|
||||
|
||||
This permission allows recursive read functionality on the application
|
||||
specific base directories.
|
||||
specific base directories.
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"$schema" = "schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
[[set]]
|
||||
identifier = "create-app-specific-dirs"
|
||||
description = """
|
||||
This permissions allows to create the application specific directories.
|
||||
"""
|
||||
commands.allow = ["mkdir", "scope-app-index"]
|
||||
permissions = ["allow-mkdir", "scope-app-index"]
|
||||
|
||||
@@ -24,7 +24,9 @@ the `mkdir` command.
|
||||
|
||||
This default permission set prevents access to critical components
|
||||
of the Tauri application by default.
|
||||
On Windows the webview data folder access is denied.
|
||||
|
||||
- On Windows the access to webview data folder `$APPLOCALDATA/EBWebView` is denied.
|
||||
- On Linux the access to webview data paths inside `$APPLOCALDATA` are denied.
|
||||
"""
|
||||
permissions = [
|
||||
"create-app-specific-dirs",
|
||||
|
||||
@@ -2,18 +2,47 @@
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-webview-data-linux"
|
||||
description = """This denies read access to the
|
||||
`$APPLOCALDATA` folder on linux as the webview data and configuration values are stored here.
|
||||
Allowing access can lead to sensitive information disclosure and should be well considered."""
|
||||
description = """This denies access to the following paths
|
||||
|
||||
[[scope.deny]]
|
||||
path = "$APPLOCALDATA/**"
|
||||
- `$APPLOCALDATA/CacheStorage/**`
|
||||
- `$APPLOCALDATA/cookies`
|
||||
- `$APPLOCALDATA/hsts-storage.sqlite`
|
||||
- `$APPLOCALDATA/serviceworkers/**`
|
||||
- `$APPLOCALDATA/WebKitCache/**`
|
||||
- `$APPLOCALDATA/databases/**`
|
||||
- `$APPLOCALDATA/localstorage/**`
|
||||
- `$APPLOCALDATA/mediakeys/**`
|
||||
- `$APPLOCALDATA/storage/**`
|
||||
|
||||
on linux as the webview data and configuration values are stored here.
|
||||
Allowing access can lead to sensitive information disclosure and should be well considered."""
|
||||
platforms = ["linux"]
|
||||
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/CacheStorage/**"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/cookies"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/hsts-storage.sqlite"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/serviceworkers/**"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/WebKitCache/**"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/databases/**"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/localstorage/**"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/mediakeys/**"
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/storage/**"
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-webview-data-windows"
|
||||
description = """This denies read access to the
|
||||
description = """This denies access to the
|
||||
`$APPLOCALDATA/EBWebView` folder on windows as the webview data and configuration values are stored here.
|
||||
Allowing access can lead to sensitive information disclosure and should be well considered."""
|
||||
platforms = ["windows"]
|
||||
|
||||
[[scope.deny]]
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/EBWebView/**"
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
"$schema" = "schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
[[set]]
|
||||
identifier = "read-app-specific-dirs-recursive"
|
||||
description = """
|
||||
This permission allows recursive read functionality on the application
|
||||
specific base directories.
|
||||
specific base directories.
|
||||
"""
|
||||
commands.allow = [
|
||||
"read_dir",
|
||||
"read_file",
|
||||
"read_text_file",
|
||||
"read_text_file_lines",
|
||||
"read_text_file_lines_next",
|
||||
"exists",
|
||||
permissions = [
|
||||
"allow-read-dir",
|
||||
"allow-read-file",
|
||||
"allow-read-text-file",
|
||||
"allow-read-text-file-lines",
|
||||
"allow-read-text-file-lines-next",
|
||||
"allow-exists",
|
||||
"scope-app-recursive",
|
||||
]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+106
-109
@@ -74,7 +74,7 @@ pub type CommandResult<T> = std::result::Result<T, CommandError>;
|
||||
/// Represents either a plain PathBuf or a PathHandle that manages security-scoped resources.
|
||||
pub enum PathKind<R: Runtime> {
|
||||
/// A plain path that doesn't manage security-scoped resources.
|
||||
#[allow(dead_code)] // only used on mobile
|
||||
#[cfg(mobile)] // only used on mobile
|
||||
Path(PathBuf),
|
||||
/// A path handle that manages security-scoped resources and will clean them up on drop.
|
||||
Handle(PathHandle<R>),
|
||||
@@ -84,6 +84,7 @@ impl<R: Runtime> PathKind<R> {
|
||||
/// Get a reference to the underlying path.
|
||||
pub fn as_path(&self) -> &Path {
|
||||
match self {
|
||||
#[cfg(mobile)]
|
||||
PathKind::Path(p) => p.as_ref(),
|
||||
PathKind::Handle(h) => h.as_ref(),
|
||||
}
|
||||
@@ -92,6 +93,7 @@ impl<R: Runtime> PathKind<R> {
|
||||
/// Get a reference to the underlying PathBuf.
|
||||
pub fn as_path_buf(&self) -> &PathBuf {
|
||||
match self {
|
||||
#[cfg(mobile)]
|
||||
PathKind::Path(p) => p,
|
||||
PathKind::Handle(h) => h,
|
||||
}
|
||||
@@ -114,27 +116,13 @@ impl<R: Runtime> AsRef<PathBuf> for PathKind<R> {
|
||||
pub struct FileHandle<R: Runtime> {
|
||||
file: File,
|
||||
path: PathKind<R>,
|
||||
#[allow(dead_code)] // Used in Drop implementation
|
||||
#[cfg(target_os = "ios")]
|
||||
path_: SafeFilePath,
|
||||
#[allow(dead_code)] // Used in Drop implementation
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle: tauri::AppHandle<R>,
|
||||
}
|
||||
|
||||
impl<R: Runtime> FileHandle<R> {
|
||||
fn new(
|
||||
file: File,
|
||||
path: PathKind<R>,
|
||||
path_: SafeFilePath,
|
||||
app_handle: tauri::AppHandle<R>,
|
||||
) -> Self {
|
||||
Self {
|
||||
file,
|
||||
path,
|
||||
path_,
|
||||
app_handle,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the resolved path.
|
||||
pub fn path(&self) -> &Path {
|
||||
self.path.as_path()
|
||||
@@ -155,41 +143,39 @@ impl<R: Runtime> DerefMut for FileHandle<R> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
impl<R: Runtime> Drop for FileHandle<R> {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
// Only clean up if we have a plain PathBuf, not a PathHandle
|
||||
// PathHandle will handle its own cleanup when it's dropped
|
||||
if let PathKind::Path(_) = &self.path {
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
// Only clean up if we have a plain PathBuf, not a PathHandle
|
||||
// PathHandle will handle its own cleanup when it's dropped
|
||||
if let PathKind::Path(_) = &self.path {
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
|
||||
// Only clean up if we're tracking this resource
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
// Only clean up if we're tracking this resource
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!("Stopping accessing security-scoped resource for URL: {url} on drop");
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(
|
||||
url.clone(),
|
||||
));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!(
|
||||
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||
);
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,38 +222,36 @@ impl<R: Runtime> AsRef<PathBuf> for PathHandle<R> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
impl<R: Runtime> Drop for PathHandle<R> {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
|
||||
// Only clean up if we're tracking this resource (i.e., resolve_path started it)
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
// Only clean up if we're tracking this resource (i.e., resolve_path started it)
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!(
|
||||
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||
);
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!(
|
||||
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||
);
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,6 +272,7 @@ pub fn create<R: Runtime>(
|
||||
path: SafeFilePath,
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<ResourceId> {
|
||||
#[cfg(target_os = "ios")]
|
||||
let path_ = path.clone();
|
||||
let resolved_path_handle = resolve_path(
|
||||
"create",
|
||||
@@ -303,13 +288,16 @@ pub fn create<R: Runtime>(
|
||||
resolved_path_handle.display()
|
||||
)
|
||||
})?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let app_handle = webview.app_handle().clone();
|
||||
let file_handle = FileHandle::new(
|
||||
let file_handle = FileHandle {
|
||||
file,
|
||||
PathKind::Handle(resolved_path_handle),
|
||||
path: PathKind::Handle(resolved_path_handle),
|
||||
#[cfg(target_os = "ios")]
|
||||
path_,
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle,
|
||||
);
|
||||
};
|
||||
let rid = webview
|
||||
.resources_table()
|
||||
.add(StdFileResource::new(file_handle));
|
||||
@@ -1417,6 +1405,7 @@ fn resolve_file_in_fs<R: Runtime>(
|
||||
path: SafeFilePath,
|
||||
open_options: OpenOptions,
|
||||
) -> CommandResult<FileHandle<R>> {
|
||||
#[cfg(target_os = "ios")]
|
||||
let path_ = path.clone();
|
||||
let resolved_path_handle = resolve_path(
|
||||
permission,
|
||||
@@ -1436,13 +1425,16 @@ fn resolve_file_in_fs<R: Runtime>(
|
||||
)
|
||||
})?;
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
let app_handle = webview.app_handle().clone();
|
||||
Ok(FileHandle::new(
|
||||
Ok(FileHandle {
|
||||
file,
|
||||
PathKind::Handle(resolved_path_handle),
|
||||
path: PathKind::Handle(resolved_path_handle),
|
||||
#[cfg(target_os = "ios")]
|
||||
path_,
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(mobile)]
|
||||
@@ -1456,6 +1448,7 @@ pub fn resolve_file<R: Runtime>(
|
||||
) -> CommandResult<FileHandle<R>> {
|
||||
use crate::FsExt;
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
let path_ = path.clone();
|
||||
match path {
|
||||
SafeFilePath::Url(url) => {
|
||||
@@ -1463,13 +1456,16 @@ pub fn resolve_file<R: Runtime>(
|
||||
let file = webview
|
||||
.fs()
|
||||
.open(SafeFilePath::Url(url.clone()), open_options.options)?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let app_handle = webview.app_handle().clone();
|
||||
Ok(FileHandle::new(
|
||||
Ok(FileHandle {
|
||||
file,
|
||||
PathKind::Path(resolved_path),
|
||||
path: PathKind::Path(resolved_path),
|
||||
#[cfg(target_os = "ios")]
|
||||
path_,
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle,
|
||||
))
|
||||
})
|
||||
}
|
||||
SafeFilePath::Path(path) => resolve_file_in_fs(
|
||||
permission,
|
||||
@@ -1494,36 +1490,37 @@ pub fn resolve_path<R: Runtime>(
|
||||
// On iOS, start accessing security-scoped resource if the path is a file URL
|
||||
// Only if it hasn't been started already via start_accessing_security_scoped_resource
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
if let SafeFilePath::Url(url) = &path {
|
||||
if url.scheme() == "file" {
|
||||
use objc2_foundation::{NSString, NSURL};
|
||||
if let SafeFilePath::Url(url) = &path {
|
||||
if url.scheme() == "file" {
|
||||
use objc2_foundation::{NSString, NSURL};
|
||||
|
||||
let security_scoped_resources = webview.state::<crate::SecurityScopedResources>();
|
||||
let security_scoped_resources = webview.state::<crate::SecurityScopedResources>();
|
||||
|
||||
// Check if already active (started via start_accessing_security_scoped_resource)
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
let url_nsstring = NSString::from_str(url.as_str());
|
||||
let ns_url = unsafe { NSURL::URLWithString(&url_nsstring) };
|
||||
if let Some(ns_url) = ns_url {
|
||||
// Start accessing the security-scoped resource
|
||||
// This is required for files outside the app's sandbox (e.g., from file picker)
|
||||
unsafe {
|
||||
let success = ns_url.startAccessingSecurityScopedResource();
|
||||
if success {
|
||||
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str());
|
||||
// Track it so we know to clean it up
|
||||
security_scoped_resources.track_manually(url.as_str().to_string());
|
||||
} else {
|
||||
log::warn!("Failed to start accessing security-scoped resource for URL: {}", url.as_str());
|
||||
}
|
||||
// Check if already active (started via start_accessing_security_scoped_resource)
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
let url_nsstring = NSString::from_str(url.as_str());
|
||||
let ns_url = unsafe { NSURL::URLWithString(&url_nsstring) };
|
||||
if let Some(ns_url) = ns_url {
|
||||
// Start accessing the security-scoped resource
|
||||
// This is required for files outside the app's sandbox (e.g., from file picker)
|
||||
unsafe {
|
||||
let success = ns_url.startAccessingSecurityScopedResource();
|
||||
if success {
|
||||
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str());
|
||||
// Track it so we know to clean it up
|
||||
security_scoped_resources.track_manually(url.as_str().to_string());
|
||||
} else {
|
||||
log::warn!(
|
||||
"Failed to start accessing security-scoped resource for URL: {}",
|
||||
url.as_str()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str());
|
||||
}
|
||||
} else {
|
||||
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str());
|
||||
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str());
|
||||
}
|
||||
} else {
|
||||
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Access the file system.
|
||||
//!
|
||||
//! ## Cargo features
|
||||
//!
|
||||
//! - **watch**: Enables the `watch` command backed by [`notify`](http://crates.io/crates/notify).
|
||||
|
||||
// TODO(v3): consider redesign the API to implement automatic stopAccessingSecurityScopedResource on iOS
|
||||
// this likely requires returning a handle to a resource so we can impl Drop for it
|
||||
|
||||
Reference in New Issue
Block a user