Эх сурвалжийг харах

fix(acl): inconsistencies on urlpattern usage for remote domain URL (#9133)

* fix(acl): inconsistencies on urlpattern usage for remote domain URL

* remove println!

* typo

* fix tests
Lucas Fernandes Nogueira 1 жил өмнө
parent
commit
e673854c83

+ 5 - 0
.changes/fix-remote-domain-url.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch:bug
+---
+
+Fixes capability remote domain not allowing subpaths, query parameters and hash when those values are empty.

+ 1 - 1
core/tauri-config-schema/schema.json

@@ -1141,7 +1141,7 @@
       ],
       "properties": {
         "urls": {
-          "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).",
+          "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n# Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api",
           "type": "array",
           "items": {
             "type": "string"

+ 5 - 0
core/tauri-utils/src/acl/capability.rs

@@ -90,6 +90,11 @@ fn default_capability_local() -> bool {
 #[serde(rename_all = "camelCase")]
 pub struct CapabilityRemote {
   /// Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).
+  ///
+  /// # Examples
+  ///
+  /// - "https://*.mydomain.dev": allows subdomains of mydomain.dev
+  /// - "https://mydomain.dev/api/*": allows any subpath of mydomain.dev/api
   pub urls: Vec<String>,
 }
 

+ 55 - 1
core/tauri-utils/src/acl/mod.rs

@@ -202,7 +202,21 @@ impl FromStr for RemoteUrlPattern {
   type Err = urlpattern::quirks::Error;
 
   fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
-    let init = urlpattern::UrlPatternInit::parse_constructor_string::<regex::Regex>(s, None)?;
+    let mut init = urlpattern::UrlPatternInit::parse_constructor_string::<regex::Regex>(s, None)?;
+    if init.search.as_ref().map(|p| p.is_empty()).unwrap_or(true) {
+      init.search.replace("*".to_string());
+    }
+    if init.hash.as_ref().map(|p| p.is_empty()).unwrap_or(true) {
+      init.hash.replace("*".to_string());
+    }
+    if init
+      .pathname
+      .as_ref()
+      .map(|p| p.is_empty() || p == "/")
+      .unwrap_or(true)
+    {
+      init.pathname.replace("*".to_string());
+    }
     let pattern = urlpattern::UrlPattern::parse(init)?;
     Ok(Self(Arc::new(pattern), s.to_string()))
   }
@@ -251,6 +265,46 @@ pub enum ExecutionContext {
   },
 }
 
+#[cfg(test)]
+mod tests {
+  use crate::acl::RemoteUrlPattern;
+
+  #[test]
+  fn url_pattern_domain_wildcard() {
+    let pattern: RemoteUrlPattern = "http://*".parse().unwrap();
+
+    assert!(pattern.test(&"http://tauri.app/path".parse().unwrap()));
+    assert!(pattern.test(&"http://tauri.app/path?q=1".parse().unwrap()));
+
+    assert!(pattern.test(&"http://localhost/path".parse().unwrap()));
+    assert!(pattern.test(&"http://localhost/path?q=1".parse().unwrap()));
+
+    let pattern: RemoteUrlPattern = "http://*.tauri.app".parse().unwrap();
+
+    assert!(!pattern.test(&"http://tauri.app/path".parse().unwrap()));
+    assert!(!pattern.test(&"http://tauri.app/path?q=1".parse().unwrap()));
+    assert!(pattern.test(&"http://api.tauri.app/path".parse().unwrap()));
+    assert!(pattern.test(&"http://api.tauri.app/path?q=1".parse().unwrap()));
+    assert!(!pattern.test(&"http://localhost/path".parse().unwrap()));
+    assert!(!pattern.test(&"http://localhost/path?q=1".parse().unwrap()));
+  }
+
+  #[test]
+  fn url_pattern_path_wildcard() {
+    let pattern: RemoteUrlPattern = "http://localhost/*".parse().unwrap();
+    assert!(pattern.test(&"http://localhost/path".parse().unwrap()));
+    assert!(pattern.test(&"http://localhost/path?q=1".parse().unwrap()));
+  }
+
+  #[test]
+  fn url_pattern_scheme_wildcard() {
+    let pattern: RemoteUrlPattern = "*://localhost".parse().unwrap();
+    assert!(pattern.test(&"http://localhost/path".parse().unwrap()));
+    assert!(pattern.test(&"https://localhost/path?q=1".parse().unwrap()));
+    assert!(pattern.test(&"custom://localhost/path".parse().unwrap()));
+  }
+}
+
 #[cfg(feature = "build")]
 mod build_ {
   use std::convert::identity;

+ 48 - 30
core/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap

@@ -90,50 +90,59 @@ Resolved {
                                 },
                             },
                             pathname: Component {
-                                pattern_string: "/",
+                                pattern_string: "*",
                                 regexp: Ok(
                                     Regex(
-                                        "^/$",
+                                        "^(.*)$",
                                     ),
                                 ),
-                                group_name_list: [],
+                                group_name_list: [
+                                    "0",
+                                ],
                                 matcher: Matcher {
                                     prefix: "",
                                     suffix: "",
-                                    inner: Literal {
-                                        literal: "/",
+                                    inner: SingleCapture {
+                                        filter: None,
+                                        allow_empty: true,
                                     },
                                 },
                             },
                             search: Component {
-                                pattern_string: "",
+                                pattern_string: "*",
                                 regexp: Ok(
                                     Regex(
-                                        "^$",
+                                        "^(.*)$",
                                     ),
                                 ),
-                                group_name_list: [],
+                                group_name_list: [
+                                    "0",
+                                ],
                                 matcher: Matcher {
                                     prefix: "",
                                     suffix: "",
-                                    inner: Literal {
-                                        literal: "",
+                                    inner: SingleCapture {
+                                        filter: None,
+                                        allow_empty: true,
                                     },
                                 },
                             },
                             hash: Component {
-                                pattern_string: "",
+                                pattern_string: "*",
                                 regexp: Ok(
                                     Regex(
-                                        "^$",
+                                        "^(.*)$",
                                     ),
                                 ),
-                                group_name_list: [],
+                                group_name_list: [
+                                    "0",
+                                ],
                                 matcher: Matcher {
                                     prefix: "",
                                     suffix: "",
-                                    inner: Literal {
-                                        literal: "",
+                                    inner: SingleCapture {
+                                        filter: None,
+                                        allow_empty: true,
                                     },
                                 },
                             },
@@ -251,50 +260,59 @@ Resolved {
                                 },
                             },
                             pathname: Component {
-                                pattern_string: "/",
+                                pattern_string: "*",
                                 regexp: Ok(
                                     Regex(
-                                        "^/$",
+                                        "^(.*)$",
                                     ),
                                 ),
-                                group_name_list: [],
+                                group_name_list: [
+                                    "0",
+                                ],
                                 matcher: Matcher {
                                     prefix: "",
                                     suffix: "",
-                                    inner: Literal {
-                                        literal: "/",
+                                    inner: SingleCapture {
+                                        filter: None,
+                                        allow_empty: true,
                                     },
                                 },
                             },
                             search: Component {
-                                pattern_string: "",
+                                pattern_string: "*",
                                 regexp: Ok(
                                     Regex(
-                                        "^$",
+                                        "^(.*)$",
                                     ),
                                 ),
-                                group_name_list: [],
+                                group_name_list: [
+                                    "0",
+                                ],
                                 matcher: Matcher {
                                     prefix: "",
                                     suffix: "",
-                                    inner: Literal {
-                                        literal: "",
+                                    inner: SingleCapture {
+                                        filter: None,
+                                        allow_empty: true,
                                     },
                                 },
                             },
                             hash: Component {
-                                pattern_string: "",
+                                pattern_string: "*",
                                 regexp: Ok(
                                     Regex(
-                                        "^$",
+                                        "^(.*)$",
                                     ),
                                 ),
-                                group_name_list: [],
+                                group_name_list: [
+                                    "0",
+                                ],
                                 matcher: Matcher {
                                     prefix: "",
                                     suffix: "",
-                                    inner: Literal {
-                                        literal: "",
+                                    inner: SingleCapture {
+                                        filter: None,
+                                        allow_empty: true,
                                     },
                                 },
                             },

+ 5 - 2
examples/api/src-tauri/capabilities/run-app.json

@@ -2,7 +2,10 @@
   "$schema": "../gen/schemas/desktop-schema.json",
   "identifier": "run-app",
   "description": "permissions to run the app",
-  "windows": ["main", "main-*"],
+  "windows": [
+    "main",
+    "main-*"
+  ],
   "permissions": [
     {
       "identifier": "allow-log-operation",
@@ -96,4 +99,4 @@
     "tray:allow-set-icon-as-template",
     "tray:allow-set-show-menu-on-left-click"
   ]
-}
+}

+ 1 - 1
tooling/cli/schema.json

@@ -1141,7 +1141,7 @@
       ],
       "properties": {
         "urls": {
-          "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).",
+          "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n# Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api",
           "type": "array",
           "items": {
             "type": "string"