Skip to content

Commit

Permalink
global scope
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Jan 14, 2024
1 parent 0922789 commit 72d32d9
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 54 deletions.
65 changes: 42 additions & 23 deletions core/tauri-codegen/src/context/resolve_acl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ pub fn resolve(
let mut denied_commands = HashMap::new();

let mut current_scope_id = 0;
let mut scopes = HashMap::new();
let mut command_scopes = HashMap::new();
let mut global_scope = Vec::new();

// resolve commands
for capability in capabilities.values() {
Expand All @@ -40,25 +41,31 @@ pub fn resolve(
let permissions = get_permissions(plugin_name, permission_name, &acl)?;

for permission in permissions {
current_scope_id += 1;
scopes.insert(current_scope_id, permission.inner.scope.clone());

for allowed_command in &permission.inner.commands.allow {
resolve_command(
&mut allowed_commands,
format!("plugin:{plugin_name}|{allowed_command}"),
capability,
current_scope_id,
);
}

for denied_command in &permission.inner.commands.deny {
resolve_command(
&mut denied_commands,
format!("plugin:{plugin_name}|{denied_command}"),
capability,
current_scope_id,
);
if permission.inner.commands.allow.is_empty() && permission.inner.commands.deny.is_empty()
{
// global scope
global_scope.push(permission.inner.scope.clone());
} else {
current_scope_id += 1;
command_scopes.insert(current_scope_id, permission.inner.scope.clone());

for allowed_command in &permission.inner.commands.allow {
resolve_command(
&mut allowed_commands,
format!("plugin:{plugin_name}|{allowed_command}"),
capability,
current_scope_id,
);
}

for denied_command in &permission.inner.commands.deny {
resolve_command(
&mut denied_commands,
format!("plugin:{plugin_name}|{denied_command}"),
capability,
current_scope_id,
);
}
}
}
}
Expand All @@ -81,18 +88,29 @@ pub fn resolve(
allow: allowed
.scope
.iter()
.flat_map(|s| scopes.get(s).unwrap().allow.clone())
.flat_map(|s| command_scopes.get(s).unwrap().allow.clone())
.collect(),
deny: allowed
.scope
.iter()
.flat_map(|s| scopes.get(s).unwrap().deny.clone())
.flat_map(|s| command_scopes.get(s).unwrap().deny.clone())
.collect(),
};

resolved_scopes.insert(hash, resolved_scope);
}

let global_scope = ResolvedScope {
allow: global_scope
.iter_mut()
.flat_map(|s| s.allow.take())
.collect(),
deny: global_scope
.iter_mut()
.flat_map(|s| s.deny.take())
.collect(),
};

let resolved = Resolved {
allowed_commands: allowed_commands
.into_iter()
Expand All @@ -118,7 +136,8 @@ pub fn resolve(
)
})
.collect(),
scope: resolved_scopes,
command_scope: resolved_scopes,
global_scope,
};

Ok(resolved)
Expand Down
21 changes: 16 additions & 5 deletions core/tauri-utils/src/acl/resolved.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct ResolvedCommand {
}

/// A resolved scope. Merges all scopes defined for a single command.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct ResolvedScope {
/// Allows something on the command.
pub allow: Vec<Value>,
Expand All @@ -42,7 +42,9 @@ pub struct Resolved {
/// The commands that are denied. Map each command with its context to a [`ResolvedCommand`].
pub denied_commands: BTreeMap<CommandKey, ResolvedCommand>,
/// The store of scopes referenced by a [`ResolvedCommand`].
pub scope: BTreeMap<ScopeKey, ResolvedScope>,
pub command_scope: BTreeMap<ScopeKey, ResolvedScope>,
/// The global scope.
pub global_scope: ResolvedScope,
}

#[cfg(feature = "build")]
Expand Down Expand Up @@ -107,14 +109,23 @@ mod build {
identity,
);

