Jelajahi Sumber

feat(core): enhance HTTP scope glob validation, closes #3507 (#3515)

Lucas Fernandes Nogueira 3 tahun lalu
induk
melakukan
944b124ce0

+ 5 - 0
.changes/http-scope-host-pattern.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch
+---
+
+The HTTP scope now matches the entire URL using a glob pattern instead of only its path.

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

@@ -1091,7 +1091,13 @@ impl Allowlist for DialogAllowlistConfig {
 
 /// HTTP API scope definition.
 /// It is a list of URLs that can be accessed by the webview when using the HTTP APIs.
-/// The URL path is matched against the request URL using a glob pattern.
+/// The scoped URL is matched against the request URL using a glob pattern.
+///
+/// # Examples
+///
+/// - "https://*": allows all HTTPS urls
+/// - "https://*.github.com/tauri-apps/tauri": allows any subdomain of "github.com" with the "tauri-apps/api" path
+/// - "https://myapi.service.com/users/*": allows access to any URLs that begins with "https://myapi.service.com/users/"
 #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
 #[cfg_attr(feature = "schema", derive(JsonSchema))]
 pub struct HttpAllowlistScope(pub Vec<Url>);

+ 20 - 12
core/tauri/src/scope/http.rs

@@ -2,33 +2,36 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
+use glob::Pattern;
 use tauri_utils::config::HttpAllowlistScope;
-use url::Url;
 
 /// Scope for filesystem access.
 #[derive(Debug, Clone)]
 pub struct Scope {
-  allowed_urls: Vec<Url>,
+  allowed_urls: Vec<Pattern>,
 }
 
 impl Scope {
   /// Creates a new scope from the allowlist's `http` scope configuration.
   pub fn for_http_api(scope: &HttpAllowlistScope) -> Self {
     Self {
-      allowed_urls: scope.0.clone(),
+      allowed_urls: scope
+        .0
+        .iter()
+        .map(|url| {
+          glob::Pattern::new(url.as_str())
+            .unwrap_or_else(|_| panic!("scoped URL is not a valid glob pattern: `{}`", url))
+        })
+        .collect(),
     }
   }
 
   /// Determines if the given URL is allowed on this scope.
-  pub fn is_allowed(&self, url: &Url) -> bool {
-    self.allowed_urls.iter().any(|allowed| {
-      let origin_matches = allowed.scheme() == url.scheme()
-        && allowed.host() == url.host()
-        && allowed.port() == url.port();
-      let allowed_path_pattern = glob::Pattern::new(allowed.path())
-        .unwrap_or_else(|_| panic!("invalid glob pattern on URL `{}` path", allowed));
-      origin_matches && allowed_path_pattern.matches(url.path())
-    })
+  pub fn is_allowed(&self, url: &url::Url) -> bool {
+    self
+      .allowed_urls
+      .iter()
+      .any(|allowed| allowed.matches(url.as_str()))
   }
 }
 
@@ -73,5 +76,10 @@ mod tests {
     assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap()));
 
     assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap()));
+
+    let scope = super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://*".parse().unwrap()]));
+
+    assert!(scope.is_allowed(&"http://something.else".parse().unwrap()));
+    assert!(!scope.is_allowed(&"https://something.else".parse().unwrap()));
   }
 }

+ 6 - 6
core/tauri/tests/restart/Cargo.lock

@@ -2540,7 +2540,7 @@ dependencies = [
 
 [[package]]
 name = "tauri"
-version = "1.0.0-rc.2"
+version = "1.0.0-rc.3"
 dependencies = [
  "anyhow",
  "bincode",
@@ -2581,7 +2581,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-codegen"
-version = "1.0.0-rc.1"
+version = "1.0.0-rc.2"
 dependencies = [
  "base64",
  "blake3",
@@ -2599,7 +2599,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-macros"
-version = "1.0.0-rc.1"
+version = "1.0.0-rc.2"
 dependencies = [
  "heck 0.4.0",
  "proc-macro2",
@@ -2611,7 +2611,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-runtime"
-version = "0.3.1"
+version = "0.3.2"
 dependencies = [
  "gtk",
  "http",
@@ -2628,7 +2628,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-runtime-wry"
-version = "0.3.1"
+version = "0.3.2"
 dependencies = [
  "gtk",
  "ico",
@@ -2644,7 +2644,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-utils"
-version = "1.0.0-rc.1"
+version = "1.0.0-rc.2"
 dependencies = [
  "ctor",
  "heck 0.4.0",

+ 7 - 7
examples/api/src-tauri/Cargo.lock

@@ -3311,7 +3311,7 @@ dependencies = [
 
 [[package]]
 name = "tauri"
-version = "1.0.0-rc.2"
+version = "1.0.0-rc.3"
 dependencies = [
  "anyhow",
  "attohttpc",
@@ -3363,7 +3363,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-build"
-version = "1.0.0-rc.2"
+version = "1.0.0-rc.3"
 dependencies = [
  "anyhow",
  "cargo_toml",
@@ -3375,7 +3375,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-codegen"
-version = "1.0.0-rc.1"
+version = "1.0.0-rc.2"
 dependencies = [
  "base64",
  "blake3",
@@ -3394,7 +3394,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-macros"
-version = "1.0.0-rc.1"
+version = "1.0.0-rc.2"
 dependencies = [
  "heck 0.4.0",
  "proc-macro2",
@@ -3406,7 +3406,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-runtime"
-version = "0.3.1"
+version = "0.3.2"
 dependencies = [
  "gtk",
  "http",
@@ -3423,7 +3423,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-runtime-wry"
-version = "0.3.1"
+version = "0.3.2"
 dependencies = [
  "gtk",
  "ico",
@@ -3439,7 +3439,7 @@ dependencies = [
 
 [[package]]
 name = "tauri-utils"
-version = "1.0.0-rc.1"
+version = "1.0.0-rc.2"
 dependencies = [
  "aes-gcm",
  "ctor",

+ 1 - 1
tooling/cli/schema.json

@@ -1041,7 +1041,7 @@
       "additionalProperties": false
     },
     "HttpAllowlistScope": {
-      "description": "HTTP API scope definition. It is a list of URLs that can be accessed by the webview when using the HTTP APIs. The URL path is matched against the request URL using a glob pattern.",
+      "description": "HTTP API scope definition. It is a list of URLs that can be accessed by the webview when using the HTTP APIs. The scoped URL is matched against the request URL using a glob pattern.\n\n# Examples\n\n- \"https://*\": allows all HTTPS urls - \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path - \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"",
       "type": "array",
       "items": {
         "type": "string",