소스 검색

feat(core): configure HTTP scope using glob patterns

Lucas Nogueira 3 년 전
부모
커밋
b82e2b5cf7
3개의 변경된 파일54개의 추가작업 그리고 3개의 파일을 삭제
  1. 1 0
      core/tauri-utils/src/config.rs
  2. 49 2
      core/tauri/src/scope/http.rs
  3. 4 1
      examples/api/src-tauri/tauri.conf.json

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

@@ -1058,6 +1058,7 @@ 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.
 #[derive(Debug, Default, PartialEq, Clone, Deserialize, Serialize)]
 #[cfg_attr(feature = "schema", derive(JsonSchema))]
 pub struct HttpAllowlistScope(pub Vec<Url>);

+ 49 - 2
core/tauri/src/scope/http.rs

@@ -22,9 +22,56 @@ impl Scope {
   /// Determines if the given URL is allowed on this scope.
   pub fn is_allowed(&self, url: &Url) -> bool {
     self.allowed_urls.iter().any(|allowed| {
-      allowed.scheme() == url.scheme()
+      let origin_matches = allowed.scheme() == url.scheme()
         && allowed.host() == url.host()
-        && allowed.port() == url.port()
+        && 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())
     })
   }
 }
+
+#[cfg(test)]
+mod tests {
+  use tauri_utils::config::HttpAllowlistScope;
+
+  #[test]
+  fn is_allowed() {
+    // plain URL
+    let scope = super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080"
+      .parse()
+      .unwrap()]));
+    assert!(scope.is_allowed(&"http://localhost:8080".parse().unwrap()));
+    assert!(scope.is_allowed(&"http://localhost:8080/".parse().unwrap()));
+
+    assert!(!scope.is_allowed(&"http://localhost:8080/file".parse().unwrap()));
+    assert!(!scope.is_allowed(&"http://localhost:8080/path/to/asset.png".parse().unwrap()));
+    assert!(!scope.is_allowed(&"https://localhost:8080".parse().unwrap()));
+    assert!(!scope.is_allowed(&"http://localhost:8081".parse().unwrap()));
+    assert!(!scope.is_allowed(&"http://local:8080".parse().unwrap()));
+
+    // URL with fixed path
+    let scope =
+      super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080/file.png"
+        .parse()
+        .unwrap()]));
+
+    assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
+
+    assert!(!scope.is_allowed(&"http://localhost:8080".parse().unwrap()));
+    assert!(!scope.is_allowed(&"http://localhost:8080/file".parse().unwrap()));
+    assert!(!scope.is_allowed(&"http://localhost:8080/file.png/other.jpg".parse().unwrap()));
+
+    // URL with glob pattern
+    let scope =
+      super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080/*.png"
+        .parse()
+        .unwrap()]));
+
+    assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
+    assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap()));
+
+    assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap()));
+  }
+}

+ 4 - 1
examples/api/src-tauri/tauri.conf.json

@@ -80,6 +80,7 @@
       "shell": {
         "scope": [
           {
+            "name": "test",
             "cmd": "__test",
             "args": [
               "-d --date <DATE> ^\\d{4}-\\d{2}-\\d{2}$",
@@ -90,9 +91,11 @@
             ]
           },
           {
+            "name": "sh",
             "cmd": "sh"
           },
           {
+            "name": "cmd",
             "cmd": "cmd"
           }
         ]
@@ -102,7 +105,7 @@
         "assetScope": ["$RESOURCE/**"]
       },
       "http": {
-        "scope": ["https://jsonplaceholder.typicode.com"]
+        "scope": ["https://jsonplaceholder.typicode.com/todos/*"]
       }
     },
     "windows": [