tauri-apps / tauri

Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
https://tauri.app
Apache License 2.0
85.39k stars 2.58k forks source link

[bug] "forbidden path" when calling `exists` with absolute resource path for non-existing file #11614

Closed Phippe closed 2 days ago

Phippe commented 2 weeks ago

Describe the bug

I'm in the process of making my app compatible with Tauri 2.0 after upgrading to it recently. I'm trying to access files in the resource folder by fist calling path.exists like this:

let filePath = await path.join(await path.resourceDir(), "some_folder", "file.xlsx");
let fileExists = await exists(filePath);

This looked pretty much the same on Tauri 1.x and worked, but now on Tauri 2.0 I'm getting an exception: forbidden path: D:\path_to_repo\src-tauri\target\debug\some_folder\file.xlsx

Two weird things about all this:

Although I'm not 100% sure how the new permission system works yet, I think my app should have the correct permissions to interact with the file:

{
  "permissions": [
    "fs:default",
    "fs:allow-desktop-read-recursive",
    "fs:allow-desktop-meta-recursive",
    "fs:allow-resource-read-recursive",
    "fs:allow-resource-meta-recursive"
  ]
}

In the end, using a base directory, this code worked:

let filePath = await path.join("some_folder", "file.xlsx");
let fileExists = await exists(filePath, {baseDir: BaseDirectory.Resource});

In order to check whether it is a permission issue or not, I ran the same code for desktop files and experienced no issues doing that. All the results were correct and no exception happened.

Reproduction

Here are the various tests I did, always for both an existing and a non-existing file. First are the resource accesses with the mentioned exception and the wrong results, followed by the desktop accesses with all correct results.

let filePath = "";

// Accessing resource
console.log("\n-----------------------");

// Relative path, using join and baseDir
filePath = await path.join("some_folder", "existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Resource})); // true
filePath = await path.join("some_folder", "non_existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Resource})); // false

// Absolute path, using join, but no baseDir
filePath = await path.join(await path.resourceDir(), "some_folder", "existing_file.xlsx");
console.log(filePath, await exists(filePath)); // true
filePath = await path.join(await path.resourceDir(), "some_folder", "non_existing_file.xlsx");
console.log(filePath, await exists(filePath)); // exception, forbidden path

// Absolute path, using join and baseDir
filePath = await path.join(await path.resourceDir(), "some_folder", "existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Resource})); // false, wrong result
filePath = await path.join(await path.resourceDir(), "some_folder", "non_existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Resource})); // false, probably "wrong" result

// Now accessing desktop instead of resource
console.log("\n-----------------------");

// Relative path, using join and baseDir
filePath = await path.join("some_folder", "existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Desktop})); // true
filePath = await path.join("some_folder", "non_existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Desktop})); // false

// Absolute path, using join, but no baseDir
filePath = await path.join(await path.desktopDir(), "some_folder", "existing_file.xlsx");
console.log(filePath, await exists(filePath)); // true
filePath = await path.join(await path.desktopDir(), "some_folder", "non_existing_file.xlsx");
console.log(filePath, await exists(filePath)); // false

// Absolute path, using join and baseDir
filePath = await path.join(await path.desktopDir(), "some_folder", "existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Desktop})); // true
filePath = await path.join(await path.desktopDir(), "some_folder", "non_existing_file.xlsx");
console.log(filePath, await exists(filePath, {baseDir: BaseDirectory.Desktop})); // false

Expected behavior

No exception for this one:

let filePath = await path.join(await path.resourceDir(), "some_folder", "non_existing_file.xlsx"); // non-existing file
let fileExists = await exists(filePath);

Correct results for this one. Not that important, since the access technically shouldn't give correct results (you're appending the whole path to the base path), but it did work for the desktop directory, so...

let filePath = await path.join(await path.resourceDir(), "some_folder", "file.xlsx"); // either existing or non-existing file
let fileExists = await exists(filePath, {baseDir: BaseDirectory.Resource});

Full tauri info output

[✔] Environment
    - OS: Windows 10.0.22621 x86_64 (X64)
    ✔ WebView2: 130.0.2849.56
    ✔ MSVC: Visual Studio Community 2022
    ✔ rustc: 1.82.0 (f6e511eec 2024-10-15)
    ✔ cargo: 1.82.0 (8f40fc59f 2024-08-21)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-x86_64-pc-windows-msvc (default)
    - node: 20.11.1
    - pnpm: 8.15.5
    - yarn: 1.22.21
    - npm: 10.5.0

[-] Packages
    - tauri 🦀: 2.0.6
    - tauri-build 🦀: 2.0.2
    - wry 🦀: 0.46.3
    - tao 🦀: 0.30.5
    - @tauri-apps/api : 2.0.3
    - @tauri-apps/cli : 2.0.5

[-] Plugins
    - tauri-plugin-fs 🦀: 2.0.3
    - @tauri-apps/plugin-fs : 2.0.2
    - tauri-plugin-log 🦀: 2.0.2
    - @tauri-apps/plugin-log : 2.0.0
    - tauri-plugin-window-state 🦀: 2.0.2
    - @tauri-apps/plugin-window-state : 2.0.0
    - tauri-plugin-dialog 🦀: 2.0.3
    - @tauri-apps/plugin-dialog : 2.0.1
    - tauri-plugin-shell 🦀: 2.0.2
    - @tauri-apps/plugin-shell : 2.0.1

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../dist
    - devUrl: http://localhost:1420/
    - framework: Vue.js
    - bundler: Vite

Stack trace

No response

Additional context

No response