From eb1322df4ce10aeedb48004848cdd50d4624d717 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 1 May 2025 03:58:25 -0400 Subject: [PATCH] proxy requests through tauri to avoid 3rd party cookie ban --- Cargo.lock | 54 +++++++++++++++++++ crates/desktop/tauri-artcraft/Cargo.toml | 1 + .../tauri-artcraft/capabilities/default.json | 10 +++- crates/desktop/tauri-artcraft/src/lib.rs | 2 + .../persist_storyteller_cookies_task.rs | 14 +++-- .../GalleryRootComponent.tsx | 1 + .../app/src/Classes/ApiManager/ApiManager.ts | 2 + frontend/apps/editor3d/package.json | 1 + frontend/libs/api/src/lib/ApiManager.ts | 2 + .../libs/tauri-utils/src/lib/FetchProxy.ts | 27 ++++++++++ .../libs/tauri-utils/src/lib/tauri-utils.tsx | 1 + frontend/package-lock.json | 10 ++++ 12 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 frontend/libs/tauri-utils/src/lib/FetchProxy.ts diff --git a/Cargo.lock b/Cargo.lock index 9622c08829..4752764ce5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2877,6 +2877,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + [[package]] name = "datetimes" version = "0.0.1" @@ -12095,6 +12101,7 @@ dependencies = [ "subprocess_common", "tauri", "tauri-build", + "tauri-plugin-http", "tauri-plugin-log", "tempdir", "tempfile", @@ -12184,6 +12191,53 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-plugin-fs" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88371e340ad2f07409a3b68294abe73f20bc9c1bc1b631a31dc37a3d0161f682" +dependencies = [ + "anyhow", + "dunce", + "glob", + "percent-encoding", + "schemars", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.12", + "toml 0.8.20", + "url", + "uuid 1.8.0", +] + +[[package]] +name = "tauri-plugin-http" +version = "2.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40dcd6c922a1885e1f0bcebc6768fec6e005bd4b9001c5d90a2f5d4cab297729" +dependencies = [ + "bytes 1.10.0", + "cookie_store", + "data-url", + "http 1.1.0", + "regex", + "reqwest 0.12.15", + "schemars", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.12", + "tokio", + "url", + "urlpattern", +] + [[package]] name = "tauri-plugin-log" version = "2.3.1" diff --git a/crates/desktop/tauri-artcraft/Cargo.toml b/crates/desktop/tauri-artcraft/Cargo.toml index 38a40fef82..bf7f46dd58 100644 --- a/crates/desktop/tauri-artcraft/Cargo.toml +++ b/crates/desktop/tauri-artcraft/Cargo.toml @@ -54,6 +54,7 @@ serde_derive = { workspace = true } serde_json = { workspace = true } serde_yaml = { workspace = true } tauri = { version = "2.4.1", features = ["unstable"] } +tauri-plugin-http = "2.0.0" tauri-plugin-log = "2.3.1" tempdir = "0.3.7" tempfile = "3.18.0" diff --git a/crates/desktop/tauri-artcraft/capabilities/default.json b/crates/desktop/tauri-artcraft/capabilities/default.json index f3543164cb..6953ca51dc 100644 --- a/crates/desktop/tauri-artcraft/capabilities/default.json +++ b/crates/desktop/tauri-artcraft/capabilities/default.json @@ -7,6 +7,14 @@ ], "permissions": [ "core:default", - "log:default" + "log:default", + { + "identifier": "http:default", + "allow": [ + { "url": "https://*.storyteller.ai" }, + { "url": "https://*.fakeyou.com" } + ], + "deny": [{ "url": "https://private.tauri.app" }] + } ] } \ No newline at end of file diff --git a/crates/desktop/tauri-artcraft/src/lib.rs b/crates/desktop/tauri-artcraft/src/lib.rs index a5489d9926..59a00295f4 100644 --- a/crates/desktop/tauri-artcraft/src/lib.rs +++ b/crates/desktop/tauri-artcraft/src/lib.rs @@ -21,6 +21,7 @@ use crate::threads::main_window_thread::main_window_thread::main_window_thread; use crate::threads::sora_session_login_thread::sora_session_login_thread; use crate::threads::sora_task_polling_thread::sora_task_polling_thread; +use tauri_plugin_http; use tauri_plugin_log::Target; use tauri_plugin_log::TargetKind; @@ -51,6 +52,7 @@ pub fn run() { println!("Initializing backend runtime..."); tauri::Builder::default() + .plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_log::Builder::new() .level(log::LevelFilter::Info) .targets(vec![ diff --git a/crates/desktop/tauri-artcraft/src/threads/main_window_thread/persist_storyteller_cookies_task.rs b/crates/desktop/tauri-artcraft/src/threads/main_window_thread/persist_storyteller_cookies_task.rs index bdfbb60fa1..94ab66c450 100644 --- a/crates/desktop/tauri-artcraft/src/threads/main_window_thread/persist_storyteller_cookies_task.rs +++ b/crates/desktop/tauri-artcraft/src/threads/main_window_thread/persist_storyteller_cookies_task.rs @@ -89,14 +89,18 @@ async fn persist_webview_cookies( pub async fn get_storyteller_cookies(webview: &Webview) -> AnyhowResult { debug!("Getting storyteller cookies..."); - // FIXME: THIS IS A TOTAL HACK. / DO NOT REMOVE. - // NB: If we don't call a method on the webview, the very next call to get cookies will deadlock. - if let Ok(url) = webview.url() { - debug!("For url: {:?}", url); - } + //// FIXME: THIS IS A TOTAL HACK. / DO NOT REMOVE. + //// NB: If we don't call a method on the webview, the very next call to get cookies will deadlock. + //if let Ok(url) = webview.url() { + // debug!("For url: {:?}", url); + //} let cookies = webview.cookies_for_url(STORYTELLER_ROOT_COOKIE_URL.clone())?; + info!("Got storyteller cookies: {:?}", cookies); + info!("Got storyteller cookies: {:?}", cookies.len()); + info!("Got storyteller location: {:?}", webview.url()); + let mut avt_cookie = None; let mut session_cookie = None; diff --git a/frontend/apps/editor2d/src/GalleryRootComponent/GalleryRootComponent.tsx b/frontend/apps/editor2d/src/GalleryRootComponent/GalleryRootComponent.tsx index 60a1264730..068af553c7 100644 --- a/frontend/apps/editor2d/src/GalleryRootComponent/GalleryRootComponent.tsx +++ b/frontend/apps/editor2d/src/GalleryRootComponent/GalleryRootComponent.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from "react"; import { Button } from "~/components/ui" const testUrl = "https://api.fakeyou.com/v1/media_files/list/user/hanashi?include_user_uploads=true&page_size=24&filter_media_classes=unknown"; + const getTestData = (callback: (data: any) => void) => { const netCall = async () => { // GET the test url diff --git a/frontend/apps/editor3d/app/src/Classes/ApiManager/ApiManager.ts b/frontend/apps/editor3d/app/src/Classes/ApiManager/ApiManager.ts index b676745d31..6c1a79de9f 100644 --- a/frontend/apps/editor3d/app/src/Classes/ApiManager/ApiManager.ts +++ b/frontend/apps/editor3d/app/src/Classes/ApiManager/ApiManager.ts @@ -1,6 +1,8 @@ import { GetBuildEnvironment } from "~/BuildEnvironment"; import environmentVariables from "../EnvironmentVariables"; import { Configs } from "~/configs"; +//import { fetch } from '@tauri-apps/plugin-http' +import { FetchProxy as fetch } from "@storyteller/tauri-utils"; type NonNullableObject = NonNullable; diff --git a/frontend/apps/editor3d/package.json b/frontend/apps/editor3d/package.json index 13a115d6da..761c2f581f 100644 --- a/frontend/apps/editor3d/package.json +++ b/frontend/apps/editor3d/package.json @@ -45,6 +45,7 @@ "@remix-run/react": "^2.8.1", "@remix-run/router": "^1.15.3", "@remix-run/serve": "^2.8.1", + "@tauri-apps/plugin-http": "^2.4.3", "@tweenjs/tween.js": "^18.6.4", "@types/lodash": "^4.17.6", "@types/react-virtualized": "^9.22.2", diff --git a/frontend/libs/api/src/lib/ApiManager.ts b/frontend/libs/api/src/lib/ApiManager.ts index 5299458e04..784d2757c9 100644 --- a/frontend/libs/api/src/lib/ApiManager.ts +++ b/frontend/libs/api/src/lib/ApiManager.ts @@ -1,5 +1,7 @@ // import { bool } from "@techstark/opencv-js"; import { API_TARGETS } from "./enums/Api.js"; +//import { fetch } from '@tauri-apps/plugin-http' +import { FetchProxy as fetch } from "@storyteller/tauri-utils"; type NonNullableObject = NonNullable; diff --git a/frontend/libs/tauri-utils/src/lib/FetchProxy.ts b/frontend/libs/tauri-utils/src/lib/FetchProxy.ts new file mode 100644 index 0000000000..3a15fab3c8 --- /dev/null +++ b/frontend/libs/tauri-utils/src/lib/FetchProxy.ts @@ -0,0 +1,27 @@ +import { IsDesktopApp } from "./IsDesktopApp"; +import { fetch as tauriFetch } from '@tauri-apps/plugin-http' + +// TODO: Match the function signature in typescript annotations: +// export declare function fetch(input: URL | Request | string, init?: RequestInit & ClientOptions): Promise; + +/// Third party cookies are blocked on Mac, which means all of our API calls +/// to our backend fail. Fortunately Tauri exposes a drop-in mixin for the +/// Javascript fetch API that can proxy all requests to Rust, and then onto +/// the downstream service. It maintains its own cookie jar and avoids the +/// 3rd party cookie issue. +/// +/// This function basically determines if we're in Tauri or on the Web. If the +/// former, we replace Fetch with the Tauri fetch. If the latter, we dispatch +/// to the normal browser fetch. + +export function FetchProxy(args: any) : Promise { + if (IsDesktopApp()) { + // Tauri proxy fetch + return tauriFetch(args); + } else { + // Browser native fetch + return fetch(args); + } +} + +(window as any).FetchProxy = FetchProxy; diff --git a/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx b/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx index e772f78a2b..62526e40f7 100644 --- a/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx +++ b/frontend/libs/tauri-utils/src/lib/tauri-utils.tsx @@ -1 +1,2 @@ export { IsDesktopApp } from './IsDesktopApp'; +export { FetchProxy } from './FetchProxy'; \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 103b9efb24..aefe8fec23 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1272,6 +1272,7 @@ "@remix-run/react": "^2.8.1", "@remix-run/router": "^1.15.3", "@remix-run/serve": "^2.8.1", + "@tauri-apps/plugin-http": "^2.4.3", "@tweenjs/tween.js": "^18.6.4", "@types/lodash": "^4.17.6", "@types/react-virtualized": "^9.22.2", @@ -11135,6 +11136,15 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/plugin-http": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-http/-/plugin-http-2.4.3.tgz", + "integrity": "sha512-Us8X+FikzpaZRNr4kH4HLwyXascHbM42p6LxAqRTQnHPrrqp1usaH4vxWAZalPvTbHJ3gBEMJPHusFJgtjGJjA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.0.0" + } + }, "node_modules/@techstark/opencv-js": { "version": "4.10.0-release.1", "resolved": "https://registry.npmjs.org/@techstark/opencv-js/-/opencv-js-4.10.0-release.1.tgz",