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

This commit is contained in:
Lucas Fernandes Nogueira
2022-02-24 10:06:19 -03:00
committed by GitHub
parent 6a6f1e7bf9
commit 944b124ce0
6 changed files with 46 additions and 27 deletions

View File

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

View File

@@ -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>);

View File

@@ -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()));
}
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",