let scope = map_lit(
let command_scope = map_lit(
quote! { ::std::collections::BTreeMap },
&self.scope,
&self.command_scope,
identity,
identity,
);

literal_struct!(tokens, Resolved, allowed_commands, denied_commands, scope)
let global_scope = &self.global_scope;

literal_struct!(
tokens,
Resolved,
allowed_commands,
denied_commands,
command_scope,
global_scope
)
}
}
}
105 changes: 84 additions & 21 deletions core/tauri/src/command/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,19 @@ pub struct RuntimeAuthority {

impl RuntimeAuthority {
pub(crate) fn new(acl: Resolved) -> Self {
let command_cache = acl
.command_scope
.keys()
.map(|key| (*key, <TypeMap![Send + Sync]>::new()))
.collect();
Self {
allowed_commands: acl.allowed_commands,
denied_commands: acl.denied_commands,
scope_manager: ScopeManager {
raw: acl.scope,
cache: <TypeMap![Send + Sync]>::new(),
command_scope: acl.command_scope,
global_scope: acl.global_scope,
command_cache,
global_scope_cache: Default::default(),
},
}
}
Expand Down Expand Up @@ -55,18 +62,16 @@ impl RuntimeAuthority {
}

#[derive(Debug)]
struct CommandScope<T: Debug + DeserializeOwned + Send + Sync + 'static> {
struct ScopeValue<T: Debug + DeserializeOwned + Send + Sync + 'static> {
allow: Vec<T>,
deny: Vec<T>,
}

/// Access scope for a command that can be retrieved directly in the command function.
#[derive(Debug)]
pub struct AccessScope<'a, T: Debug + DeserializeOwned + Send + Sync + 'static>(
&'a CommandScope<T>,
);
pub struct CommandScope<'a, T: Debug + DeserializeOwned + Send + Sync + 'static>(&'a ScopeValue<T>);

impl<'a, T: Debug + DeserializeOwned + Send + Sync + 'static> AccessScope<'a, T> {
impl<'a, T: Debug + DeserializeOwned + Send + Sync + 'static> CommandScope<'a, T> {
/// What this access scope allows.
pub fn allows(&self) -> &Vec<T> {
&self.0.allow
Expand All @@ -79,9 +84,9 @@ impl<'a, T: Debug + DeserializeOwned + Send + Sync + 'static> AccessScope<'a, T>
}

impl<'a, R: Runtime, T: Debug + DeserializeOwned + Send + Sync + 'static> CommandArg<'a, R>
for AccessScope<'a, T>
for CommandScope<'a, T>
{
/// Grabs the [`Window`] from the [`CommandItem`] and returns the associated [`Scope`].
/// Grabs the [`ResolvedScope`] from the [`CommandItem`] and returns the associated [`CommandScope`].
fn from_command(command: CommandItem<'a, R>) -> Result<Self, InvokeError> {
command
.acl
Expand All @@ -93,27 +98,85 @@ impl<'a, R: Runtime, T: Debug + DeserializeOwned + Send + Sync + 'static> Comman
.manager
.runtime_authority
.scope_manager
.get_typed(&resolved.scope)
.map(AccessScope)
.get_command_scope_typed(&resolved.scope)
.map(CommandScope)
})
.ok_or_else(|| InvokeError::from_anyhow(anyhow::anyhow!("scope not found")))
}
}

#[derive(Debug, Default)]
/// Global access scope that can be retrieved directly in the command function.
#[derive(Debug)]
pub struct GlobalScope<'a, T: Debug + DeserializeOwned + Send + Sync + 'static>(&'a ScopeValue<T>);

impl<'a, T: Debug + DeserializeOwned + Send + Sync + 'static> GlobalScope<'a, T> {
/// What this access scope allows.
pub fn allows(&self) -> &Vec<T> {
&self.0.allow
}

/// What this access scope denies.
pub fn denies(&self) -> &Vec<T> {
&self.0.deny
}
}

