From a35b416e38353fc8a65f79ca44c0fa695191a102 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Fri, 2 Feb 2024 09:18:59 -0300 Subject: [PATCH] refactor(core): merge scope and commands resolving permission sets (#8731) --- core/tauri-utils/src/acl/resolved.rs | 141 ++++++++------- .../capabilities/scope-extended/cap.json | 3 +- .../acl/fixtures/capabilities/scope/cap.toml | 1 + .../plugins/fs/read-download-dir.toml | 4 + core/tests/acl/fixtures/plugins/fs/scope.toml | 10 +- .../acl_tests__tests__scope-extended.snap | 163 ++++++++++-------- .../snapshots/acl_tests__tests__scope.snap | 36 +++- 7 files changed, 216 insertions(+), 142 deletions(-) create mode 100644 core/tests/acl/fixtures/plugins/fs/read-download-dir.toml diff --git a/core/tauri-utils/src/acl/resolved.rs b/core/tauri-utils/src/acl/resolved.rs index 85667df7c..9a138fce8 100644 --- a/core/tauri-utils/src/acl/resolved.rs +++ b/core/tauri-utils/src/acl/resolved.rs @@ -17,7 +17,7 @@ use crate::platform::Target; use super::{ capability::{Capability, CapabilityContext, PermissionEntry}, plugin::Manifest, - Error, ExecutionContext, Permission, PermissionSet, Scopes, Value, + Commands, Error, ExecutionContext, Permission, PermissionSet, Scopes, Value, }; /// A key for a scope, used to link a [`ResolvedCommand#structfield.scope`] to the store [`Resolved#structfield.scopes`]. @@ -127,70 +127,85 @@ impl Resolved { if let Some(plugin_name) = permission_id.get_prefix() { let permissions = get_permissions(plugin_name, permission_name, &acl)?; + let mut resolved_scope = Scopes::default(); + let mut commands = Commands::default(); + + if let PermissionEntry::ExtendedPermission { + identifier: _, + scope, + } = permission_entry + { + if let Some(allow) = scope.allow.clone() { + resolved_scope + .allow + .get_or_insert_with(Default::default) + .extend(allow); + } + if let Some(deny) = scope.deny.clone() { + resolved_scope + .deny + .get_or_insert_with(Default::default) + .extend(deny); + } + } + for permission in permissions { - let scope = match permission_entry { - PermissionEntry::PermissionRef(_) => permission.scope.clone(), - PermissionEntry::ExtendedPermission { - identifier: _, - scope, - } => { - let mut merged = permission.scope.clone(); - if let Some(allow) = scope.allow.clone() { - merged - .allow - .get_or_insert_with(Default::default) - .extend(allow); - } - if let Some(deny) = scope.deny.clone() { - merged - .deny - .get_or_insert_with(Default::default) - .extend(deny); - } - merged - } + if let Some(allow) = permission.scope.allow.clone() { + resolved_scope + .allow + .get_or_insert_with(Default::default) + .extend(allow); + } + if let Some(deny) = permission.scope.deny.clone() { + resolved_scope + .deny + .get_or_insert_with(Default::default) + .extend(deny); + } + + commands.allow.extend(permission.commands.allow.clone()); + commands.deny.extend(permission.commands.deny.clone()); + } + + if commands.allow.is_empty() && commands.deny.is_empty() { + // global scope + global_scope + .entry(plugin_name.to_string()) + .or_default() + .push(resolved_scope); + } else { + let has_scope = resolved_scope.allow.is_some() || resolved_scope.deny.is_some(); + if has_scope { + current_scope_id += 1; + command_scopes.insert(current_scope_id, resolved_scope); + } + + let scope_id = if has_scope { + Some(current_scope_id) + } else { + None }; - if permission.commands.allow.is_empty() && permission.commands.deny.is_empty() { - // global scope - global_scope - .entry(plugin_name.to_string()) - .or_default() - .push(scope.clone()); - } else { - let has_scope = scope.allow.is_some() || scope.deny.is_some(); - if has_scope { - current_scope_id += 1; - command_scopes.insert(current_scope_id, scope.clone()); - } + for allowed_command in &commands.allow { + resolve_command( + &mut allowed_commands, + format!("plugin:{plugin_name}|{allowed_command}"), + capability, + scope_id, + #[cfg(debug_assertions)] + permission_name.to_string(), + ); + } - let scope_id = if has_scope { - Some(current_scope_id) - } else { - None - }; - - for allowed_command in &permission.commands.allow { - resolve_command( - &mut allowed_commands, - format!("plugin:{plugin_name}|{allowed_command}"), - capability, - scope_id, - #[cfg(debug_assertions)] - permission, - ); - } - - for denied_command in &permission.commands.deny { - resolve_command( - &mut denied_commands, - format!("plugin:{plugin_name}|{denied_command}"), - capability, - scope_id, - #[cfg(debug_assertions)] - permission, - ); - } + for denied_command in &commands.deny { + resolve_command( + &mut denied_commands, + format!("plugin:{plugin_name}|{denied_command}"), + capability, + scope_id, + #[cfg(debug_assertions)] + permission_name.to_string(), + ); } } } @@ -306,7 +321,7 @@ fn resolve_command( command: String, capability: &Capability, scope_id: Option, - #[cfg(debug_assertions)] permission: &Permission, + #[cfg(debug_assertions)] referenced_by_permission_identifier: String, ) { let contexts = match &capability.context { CapabilityContext::Local => { @@ -332,7 +347,7 @@ fn resolve_command( #[cfg(debug_assertions)] resolved.referenced_by.push(ResolvedCommandReference { capability: capability.identifier.clone(), - permission: permission.identifier.clone(), + permission: referenced_by_permission_identifier.clone(), }); resolved.windows.extend(capability.windows.clone()); diff --git a/core/tests/acl/fixtures/capabilities/scope-extended/cap.json b/core/tests/acl/fixtures/capabilities/scope-extended/cap.json index e0eebc73a..e665dcd55 100644 --- a/core/tests/acl/fixtures/capabilities/scope-extended/cap.json +++ b/core/tests/acl/fixtures/capabilities/scope-extended/cap.json @@ -35,6 +35,7 @@ "path": "$APP/*.db" } ] - } + }, + "fs:read-download-dir" ] } \ No newline at end of file diff --git a/core/tests/acl/fixtures/capabilities/scope/cap.toml b/core/tests/acl/fixtures/capabilities/scope/cap.toml index 934483076..70ad71cc5 100644 --- a/core/tests/acl/fixtures/capabilities/scope/cap.toml +++ b/core/tests/acl/fixtures/capabilities/scope/cap.toml @@ -7,4 +7,5 @@ permissions = [ "fs:deny-home", "fs:allow-read-resources", "fs:allow-move-temp", + "fs:read-download-dir" ] diff --git a/core/tests/acl/fixtures/plugins/fs/read-download-dir.toml b/core/tests/acl/fixtures/plugins/fs/read-download-dir.toml new file mode 100644 index 000000000..b5a5b7f6c --- /dev/null +++ b/core/tests/acl/fixtures/plugins/fs/read-download-dir.toml @@ -0,0 +1,4 @@ +[[set]] +identifier = "read-download-dir" +description = "allows all read the $DOWNLOAD dir" +permissions = ["allow-read-dir", "allow-download-dir"] diff --git a/core/tests/acl/fixtures/plugins/fs/scope.toml b/core/tests/acl/fixtures/plugins/fs/scope.toml index 9c00d0e6c..47e45f113 100644 --- a/core/tests/acl/fixtures/plugins/fs/scope.toml +++ b/core/tests/acl/fixtures/plugins/fs/scope.toml @@ -1,6 +1,14 @@ - [[permission]] identifier = "allow-app" description = "Allows accessing the $APP path." [[permission.scope.allow]] path = "$APP" + + +[[permission]] +identifier = "allow-download-dir" +description = "Allows accessing the $DOWNLOAD directory." +[[permission.scope.allow]] +path = "$DOWNLOAD" +[[permission.scope.allow]] +path = "$DOWNLOAD/**" diff --git a/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap b/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap index 1e04fac83..fee8df2a6 100644 --- a/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap +++ b/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap @@ -1,6 +1,5 @@ --- source: core/tests/acl/src/lib.rs -assertion_line: 59 expression: resolved --- Resolved { @@ -30,7 +29,7 @@ Resolved { }, ], scope: Some( - 792017965103506125, + 9188997750422900590, ), }, CommandKey { @@ -58,7 +57,7 @@ Resolved { }, ], scope: Some( - 5856262838373339618, + 1349364295896631601, ), }, CommandKey { @@ -86,13 +85,95 @@ Resolved { }, ], scope: Some( - 10252531491715478446, + 8031926490300119127, ), }, }, denied_commands: {}, command_scope: { - 792017965103506125: ResolvedScope { + 1349364295896631601: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$HOME/.config/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE", + ), + }, + ), + Map( + { + "path": String( + "$DOWNLOAD", + ), + }, + ), + Map( + { + "path": String( + "$DOWNLOAD/**", + ), + }, + ), + ], + deny: [ + Map( + { + "path": String( + "$RESOURCE/**/*.key", + ), + }, + ), + ], + }, + 8031926490300119127: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$HOME/.config/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE", + ), + }, + ), + ], + deny: [ + Map( + { + "path": String( + "$RESOURCE/**/*.key", + ), + }, + ), + ], + }, + 9188997750422900590: ResolvedScope { allow: [ Map( { @@ -104,74 +185,6 @@ Resolved { ], deny: [], }, - 5856262838373339618: ResolvedScope { - allow: [ - Map( - { - "path": String( - "$HOME/.config/**", - ), - }, - ), - Map( - { - "path": String( - "$RESOURCE/**", - ), - }, - ), - Map( - { - "path": String( - "$RESOURCE", - ), - }, - ), - ], - deny: [ - Map( - { - "path": String( - "$RESOURCE/**/*.key", - ), - }, - ), - ], - }, - 10252531491715478446: ResolvedScope { - allow: [ - Map( - { - "path": String( - "$HOME/.config/**", - ), - }, - ), - Map( - { - "path": String( - "$RESOURCE/**", - ), - }, - ), - Map( - { - "path": String( - "$RESOURCE", - ), - }, - ), - ], - deny: [ - Map( - { - "path": String( - "$RESOURCE/**/*.key", - ), - }, - ), - ], - }, }, global_scope: { "fs": ResolvedScope { @@ -179,14 +192,14 @@ Resolved { Map( { "path": String( - "$APP", + "$APP/**", ), }, ), Map( { "path": String( - "$APP/**", + "$APP", ), }, ), diff --git a/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap b/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap index 4c56de8fa..5805c5833 100644 --- a/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap +++ b/core/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap @@ -1,6 +1,5 @@ --- source: core/tests/acl/src/lib.rs -assertion_line: 59 expression: resolved --- Resolved { @@ -58,7 +57,7 @@ Resolved { }, ], scope: Some( - 7912899488978770657, + 5856262838373339618, ), }, CommandKey { @@ -92,6 +91,39 @@ Resolved { }, denied_commands: {}, command_scope: { + 5856262838373339618: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$RESOURCE/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE", + ), + }, + ), + Map( + { + "path": String( + "$DOWNLOAD", + ), + }, + ), + Map( + { + "path": String( + "$DOWNLOAD/**", + ), + }, + ), + ], + deny: [], + }, 7912899488978770657: ResolvedScope { allow: [ Map(