소스 검색

refactor(core): allow configuring both local and remote URLs on capability (#8950)

Lucas Fernandes Nogueira 1 년 전
부모
커밋
a76fb118ce

+ 7 - 0
.changes/capability-context-refactor.md

@@ -0,0 +1,7 @@
+---
+"tauri-utils": patch:breaking
+"tauri-cli": patch:breaking
+"@tauri-apps/cli": patch:breaking
+---
+
+Changed the capability format to allow configuring both `remote: { urls: Vec<String> }` and `local: bool (default: true)` instead of choosing one on the `context` field.

+ 26 - 40
core/tauri-config-schema/schema.json

@@ -1085,15 +1085,22 @@
           "default": "",
           "type": "string"
         },
-        "context": {
-          "description": "Execution context of the capability.\n\nAt runtime, Tauri filters the IPC command together with the context to determine whether it is allowed or not and its scope.",
-          "default": "local",
-          "allOf": [
+        "remote": {
+          "description": "Configure remote URLs that can use the capability permissions.",
+          "anyOf": [
             {
-              "$ref": "#/definitions/CapabilityContext"
+              "$ref": "#/definitions/CapabilityRemote"
+            },
+            {
+              "type": "null"
             }
           ]
         },
+        "local": {
+          "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.",
+          "default": true,
+          "type": "boolean"
+        },
         "windows": {
           "description": "List of windows that uses this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.",
           "type": "array",
@@ -1131,42 +1138,21 @@
         }
       }
     },