impl<'a, R: Runtime, T: Debug + DeserializeOwned + Send + Sync + 'static> CommandArg<'a, R>
for GlobalScope<'a, T>
{
/// Grabs the [`ResolvedScope`] from the [`CommandItem`] and returns the associated [`GlobalScope`].
fn from_command(command: CommandItem<'a, R>) -> Result<Self, InvokeError> {
let scope = command
.message
.window
.manager
.runtime_authority
.scope_manager
.get_global_scope_typed();
Ok(GlobalScope(scope))
}
}

#[derive(Debug)]
pub struct ScopeManager {
raw: BTreeMap<ScopeKey, ResolvedScope>,
cache: TypeMap![Send + Sync],
command_scope: BTreeMap<ScopeKey, ResolvedScope>,
global_scope: ResolvedScope,
command_cache: BTreeMap<ScopeKey, TypeMap![Send + Sync]>,
global_scope_cache: TypeMap![Send + Sync],
}

impl ScopeManager {
fn get_typed<T: Send + Sync + DeserializeOwned + Debug + 'static>(
fn get_global_scope_typed<T: Send + Sync + DeserializeOwned + Debug + 'static>(
&self,
) -> &ScopeValue<T> {
match self.global_scope_cache.try_get() {
Some(cached) => cached,
None => {
let mut allow: Vec<T> = Vec::new();
let mut deny: Vec<T> = Vec::new();

for allowed in &self.global_scope.allow {
allow.push(allowed.deserialize().unwrap());
}
for denied in &self.global_scope.deny {
deny.push(denied.deserialize().unwrap());
}

let scope = ScopeValue { allow, deny };
let _ = self.global_scope_cache.set(scope);
self.global_scope_cache.get()
}
}
}

fn get_command_scope_typed<T: Send + Sync + DeserializeOwned + Debug + 'static>(
&self,
key: &ScopeKey,
) -> Option<&CommandScope<T>> {
match self.cache.try_get() {
) -> Option<&ScopeValue<T>> {
let cache = self.command_cache.get(key).unwrap();
match cache.try_get() {
cached @ Some(_) => cached,
None => match self.raw.get(key).map(|r| {
None => match self.command_scope.get(key).map(|r| {
let mut allow: Vec<T> = Vec::new();
let mut deny: Vec<T> = Vec::new();

Expand All @@ -124,12 +187,12 @@ impl ScopeManager {
deny.push(denied.deserialize().unwrap());
}

CommandScope { allow, deny }
ScopeValue { allow, deny }
}) {
None => None,
Some(value) => {
let _ = self.cache.set(value);
self.cache.try_get()
let _ = cache.set(value);
cache.try_get()
}
},
}
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use serde::{

mod authority;

pub use authority::{AccessScope, RuntimeAuthority};
pub use authority::{CommandScope, GlobalScope, RuntimeAuthority};
use tauri_utils::acl::resolved::ResolvedCommand;

/// Represents a custom command.
Expand Down
3 changes: 2 additions & 1 deletion core/tauri/src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context<A> {
resolved_acl: Resolved {
allowed_commands: Default::default(),
denied_commands: Default::default(),
scope: Default::default(),
command_scope: Default::default(),
global_scope: Default::default(),
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/api/src-tauri/capabilities/run-app.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
identifier = "run-app"
description = "app capability"
windows = ["main"]
permissions = ["sample:allow-ping-scoped"]
permissions = ["sample:allow-ping-scoped", "sample:global-scope"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[[permission]]
identifier = "global-scope"
description = "This sets a global scope."
[permission.scope.allow]
path = "global"
6 changes: 4 additions & 2 deletions examples/api/src-tauri/tauri-plugin-sample/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ struct PingScope {
fn ping<R: tauri::Runtime>(
app: tauri::AppHandle<R>,
value: Option<String>,
scope: tauri::command::AccessScope<PingScope>,
scope: tauri::command::CommandScope<PingScope>,
global_scope: tauri::command::GlobalScope<PingScope>,
) -> std::result::Result<PingResponse, String> {
println!("{:?}", scope);
println!("local scope {:?}", scope);
println!("global scope {:?}", global_scope);
app
.sample()
.ping(PingRequest {
Expand Down

0 comments on commit 72d32d9

Please sign in to comment.