Skip to content

Commit

Permalink
feat(core): enhance HTTP scope glob validation, closes #3507 (#3515)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Feb 24, 2022
1 parent 6a6f1e7 commit 944b124
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .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.
8 changes: 7 additions & 1 deletion core/tauri-utils/src/config.rs
Expand Up @@ -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>);
Expand Down
32 changes: 20 additions & 12 deletions core/tauri/src/scope/http.rs
Expand Up @@ -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()))
}
}

Expand Down Expand Up @@ -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()));
}
}
12 changes: 6 additions & 6 deletions core/tauri/tests/restart/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions examples/api/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tooling/cli/schema.json
Expand Up @@ -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",
Expand Down

0 comments on commit 944b124

Please sign in to comment.