tauri icon indicating copy to clipboard operation
tauri copied to clipboard

[feat] CORS workaround

Open 0xDevrim opened this issue 1 year ago • 4 comments

Describe the problem

I've hit a roadblock with CORS and I am stuck. This isn't necessarily an issue caused by Tauri but I believe something may be done about it. I'm aware we cannot simply disable CORS as Tauri isn't chromium.

My specific use case:

I have user generated html documents which users can download to their devices via my Tauri app. It isn't a simple as just displaying the iframes as I need to interact with them via the app window.

The users can view their html documents (I have a carousel like slider). When a document is in view, I call a js function inside these html documents from the app. At the moment, this is being blocked due to protocol mismatch.

Blocked a frame with origin "tauri://localhost" from accessing a frame with origin "asset://localhost".  The frame requesting access has a protocol of "tauri", the frame being accessed has a protocol of "asset". Protocols must match

Describe the solution you'd like

One of the ways I think this can be solved is via having a symlink. I've solved similar CORS related issues on the web with this method.

At http://localhost:1420/{reserved_path_for_symlink}, tauri://localhost/{reserved_path_for_symlink} and custom protocols pointing to user defined locations.

This could be configurable via tauri.conf.json. Ie; %APPDATA% => /appDataDir.

"symlink": [
  {
    "targetPath": "%APPDATA%",
    "linkPath": "appDataDir"
  },
]

Alternatives considered

For the time being, I'm using fetch to read the contents of the html document and writing the result to the iframe tag. This isn't ideal as it's causing other issues with the contents itself.

Additional context

Message posting is not a solution as I have no control over the html files.

0xDevrim avatar Dec 05 '23 12:12 0xDevrim

The Solution section sounds pretty much like https://github.com/tauri-apps/tauri/issues/5302 to me. Do you agree? If so i'd close this as a duplicate but at least we have something more specific to watch out for now when it's being implemented so thatnks for that :)

FabianLars avatar Dec 05 '23 14:12 FabianLars

The Solution section sounds pretty much like #5302 to me. Do you agree? If so i'd close this as a duplicate but at least we have something more specific to watch out for now when it's being implemented so thatnks for that :)

I'm reluctant to say it is. In terms of the iframes are concerned at least. In my experience, having a symlink - which is technically the same as having the assets directly in the same location is much safer than communication mechanisms. But again networking isn't my expertise area so I don't know if the suggestion made in the issue you linked will help with the issues I've been having.

0xDevrim avatar Dec 06 '23 11:12 0xDevrim

Yeah so symlinks aren't really a thing here. There is no actual filesystem or network involved when serving the frontend files (distDir), it's all stored inside the binary and loaded from memory.

But you're right, the other issue focuses a bit much on ipc stuff. I really only looked at the title tbh. I still think both issues are essentially talking about the same thing but since the focus is so vastly different i'll keep both open for now.

FabianLars avatar Dec 06 '23 14:12 FabianLars

Side note: Microsoft's WebView2 allows to access content from iframes on different origins. No other engines (as far as I know) allow this.

We have a similar use case, and it works on Windows, but on other platform we hit the security wall.

AleVul avatar Feb 20 '24 13:02 AleVul

I am curious if a really small instance of Actix is narrow enough to fill this use case?

WalrusSoup avatar Mar 20 '24 16:03 WalrusSoup

I am curious if a really small instance of Actix is narrow enough to fill this use case?

Yeah, that's how I've solved it for the time being.

use actix_web::{web, App, HttpServer};
use actix_files as actix_fs;
...

async fn start_server(dir_path: String) -> std::io::Result<()> {
    let server = HttpServer::new(move || {
        App::new()
            .service(web::resource("/").to(|| async { "Hello world!" }))
            .service(actix_fs::Files::new("/", &dir_path).show_files_listing())
    })
    .bind("127.0.0.1:0")?;
    let local_addr = server.addrs().first().unwrap().to_string();
    set_server_address(local_addr);
    server.run().await
}

...

#[tokio::main]
async fn main() {
    tauri::Builder::default()
        ...
        .setup(|app| {
            let app_handle = app.app_handle();
            let binding = app_handle.path_resolver().app_data_dir().unwrap();
            let app_data_dir = binding.to_str().unwrap().to_string();

            // Run the server on a background thread
            std::thread::spawn(move || {
                let runtime = tokio::runtime::Builder::new_multi_thread()
                    .worker_threads(4) // Adjust the number of threads as needed
                    .enable_all()
                    .build()
                    .unwrap();
                runtime.block_on(start_server(app_data_dir))
            });

            Ok(())
        })
        ...
}

FE:

  const getServerAddress = async () => {
    const address = await invoke('get_server_address');
  
    if (address) {
      dispatch({ type: 'UPDATE_SERVER_ADDRESS', payload: address });
    } else {
      console.log('Server address not set yet');
    }
  };
  ...

  src={`http://${server}/...`}

0xDevrim avatar Mar 28 '24 01:03 0xDevrim