http.rs 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2019-2022 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. use glob::Pattern;
  5. use tauri_utils::config::HttpAllowlistScope;
  6. /// Scope for filesystem access.
  7. #[derive(Debug, Clone)]
  8. pub struct Scope {
  9. allowed_urls: Vec<Pattern>,
  10. }
  11. impl Scope {
  12. /// Creates a new scope from the allowlist's `http` scope configuration.
  13. #[allow(dead_code)]
  14. pub(crate) fn for_http_api(scope: &HttpAllowlistScope) -> Self {
  15. Self {
  16. allowed_urls: scope
  17. .0
  18. .iter()
  19. .map(|url| {
  20. glob::Pattern::new(url.as_str())
  21. .unwrap_or_else(|_| panic!("scoped URL is not a valid glob pattern: `{url}`"))
  22. })
  23. .collect(),
  24. }
  25. }
  26. /// Determines if the given URL is allowed on this scope.
  27. pub fn is_allowed(&self, url: &url::Url) -> bool {
  28. self
  29. .allowed_urls
  30. .iter()
  31. .any(|allowed| allowed.matches(url.as_str()))
  32. }
  33. }
  34. #[cfg(test)]
  35. mod tests {
  36. use tauri_utils::config::HttpAllowlistScope;
  37. #[test]
  38. fn is_allowed() {
  39. // plain URL
  40. let scope = super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080"
  41. .parse()
  42. .unwrap()]));
  43. assert!(scope.is_allowed(&"http://localhost:8080".parse().unwrap()));
  44. assert!(scope.is_allowed(&"http://localhost:8080/".parse().unwrap()));
  45. assert!(!scope.is_allowed(&"http://localhost:8080/file".parse().unwrap()));
  46. assert!(!scope.is_allowed(&"http://localhost:8080/path/to/asset.png".parse().unwrap()));
  47. assert!(!scope.is_allowed(&"https://localhost:8080".parse().unwrap()));
  48. assert!(!scope.is_allowed(&"http://localhost:8081".parse().unwrap()));
  49. assert!(!scope.is_allowed(&"http://local:8080".parse().unwrap()));
  50. // URL with fixed path
  51. let scope =
  52. super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080/file.png"
  53. .parse()
  54. .unwrap()]));
  55. assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
  56. assert!(!scope.is_allowed(&"http://localhost:8080".parse().unwrap()));
  57. assert!(!scope.is_allowed(&"http://localhost:8080/file".parse().unwrap()));
  58. assert!(!scope.is_allowed(&"http://localhost:8080/file.png/other.jpg".parse().unwrap()));
  59. // URL with glob pattern
  60. let scope =
  61. super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://localhost:8080/*.png"
  62. .parse()
  63. .unwrap()]));
  64. assert!(scope.is_allowed(&"http://localhost:8080/file.png".parse().unwrap()));
  65. assert!(scope.is_allowed(&"http://localhost:8080/assets/file.png".parse().unwrap()));
  66. assert!(!scope.is_allowed(&"http://localhost:8080/file.jpeg".parse().unwrap()));
  67. let scope = super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://*".parse().unwrap()]));
  68. assert!(scope.is_allowed(&"http://something.else".parse().unwrap()));
  69. assert!(!scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap()));
  70. assert!(!scope.is_allowed(&"https://something.else".parse().unwrap()));
  71. let scope = super::Scope::for_http_api(&HttpAllowlistScope(vec!["http://**".parse().unwrap()]));
  72. assert!(scope.is_allowed(&"http://something.else".parse().unwrap()));
  73. assert!(scope.is_allowed(&"http://something.else/path/to/file".parse().unwrap()));
  74. }
  75. }