|
@@ -77,11 +77,8 @@ pub struct CommandKey {
|
|
|
}
|
|
|
|
|
|
/// Resolved access control list.
|
|
|
-#[derive(Default)]
|
|
|
+#[derive(Debug, Default)]
|
|
|
pub struct Resolved {
|
|
|
- /// ACL plugin manifests.
|
|
|
- #[cfg(debug_assertions)]
|
|
|
- pub acl: BTreeMap<String, Manifest>,
|
|
|
/// The commands that are allowed. Map each command with its context to a [`ResolvedCommand`].
|
|
|
pub allowed_commands: BTreeMap<CommandKey, ResolvedCommand>,
|
|
|
/// The commands that are denied. Map each command with its context to a [`ResolvedCommand`].
|
|
@@ -92,21 +89,10 @@ pub struct Resolved {
|
|
|
pub global_scope: BTreeMap<String, ResolvedScope>,
|
|
|
}
|
|
|
|
|
|
-impl fmt::Debug for Resolved {
|
|
|
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
- f.debug_struct("Resolved")
|
|
|
- .field("allowed_commands", &self.allowed_commands)
|
|
|
- .field("denied_commands", &self.denied_commands)
|
|
|
- .field("command_scope", &self.command_scope)
|
|
|
- .field("global_scope", &self.global_scope)
|
|
|
- .finish()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
impl Resolved {
|
|
|
/// Resolves the ACL for the given plugin permissions and app capabilities.
|
|
|
pub fn resolve(
|
|
|
- acl: BTreeMap<String, Manifest>,
|
|
|
+ acl: &BTreeMap<String, Manifest>,
|
|
|
capabilities: BTreeMap<String, Capability>,
|
|
|
target: Target,
|
|
|
) -> Result<Self, Error> {
|
|
@@ -123,67 +109,25 @@ impl Resolved {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- for permission_entry in &capability.permissions {
|
|
|
- let permission_id = permission_entry.identifier();
|
|
|
- let permission_name = permission_id.get_base();
|
|
|
-
|
|
|
- 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 {
|
|
|
- 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());
|
|
|
- }
|
|
|
-
|
|
|
+ with_resolved_permissions(
|
|
|
+ capability,
|
|
|
+ acl,
|
|
|
+ |ResolvedPermission {
|
|
|
+ plugin_name,
|
|
|
+ permission_name,
|
|
|
+ commands,
|
|
|
+ scope,
|
|
|
+ }| {
|
|
|
if commands.allow.is_empty() && commands.deny.is_empty() {
|
|
|
// global scope
|
|
|
global_scope
|
|
|
.entry(plugin_name.to_string())
|
|
|
.or_default()
|
|
|
- .push(resolved_scope);
|
|
|
+ .push(scope);
|
|
|
} else {
|
|
|
- let has_scope = resolved_scope.allow.is_some() || resolved_scope.deny.is_some();
|
|
|
- if has_scope {
|
|
|
+ let scope_id = if scope.allow.is_some() || scope.deny.is_some() {
|
|
|
current_scope_id += 1;
|
|
|
- command_scopes.insert(current_scope_id, resolved_scope);
|
|
|
- }
|
|
|
-
|
|
|
- let scope_id = if has_scope {
|
|
|
+ command_scopes.insert(current_scope_id, scope);
|
|
|
Some(current_scope_id)
|
|
|
} else {
|
|
|
None
|
|
@@ -211,8 +155,8 @@ impl Resolved {
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
+ },
|
|
|
+ )?;
|
|
|
}
|
|
|
|
|
|
// resolve scopes
|
|
@@ -264,8 +208,6 @@ impl Resolved {
|
|
|
.collect();
|
|
|
|
|
|
let resolved = Self {
|
|
|
- #[cfg(debug_assertions)]
|
|
|
- acl,
|
|
|
allowed_commands: allowed_commands
|
|
|
.into_iter()
|
|
|
.map(|(key, cmd)| {
|
|
@@ -316,6 +258,77 @@ fn parse_glob_patterns(raw: HashSet<String>) -> Result<Vec<glob::Pattern>, Error
|
|
|
Ok(patterns)
|
|
|
}
|
|
|
|
|
|
+struct ResolvedPermission<'a> {
|
|
|
+ plugin_name: &'a str,
|
|
|
+ permission_name: &'a str,
|
|
|
+ commands: Commands,
|
|
|
+ scope: Scopes,
|
|
|
+}
|
|
|
+
|
|
|
+fn with_resolved_permissions<F: FnMut(ResolvedPermission<'_>)>(
|
|
|
+ capability: &Capability,
|
|
|
+ acl: &BTreeMap<String, Manifest>,
|
|
|
+ mut f: F,
|
|
|
+) -> Result<(), Error> {
|
|
|
+ for permission_entry in &capability.permissions {
|
|
|
+ let permission_id = permission_entry.identifier();
|
|
|
+ let permission_name = permission_id.get_base();
|
|
|
+
|
|
|
+ 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 {
|
|
|
+ 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());
|
|
|
+ }
|
|
|
+
|
|
|
+ f(ResolvedPermission {
|
|
|
+ plugin_name,
|
|
|
+ permission_name,
|
|
|
+ commands,
|
|
|
+ scope: resolved_scope,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+}
|
|
|
+
|
|
|
#[derive(Debug, Default)]
|
|
|
struct ResolvedCommandTemp {
|
|
|
#[cfg(debug_assertions)]
|
|
@@ -325,7 +338,6 @@ struct ResolvedCommandTemp {
|
|
|
pub scope: Vec<ScopeKey>,
|
|
|
pub resolved_scope_key: Option<ScopeKey>,
|
|
|
}
|
|
|
-
|
|
|
fn resolve_command(
|
|
|
commands: &mut BTreeMap<CommandKey, ResolvedCommandTemp>,
|
|
|
command: String,
|
|
@@ -511,14 +523,6 @@ mod build {
|
|
|
|
|
|
impl ToTokens for Resolved {
|
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
|
- #[cfg(debug_assertions)]
|
|
|
- let acl = map_lit(
|
|
|
- quote! { ::std::collections::BTreeMap },
|
|
|
- &self.acl,
|
|
|
- str_lit,
|
|
|
- identity,
|
|
|
- );
|
|
|
-
|
|
|
let allowed_commands = map_lit(
|
|
|
quote! { ::std::collections::BTreeMap },
|
|
|
&self.allowed_commands,
|
|
@@ -547,19 +551,6 @@ mod build {
|
|
|
identity,
|
|
|
);
|
|
|
|
|
|
- #[cfg(debug_assertions)]
|
|
|
- {
|
|
|
- literal_struct!(
|
|
|
- tokens,
|
|
|
- ::tauri::utils::acl::resolved::Resolved,
|
|
|
- acl,
|
|
|
- allowed_commands,
|
|
|
- denied_commands,
|
|
|
- command_scope,
|
|
|
- global_scope
|
|
|
- )
|
|
|
- }
|
|
|
- #[cfg(not(debug_assertions))]
|
|
|
literal_struct!(
|
|
|
tokens,
|
|
|
::tauri::utils::acl::resolved::Resolved,
|