diff --git a/.changes/http-scope-host-pattern.md b/.changes/http-scope-host-pattern.md new file mode 100644 index 000000000..af937f42c --- /dev/null +++ b/.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. diff --git a/core/tauri-utils/src/config.rs b/core/tauri-utils/src/config.rs index 070256c03..95092ce66 100644 --- a/core/tauri-utils/src/config.rs +++ b/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); diff --git a/core/tauri/src/scope/http.rs b/core/tauri/src/scope/http.rs index a17849e4e..5ea142da1 100644 --- a/core/tauri/src/scope/http.rs +++ b/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, + allowed_urls: Vec, } 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())); } } diff --git a/core/tauri/tests/restart/Cargo.lock b/core/tauri/tests/restart/Cargo.lock index 891951deb..bffb2634e 100644 --- a/core/tauri/tests/restart/Cargo.lock +++ b/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", diff --git a/examples/api/src-tauri/Cargo.lock b/examples/api/src-tauri/Cargo.lock index 58ce3171f..1337bc059 100644 --- a/examples/api/src-tauri/Cargo.lock +++ b/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", diff --git a/tooling/cli/schema.json b/tooling/cli/schema.json index 3c01e8de5..73cd6f9c7 100644 --- a/tooling/cli/schema.json +++ b/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",