Przeglądaj źródła

feat(core): Allow http origin on Windows, fixes: #3007 (#7645)

Co-authored-by: Lucas Nogueira <118899497+lucasfernog-crabnebula@users.noreply.github.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Fabian-Lars 1 rok temu
rodzic
commit
9aa34ada57

+ 8 - 0
.changes/windows-http-scheme.md

@@ -0,0 +1,8 @@
+---
+'tauri': 'patch:enhance'
+'tauri-runtime': 'patch:enhance'
+'tauri-runtime-wry': 'patch:enhance'
+'tauri-utils': 'patch:enhance'
+---
+
+Add setting to switch to `http://<scheme>.localhost/` for custom protocols on Windows.

+ 7 - 0
core/tauri-config-schema/schema.json

@@ -167,6 +167,7 @@
         "security": {
           "dangerousDisableAssetCspModification": false,
           "dangerousRemoteDomainIpcAccess": [],
+          "dangerousUseHttpScheme": false,
           "freezePrototype": false
         },
         "updater": {
@@ -423,6 +424,7 @@
           "default": {
             "dangerousDisableAssetCspModification": false,
             "dangerousRemoteDomainIpcAccess": [],
+            "dangerousUseHttpScheme": false,
             "freezePrototype": false
           },
           "allOf": [
@@ -2740,6 +2742,11 @@
           "items": {
             "$ref": "#/definitions/RemoteDomainAccessScope"
           }
+        },
+        "dangerousUseHttpScheme": {
+          "description": "Sets whether the custom protocols should use `http://<scheme>.localhost` instead of the default `https://<scheme>.localhost` on Windows.\n\n**WARNING:** Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints and is therefore less secure but will match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.",
+          "default": false,
+          "type": "boolean"
         }
       },
       "additionalProperties": false

+ 5 - 0
core/tauri-runtime-wry/src/lib.rs

@@ -3196,6 +3196,11 @@ fn create_webview<T: UserEvent>(
     });
   }
 
+  #[cfg(windows)]
+  {
+    webview_builder = webview_builder.with_https_scheme(!pending.http_scheme);
+  }
+
   if let Some(handler) = ipc_handler {
     webview_builder = webview_builder.with_ipc_handler(create_ipc_handler(
       context,

+ 5 - 0
core/tauri-runtime/src/window.rs

@@ -224,6 +224,9 @@ pub struct PendingWindow<T: UserEvent, R: Runtime<T>> {
 
   pub uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocol>>,
 
+  // Whether custom protocols on windows should use http://<scheme>.localhost/ instead of https://<scheme>.localhost/
+  pub http_scheme: bool,
+
   /// How to handle IPC calls on the webview window.
   pub ipc_handler: Option<WebviewIpcHandler<T, R>>,
 
@@ -281,6 +284,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
         navigation_handler: Default::default(),
         web_resource_request_handler: Default::default(),
         url: "tauri://localhost".to_string(),
+        http_scheme: false,
       })
     }
   }
@@ -312,6 +316,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
         navigation_handler: Default::default(),
         web_resource_request_handler: Default::default(),
         url: "tauri://localhost".to_string(),
+        http_scheme: false,
       })
     }
   }

+ 9 - 1
core/tauri-utils/src/config.rs

@@ -1326,6 +1326,11 @@ pub struct SecurityConfig {
   /// vulnerable to dangerous Tauri command related attacks otherwise.
   #[serde(default, alias = "dangerous-remote-domain-ipc-access")]
   pub dangerous_remote_domain_ipc_access: Vec<RemoteDomainAccessScope>,
+  /// Sets whether the custom protocols should use `http://<scheme>.localhost` instead of the default `https://<scheme>.localhost` on Windows.
+  ///
+  /// **WARNING:** Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints and is therefore less secure but will match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.
+  #[serde(default, alias = "dangerous-use-http-scheme")]
+  pub dangerous_use_http_scheme: bool,
 }
 
 /// Defines an allowlist type.
@@ -3736,6 +3741,7 @@ mod build {
       let dev_csp = opt_lit(self.dev_csp.as_ref());
       let freeze_prototype = self.freeze_prototype;
       let dangerous_disable_asset_csp_modification = &self.dangerous_disable_asset_csp_modification;
+      let dangerous_use_http_scheme = &self.dangerous_use_http_scheme;
       let dangerous_remote_domain_ipc_access =
         vec_lit(&self.dangerous_remote_domain_ipc_access, identity);
 
@@ -3746,7 +3752,8 @@ mod build {
         dev_csp,
         freeze_prototype,
         dangerous_disable_asset_csp_modification,
-        dangerous_remote_domain_ipc_access
+        dangerous_remote_domain_ipc_access,
+        dangerous_use_http_scheme
       );
     }
   }
