From effe5871aff1267a73ecbba1693304941a691932 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Tue, 19 Dec 2023 10:19:26 -0300 Subject: [PATCH] fix(core): scope checks on Android (#8420) * fix(core): scope checks on Android On Android, when we call canonicalize() on "/data/user/0/appid" (which is the data dir), the result is a "/data/data/appid" path, so we need to adjust our scope for that. * clarify code * apply the logic to all targets --- .changes/fix-android-scope.md | 5 ++++ core/tauri/src/scope/fs.rs | 52 +++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 .changes/fix-android-scope.md diff --git a/.changes/fix-android-scope.md b/.changes/fix-android-scope.md new file mode 100644 index 000000000..4cab7f5d7 --- /dev/null +++ b/.changes/fix-android-scope.md @@ -0,0 +1,5 @@ +--- +"tauri": patch:bug +--- + +Fixes file scope checks on Android. diff --git a/core/tauri/src/scope/fs.rs b/core/tauri/src/scope/fs.rs index b842299bf..934f0a584 100644 --- a/core/tauri/src/scope/fs.rs +++ b/core/tauri/src/scope/fs.rs @@ -79,14 +79,54 @@ fn push_pattern, F: Fn(&str) -> Result crate::Result<()> { let path: PathBuf = pattern.as_ref().components().collect(); list.insert(f(&path.to_string_lossy())?); - #[cfg(windows)] - { - if let Ok(p) = std::fs::canonicalize(&path) { - list.insert(f(&p.to_string_lossy())?); - } else { - list.insert(f(&format!("\\\\?\\{}", path.display()))?); + + let mut path = path; + let mut checked_path = None; + + // attempt to canonicalize parents in case we have a path like `/data/user/0/appid/**` + // where `**` obviously does not exist but we need to canonicalize the parent + // + // example: given the `/data/user/0/appid/assets/*` path, + // it's a glob pattern so it won't exist (canonicalize() fails); + // + // the second iteration needs to check `/data/user/0/appid/assets` and save the `*` component to append later. + // + // if it also does not exist, a third iteration is required to check `/data/user/0/appid` + // with `assets/*` as the cached value (`checked_path` variable) + // on Android that gets canonicalized to `/data/data/appid` so the final value will be `/data/data/appid/assets/*` + // which is the value we want to check when we execute the `is_allowed` function + let canonicalized = loop { + if let Ok(path) = path.canonicalize() { + break Some(if let Some(p) = checked_path { + path.join(p) + } else { + path + }); } + + // get the last component of the path as an OsStr + let last = path.iter().next_back().map(PathBuf::from); + if let Some(mut p) = last { + // remove the last component of the path + // so the next iteration checks its parent + path.pop(); + // append the already checked path to the last component + if let Some(checked_path) = &checked_path { + p.push(checked_path); + } + // replace the checked path with the current value + checked_path.replace(p); + } else { + break None; + } + }; + + if let Some(p) = canonicalized { + list.insert(f(&p.to_string_lossy())?); + } else if cfg!(windows) { + list.insert(f(&format!("\\\\?\\{}", path.display()))?); } + Ok(()) }