-    "CapabilityContext": {
-      "description": "Context of the capability.",
-      "oneOf": [
-        {
-          "description": "Capability refers to local URL usage.",
-          "type": "string",
-          "enum": [
-            "local"
-          ]
-        },
-        {
-          "description": "Capability refers to remote usage.",
-          "type": "object",
-          "required": [
-            "remote"
-          ],
-          "properties": {
-            "remote": {
-              "type": "object",
-              "required": [
-                "urls"
-              ],
-              "properties": {
-                "urls": {
-                  "description": "Remote domains this capability refers to. Can use glob patterns.",
-                  "type": "array",
-                  "items": {
-                    "type": "string"
-                  }
-                }
-              }
-            }
-          },
-          "additionalProperties": false
+    "CapabilityRemote": {
+      "description": "Configuration for remote URLs that are associated with the capability.",
+      "type": "object",
+      "required": [
+        "urls"
+      ],
+      "properties": {
+        "urls": {
+          "description": "Remote domains this capability refers to. Can use glob patterns.",
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
         }
-      ]
+      }
     },
     "PermissionEntry": {
       "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.",

+ 24 - 29
core/tauri-utils/src/acl/capability.rs

@@ -56,11 +56,11 @@ pub struct Capability {
   /// Description of the capability.
   #[serde(default)]
   pub description: String,
-  /// Execution context of the capability.
-  ///
-  /// At runtime, Tauri filters the IPC command together with the context to determine whether it is allowed or not and its scope.
-  #[serde(default)]
-  pub context: CapabilityContext,
+  /// Configure remote URLs that can use the capability permissions.
+  pub remote: Option<CapabilityRemote>,
+  /// Whether this capability is enabled for local app URLs or not. Defaults to `true`.
+  #[serde(default = "default_capability_local")]
+  pub local: bool,
   /// List of windows that uses this capability. Can be a glob pattern.
   ///
   /// On multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.
@@ -78,6 +78,10 @@ pub struct Capability {
   pub platforms: Vec<Target>,
 }
 
+fn default_capability_local() -> bool {
+  true
+}
+
 fn default_platforms() -> Vec<Target> {
   vec![
     Target::Linux,
@@ -88,19 +92,13 @@ fn default_platforms() -> Vec<Target> {
   ]
 }
 
-/// Context of the capability.
+/// Configuration for remote URLs that are associated with the capability.
 #[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
 #[serde(rename_all = "camelCase")]
-pub enum CapabilityContext {
-  /// Capability refers to local URL usage.
-  #[default]
-  Local,
-  /// Capability refers to remote usage.
-  Remote {
-    /// Remote domains this capability refers to. Can use glob patterns.
-    urls: Vec<String>,
-  },
+pub struct CapabilityRemote {
+  /// Remote domains this capability refers to. Can use glob patterns.
+  pub urls: Vec<String>,
 }
 
 /// Capability formats accepted in a capability file.
@@ -154,19 +152,14 @@ mod build {
   use super::*;
   use crate::{literal_struct, tokens::*};
 
-  impl ToTokens for CapabilityContext {
+  impl ToTokens for CapabilityRemote {
     fn to_tokens(&self, tokens: &mut TokenStream) {
-      let prefix = quote! { ::tauri::utils::acl::capability::CapabilityContext };
-
-      tokens.append_all(match self {
-        Self::Remote { urls } => {
-          let urls = vec_lit(urls, str_lit);
-          quote! { #prefix::Remote { urls: #urls } }
-        }
-        Self::Local => {
-          quote! { #prefix::Local }
-        }
-      });
+      let urls = vec_lit(&self.urls, str_lit);
+      literal_struct!(
+        tokens,
+        ::tauri::utils::acl::capability::CapabilityRemote,
+        urls
+      );
     }
   }
 
@@ -192,7 +185,8 @@ mod build {
     fn to_tokens(&self, tokens: &mut TokenStream) {
       let identifier = str_lit(&self.identifier);
       let description = str_lit(&self.description);
-      let context = &self.context;
+      let remote = &self.remote;
+      let local = self.local;
       let windows = vec_lit(&self.windows, str_lit);
       let permissions = vec_lit(&self.permissions, identity);
       let platforms = vec_lit(&self.platforms, identity);
@@ -202,7 +196,8 @@ mod build {
         ::tauri::utils::acl::capability::Capability,
         identifier,
         description,
-        context,
+        remote,
+        local,
         windows,
         permissions,
         platforms

+ 11 - 11
core/tauri-utils/src/acl/resolved.rs

@@ -15,7 +15,7 @@ use glob::Pattern;
 use crate::platform::Target;
 
 use super::{
-  capability::{Capability, CapabilityContext, PermissionEntry},
+  capability::{Capability, PermissionEntry},
   plugin::Manifest,
   Commands, Error, ExecutionContext, Permission, PermissionSet, Scopes, Value,
 };
@@ -346,18 +346,18 @@ fn resolve_command(
   scope_id: Option<ScopeKey>,
   #[cfg(debug_assertions)] referenced_by_permission_identifier: String,
 ) {
-  let contexts = match &capability.context {
-    CapabilityContext::Local => {
-      vec![ExecutionContext::Local]
-    }
-    CapabilityContext::Remote { urls } => urls
-      .iter()
-      .map(|url| ExecutionContext::Remote {
+  let mut contexts = Vec::new();
+  if capability.local {
+    contexts.push(ExecutionContext::Local);
+  }
+  if let Some(remote) = &capability.remote {
+    contexts.extend(remote.urls.iter().map(|url| {
+      ExecutionContext::Remote {
         url: Pattern::new(url)
           .unwrap_or_else(|e| panic!("invalid glob pattern for remote URL {url}: {e}")),
-      })
-      .collect(),
-  };
+      }
+    }));
+  }
 
   for context in contexts {
     let resolved = commands

+ 2 - 1
core/tests/acl/fixtures/capabilities/file-explorer-remote/cap.toml

@@ -2,5 +2,6 @@ identifier = "run-app"
 description = "app capability"
 windows = ["main"]
 permissions = ["fs:read", "fs:allow-app"]
-[context.remote]
+local = false
+[remote]
 urls = ["https://tauri.app"]

+ 26 - 40
tooling/cli/schema.json

@@ -1085,15 +1085,22 @@
           "default": "",
           "type": "string"
         },
-        "context": {
-          "description": "Execution context of the capability.\n\nAt runtime, Tauri filters the IPC command together with the context to determine whether it is allowed or not and its scope.",
-          "default": "local",
-          "allOf": [
+        "remote": {
+          "description": "Configure remote URLs that can use the capability permissions.",
+          "anyOf": [
             {
-              "$ref": "#/definitions/CapabilityContext"
+              "$ref": "#/definitions/CapabilityRemote"
+            },
+            {
+              "type": "null"
             }
           ]
         },
+        "local": {
+          "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.",
+          "default": true,
+          "type": "boolean"
+        },
         "windows": {
           "description": "List of windows that uses this capability. Can be a glob pattern.\n\nOn multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.",
           "type": "array",
@@ -1131,42 +1138,21 @@
         }
       }
     },
-    "CapabilityContext": {
-      "description": "Context of the capability.",
-      "oneOf": [
-        {
-          "description": "Capability refers to local URL usage.",
-          "type": "string",
-          "enum": [
-            "local"
-          ]
-        },
-        {
-          "description": "Capability refers to remote usage.",
-          "type": "object",
-          "required": [
-            "remote"
-          ],
-          "properties": {
-            "remote": {
-              "type": "object",
-              "required": [
-                "urls"
-              ],
-              "properties": {
-                "urls": {
-                  "description": "Remote domains this capability refers to. Can use glob patterns.",
-                  "type": "array",
-                  "items": {
-                    "type": "string"
-                  }
-                }
-              }
-            }
-          },
-          "additionalProperties": false
+    "CapabilityRemote": {
+      "description": "Configuration for remote URLs that are associated with the capability.",
+      "type": "object",
+      "required": [
+        "urls"
+      ],
+      "properties": {
+        "urls": {
+          "description": "Remote domains this capability refers to. Can use glob patterns.",
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
         }
-      ]
+      }
     },
     "PermissionEntry": {
       "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.",

+ 3 - 2
tooling/cli/src/migrate/config.rs

@@ -7,7 +7,7 @@ use crate::Result;
 use serde_json::{Map, Value};
 use tauri_utils::{
   acl::{
-    capability::{Capability, CapabilityContext, PermissionEntry},
+    capability::{Capability, PermissionEntry},
     Scopes, Value as AclValue,
   },
   platform::Target,
@@ -59,7 +59,8 @@ pub fn migrate(tauri_dir: &Path) -> Result<()> {
       serde_json::to_string_pretty(&Capability {
         identifier: "migrated".to_string(),
         description: "permissions that were migrated from v1".into(),
-        context: CapabilityContext::Local,
+        local: true,
+        remote: None,
         windows: vec!["main".into()],
         webviews: vec![],
         permissions,