@@ -4013,6 +4020,7 @@ mod test {
         freeze_prototype: false,
         dangerous_disable_asset_csp_modification: DisabledCspModificationKind::Flag(false),
         dangerous_remote_domain_ipc_access: Vec::new(),
+        dangerous_use_http_scheme: false,
       },
       allowlist: AllowlistConfig::default(),
       system_tray: None,

Plik diff jest za duży
+ 0 - 0
core/tauri/scripts/bundle.global.js


+ 10 - 0
core/tauri/scripts/core.js

@@ -13,6 +13,16 @@
     })
   }
 
+  const osName = __TEMPLATE_os_name__
+  const protocolScheme = __TEMPLATE_protocol_scheme__
+
+  window.__TAURI__.convertFileSrc = function convertFileSrc(filePath, protocol = 'asset') {
+    const path = encodeURIComponent(filePath)
+    return osName === 'windows'
+      ? `${protocolScheme}://${protocol}.localhost/${path}`
+      : `${protocol}://localhost/${path}`
+  }
+
   window.__TAURI__.transformCallback = function transformCallback(
     callback,
     once

+ 6 - 5
core/tauri/src/app.rs

@@ -1573,16 +1573,17 @@ impl<R: Runtime> Builder<R> {
       (self.invoke_responder, self.invoke_initialization_script),
     );
 
+    let http_scheme = manager.config().tauri.security.dangerous_use_http_scheme;
+
     // set up all the windows defined in the config
     for config in manager.config().tauri.windows.clone() {
       let label = config.label.clone();
       let webview_attributes = WebviewAttributes::from(&config);
 
-      self.pending_windows.push(PendingWindow::with_config(
-        config,
-        webview_attributes,
-        label,
-      )?);
+      let mut pending = PendingWindow::with_config(config, webview_attributes, label)?;
+      pending.http_scheme = http_scheme;
+
+      self.pending_windows.push(pending);
     }
 
     #[cfg(any(windows, target_os = "linux"))]

+ 37 - 8
core/tauri/src/manager.rs

@@ -142,7 +142,10 @@ fn set_csp<R: Runtime>(
     let default_src = csp
       .entry("default-src".into())
       .or_insert_with(Default::default);
-    default_src.push(crate::pattern::format_real_schema(schema));
+    default_src.push(crate::pattern::format_real_schema(
+      schema,
+      manager.config().tauri.security.dangerous_use_http_scheme,
+    ));
   }
 
   Csp::DirectiveMap(csp).to_string()
@@ -388,7 +391,14 @@ impl<R: Runtime> WindowManager<R> {
     match self.base_path() {
       AppUrl::Url(WindowUrl::External(url)) => Cow::Borrowed(url),
       #[cfg(windows)]
-      _ => Cow::Owned(Url::parse("https://tauri.localhost").unwrap()),
+      _ => {
+        let scheme = if self.inner.config.tauri.security.dangerous_use_http_scheme {
+          "http"
+        } else {
+          "https"
+        };
+        Cow::Owned(Url::parse(&format!("{scheme}://tauri.localhost")).unwrap())
+      }
       #[cfg(not(windows))]
       _ => Cow::Owned(Url::parse("tauri://localhost").unwrap()),
     }
@@ -429,17 +439,19 @@ impl<R: Runtime> WindowManager<R> {
     }
     .render_default(&Default::default())?;
 
+    let mut webview_attributes = pending.webview_attributes;
+
     let ipc_init = IpcJavascript {
       isolation_origin: &match self.pattern() {
         #[cfg(feature = "isolation")]
-        Pattern::Isolation { schema, .. } => crate::pattern::format_real_schema(schema),
+        Pattern::Isolation { schema, .. } => {
+          crate::pattern::format_real_schema(schema, pending.http_scheme)
+        }
         _ => "".to_string(),
       },
     }
     .render_default(&Default::default())?;
 
-    let mut webview_attributes = pending.webview_attributes;
-
     let mut window_labels = window_labels.to_vec();
     let l = label.to_string();
     if !window_labels.contains(&l) {
@@ -466,7 +478,7 @@ impl<R: Runtime> WindowManager<R> {
     if let Pattern::Isolation { schema, .. } = self.pattern() {
       webview_attributes = webview_attributes.initialization_script(
         &IsolationJavascript {
-          isolation_src: &crate::pattern::format_real_schema(schema),
+          isolation_src: &crate::pattern::format_real_schema(schema, pending.http_scheme),
           style: tauri_utils::pattern::isolation::IFRAME_STYLE,
         }
         .render_default(&Default::default())?
@@ -491,7 +503,8 @@ impl<R: Runtime> WindowManager<R> {
     let window_origin = if window_url.scheme() == "data" {
       "null".into()
     } else if cfg!(windows) && window_url.scheme() != "http" && window_url.scheme() != "https" {
-      format!("https://{}.localhost", window_url.scheme())
+      let scheme = if pending.http_scheme { "http" } else { "https" };
+      format!("{scheme}://{}.localhost", window_url.scheme())
     } else {
       format!(
         "{}://{}{}",
@@ -782,6 +795,13 @@ impl<R: Runtime> WindowManager<R> {
       hotkeys: &'a str,
     }
 
+    #[derive(Template)]
+    #[default_template("../scripts/core.js")]
+    struct CoreJavascript<'a> {
+      os_name: &'a str,
+      protocol_scheme: &'a str,
+    }
+
     let bundle_script = if with_global_tauri {
       include_str!("../scripts/bundle.global.js")
     } else {
@@ -813,7 +833,16 @@ impl<R: Runtime> WindowManager<R> {
           "window['_' + window.__TAURI__.transformCallback(cb) ]".into()
         )
       ),
-      core_script: include_str!("../scripts/core.js"),
+      core_script: &CoreJavascript {
+        os_name: std::env::consts::OS,
+        protocol_scheme: if self.inner.config.tauri.security.dangerous_use_http_scheme {
+          "http"
+        } else {
+          "https"
+        },
+      }
+      .render_default(&Default::default())?
+      .into_string(),
       event_initialization_script: &self.event_initialization_script(),
       plugin_initialization_script,
       freeze_prototype,

+ 3 - 2
core/tauri/src/pattern.rs

@@ -108,9 +108,10 @@ pub(crate) struct PatternJavascript {
 }
 
 #[allow(dead_code)]
-pub(crate) fn format_real_schema(schema: &str) -> String {
+pub(crate) fn format_real_schema(schema: &str, _http: bool) -> String {
   if cfg!(windows) {
-    format!("https://{schema}.{ISOLATION_IFRAME_SRC_DOMAIN}")
+    let http = if _http { "http" } else { "https" };
+    format!("{http}://{schema}.{ISOLATION_IFRAME_SRC_DOMAIN}")
   } else {
     format!("{schema}://{ISOLATION_IFRAME_SRC_DOMAIN}")
   }

+ 6 - 0
core/tauri/src/window.rs

@@ -329,6 +329,12 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
     )?;
     pending.navigation_handler = self.navigation_handler.take();
     pending.web_resource_request_handler = self.web_resource_request_handler.take();
+    pending.http_scheme = self
+      .manager
+      .config()
+      .tauri
+      .security
+      .dangerous_use_http_scheme;
 
     let labels = self.manager.labels().into_iter().collect::<Vec<_>>();
     let pending = self

+ 4 - 4
tooling/api/src/tauri.ts

@@ -17,6 +17,9 @@ declare global {
     ipc: {
       postMessage: (args: string) => void
     }
+    __TAURI__: {
+      convertFileSrc: (src: string, protocol: string) => string
+    }
   }
 }
 
@@ -127,10 +130,7 @@ async function invoke<T>(cmd: string, args: InvokeArgs = {}): Promise<T> {
  * @since 1.0.0
  */
 function convertFileSrc(filePath: string, protocol = 'asset'): string {
-  const path = encodeURIComponent(filePath)
-  return navigator.userAgent.includes('Windows')
-    ? `https://${protocol}.localhost/${path}`
-    : `${protocol}://localhost/${path}`
+  return window.__TAURI__.convertFileSrc(filePath, protocol)
 }
 
 export type { InvokeArgs }

+ 7 - 0
tooling/cli/schema.json

@@ -167,6 +167,7 @@
         "security": {
           "dangerousDisableAssetCspModification": false,
           "dangerousRemoteDomainIpcAccess": [],
+          "dangerousUseHttpScheme": false,
           "freezePrototype": false
         },
         "updater": {
@@ -423,6 +424,7 @@
           "default": {
             "dangerousDisableAssetCspModification": false,
             "dangerousRemoteDomainIpcAccess": [],
+            "dangerousUseHttpScheme": false,
             "freezePrototype": false
           },
           "allOf": [
@@ -2740,6 +2742,11 @@
           "items": {
             "$ref": "#/definitions/RemoteDomainAccessScope"
           }
+        },
+        "dangerousUseHttpScheme": {
+          "description": "Sets whether the custom protocols should use `http://<scheme>.localhost` instead of the default `https://<scheme>.localhost` on Windows.\n\n**WARNING:** Using a `http` scheme will allow mixed content when trying to fetch `http` endpoints and is therefore less secure but will match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.",
+          "default": false,
+          "type": "boolean"
         }
       },
       "additionalProperties": false

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików