Boscop / web-view

Rust bindings for webview, a tiny cross-platform library to render web-based GUIs for desktop applications
MIT License
1.92k stars 175 forks source link

webkit2gtk localStorage error: "this operation is insecure" #252

Open ohmree opened 3 years ago

ohmree commented 3 years ago

I'm building a single-page app using seed and rollup, and a native wrapper using inline-assets, rust-embed and web-view (all glued together using npm and rust build scripts).

When I serve my single html file or load it locally (as a file:// url) in epiphany, firefox or chromium it works just fine, but when I embed it into the native wrapper and load the entire html contents using WebViewBuilder::content it complains about the operation being insecure (the exact error is in the issue title).

I assume this is due to how web-view loads the entire file as a data: url, and have tried various csp configurations to fix this (using my personal fork of the rollup html plugin that adds file hash csp directives along with any other csp directives it's configured to add, without the file hash directives i'd have to enable unsafe-inline for scripts).

I've tried allowing unsafe-inline for default-src and script-src and allowing data: for default-src but nothing worked, it always crashes with an extremely long message (as long as my index.html) that makes debugging impossible because the console chokes on such a giant error and freezes (when I redirect the error message to a file it takes up about 10 mb of space).

Here's how the error looks, not too helpful:

CONSOLE JS ERROR Unhandled Promise Rejection: error retrieving oauth state from local store: GetStorageError(
   JsValue(SecurityError: The operation is insecure.
   data:text/html, # the entire contents of index.html as a urlencoded string...
   )
)

Is there any way to bypass this using csp?

Thanks in advance.

ohmree commented 3 years ago

I've managed to reproduce this issue in a minimal example:

web_view::builder()
    .title("Minimal webview example")
    // .content(Content::Html(std::str::from_utf8(index_content.as_ref())?))
    .content(Content::Html(r#"<html><head></head><body><script>console.log(window.localStorage)</script></body></html>"#))
    .size(800, 600)
    .resizable(true)
    .user_data(())
    .invoke_handler(|_webview, _arg| Ok(()))
    .run()?;

And since now the console doesn't crash anymore, I can look at the value of window.location.href:

"data:text/html,%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3Cscript%3Econsole.log%28window.localStorage%29%3C%2Fscript%3E%3C%2Fbody%3E%3C%2Fhtml%3E"

Which I suspect is indeed the reason this is happening.

EDIT: here's some more info about this, which was surprisingly hard to find.

EDIT #2: I think the best option is for me to implement some sort of wrapper that can use either seed's localStorage api or something custom-made that's exposed to the browser (and to wasm_bindgen) using web-view's api.
I don't know how much work it'll be though, I might have a go at implementing it sometime soon.