mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 14:17:02 +00:00
* refactor(core): capabilities must be referenced on the Tauri config file * add all capabilities by default * feat(codegen): allow defining additional capabilities, closes #8798 * undo example * lint * move add_capability to runtime authority * feat(core): add Manager::add_capability, closes #8799 * add change file
This commit is contained in:
parent
f284f9c545
commit
258494bd24
5
.changes/acl-scope-refactor.md
Normal file
5
.changes/acl-scope-refactor.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:breaking
|
||||
---
|
||||
|
||||
Removed the lifetime parameter from `ipc::GlobalScope` and `ipc::CommandScope`.
|
||||
5
.changes/runtime-add-capability.md
Normal file
5
.changes/runtime-add-capability.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:enhance
|
||||
---
|
||||
|
||||
Added `Manager::add_capability` to add a capability file at runtime.
|
||||
@ -338,6 +338,7 @@ struct ResolvedCommandTemp {
|
||||
pub scope: Vec<ScopeKey>,
|
||||
pub resolved_scope_key: Option<ScopeKey>,
|
||||
}
|
||||
|
||||
fn resolve_command(
|
||||
commands: &mut BTreeMap<CommandKey, ResolvedCommandTemp>,
|
||||
command: String,
|
||||
|
||||
@ -2,8 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::{collections::BTreeMap, ops::Deref};
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::de::DeserializeOwned;
|
||||
use state::TypeMap;
|
||||
@ -335,11 +336,18 @@ impl RuntimeAuthority {
|
||||
/// List of allowed and denied objects that match either the command-specific or plugin global scope criterias.
|
||||
#[derive(Debug)]
|
||||
pub struct ScopeValue<T: ScopeObject> {
|
||||
allow: Vec<T>,
|
||||
deny: Vec<T>,
|
||||
allow: Arc<Vec<T>>,
|
||||
deny: Arc<Vec<T>>,
|
||||
}
|
||||
|
||||
impl<T: ScopeObject> ScopeValue<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
allow: self.allow.clone(),
|
||||
deny: self.deny.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// What this access scope allows.
|
||||
pub fn allows(&self) -> &Vec<T> {
|
||||
&self.allow
|
||||
@ -351,27 +359,11 @@ impl<T: ScopeObject> ScopeValue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OwnedOrRef<'a, T: Debug> {
|
||||
Owned(T),
|
||||
Ref(&'a T),
|
||||
}
|
||||
|
||||
impl<'a, T: Debug> Deref for OwnedOrRef<'a, T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Owned(t) => t,
|
||||
Self::Ref(r) => r,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Access scope for a command that can be retrieved directly in the command function.
|
||||
#[derive(Debug)]
|
||||
pub struct CommandScope<'a, T: ScopeObject>(OwnedOrRef<'a, ScopeValue<T>>);
|
||||
pub struct CommandScope<T: ScopeObject>(ScopeValue<T>);
|
||||
|
||||
impl<'a, T: ScopeObject> CommandScope<'a, T> {
|
||||
impl<T: ScopeObject> CommandScope<T> {
|
||||
/// What this access scope allows.
|
||||
pub fn allows(&self) -> &Vec<T> {
|
||||
&self.0.allow
|
||||
@ -383,33 +375,35 @@ impl<'a, T: ScopeObject> CommandScope<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for CommandScope<'a, T> {
|
||||
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for CommandScope<T> {
|
||||
/// Grabs the [`ResolvedScope`] from the [`CommandItem`] and returns the associated [`CommandScope`].
|
||||
fn from_command(command: CommandItem<'a, R>) -> Result<Self, InvokeError> {
|
||||
if let Some(scope_id) = command.acl.as_ref().and_then(|resolved| resolved.scope) {
|
||||
Ok(CommandScope(OwnedOrRef::Ref(
|
||||
Ok(CommandScope(
|
||||
command
|
||||
.message
|
||||
.webview
|
||||
.manager()
|
||||
.runtime_authority
|
||||
.lock()
|
||||
.unwrap()
|
||||
.scope_manager
|
||||
.get_command_scope_typed(command.message.webview.app_handle(), &scope_id)?,
|
||||
)))
|
||||
))
|
||||
} else {
|
||||
Ok(CommandScope(OwnedOrRef::Owned(ScopeValue {
|
||||
allow: Vec::new(),
|
||||
deny: Vec::new(),
|
||||
})))
|
||||
Ok(CommandScope(ScopeValue {
|
||||
allow: Default::default(),
|
||||
deny: Default::default(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Global access scope that can be retrieved directly in the command function.
|
||||
#[derive(Debug)]
|
||||
pub struct GlobalScope<'a, T: ScopeObject>(&'a ScopeValue<T>);
|
||||
pub struct GlobalScope<T: ScopeObject>(ScopeValue<T>);
|
||||
|
||||
impl<'a, T: ScopeObject> GlobalScope<'a, T> {
|
||||
impl<T: ScopeObject> GlobalScope<T> {
|
||||
/// What this access scope allows.
|
||||
pub fn allows(&self) -> &Vec<T> {
|
||||
&self.0.allow
|
||||
@ -421,7 +415,7 @@ impl<'a, T: ScopeObject> GlobalScope<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for GlobalScope<'a, T> {
|
||||
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for GlobalScope<T> {
|
||||
/// Grabs the [`ResolvedScope`] from the [`CommandItem`] and returns the associated [`GlobalScope`].
|
||||
fn from_command(command: CommandItem<'a, R>) -> Result<Self, InvokeError> {
|
||||
command
|
||||
@ -437,6 +431,8 @@ impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for GlobalScope<'a, T> {
|
||||
.webview
|
||||
.manager()
|
||||
.runtime_authority
|
||||
.lock()
|
||||
.unwrap()
|
||||
.scope_manager
|
||||
.get_global_scope_typed(command.message.webview.app_handle(), plugin)
|
||||
.map_err(InvokeError::from_error)
|
||||
@ -476,9 +472,9 @@ impl ScopeManager {
|
||||
&self,
|
||||
app: &AppHandle<R>,
|
||||
plugin: &str,
|
||||
) -> crate::Result<&ScopeValue<T>> {
|
||||
match self.global_scope_cache.try_get() {
|
||||
Some(cached) => Ok(cached),
|
||||
) -> crate::Result<ScopeValue<T>> {
|
||||
match self.global_scope_cache.try_get::<ScopeValue<T>>() {
|
||||
Some(cached) => Ok(cached.clone()),
|
||||
None => {
|
||||
let mut allow: Vec<T> = Vec::new();
|
||||
let mut deny: Vec<T> = Vec::new();
|
||||
@ -498,9 +494,12 @@ impl ScopeManager {
|
||||
}
|
||||
}
|
||||
|
||||
let scope = ScopeValue { allow, deny };
|
||||
let _ = self.global_scope_cache.set(scope);
|
||||
Ok(self.global_scope_cache.get())
|
||||
let scope = ScopeValue {
|
||||
allow: Arc::new(allow),
|
||||
deny: Arc::new(deny),
|
||||
};
|
||||
self.global_scope_cache.set(scope.clone());
|
||||
Ok(scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -509,10 +508,10 @@ impl ScopeManager {
|
||||
&self,
|
||||
app: &AppHandle<R>,
|
||||
key: &ScopeKey,
|
||||
) -> crate::Result<&ScopeValue<T>> {
|
||||
) -> crate::Result<ScopeValue<T>> {
|
||||
let cache = self.command_cache.get(key).unwrap();
|
||||
match cache.try_get() {
|
||||
Some(cached) => Ok(cached),
|
||||
match cache.try_get::<ScopeValue<T>>() {
|
||||
Some(cached) => Ok(cached.clone()),
|
||||
None => {
|
||||
let resolved_scope = self
|
||||
.command_scope
|
||||
@ -535,10 +534,13 @@ impl ScopeManager {
|
||||
);
|
||||
}
|
||||
|
||||
let value = ScopeValue { allow, deny };
|
||||
let value = ScopeValue {
|
||||
allow: Arc::new(allow),
|
||||
deny: Arc::new(deny),
|
||||
};
|
||||
|
||||
let _ = cache.set(value);
|
||||
Ok(cache.get())
|
||||
let _ = cache.set(value.clone());
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -966,6 +966,28 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
|
||||
fn path(&self) -> &crate::path::PathResolver<R> {
|
||||
self.state::<crate::path::PathResolver<R>>().inner()
|
||||
}
|
||||
|
||||
/// Adds a capability to the app.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use tauri::Manager;
|
||||
///
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// #[cfg(feature = "beta")]
|
||||
/// app.add_capability(include_str!("../capabilities/beta.json"));
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
fn add_capability(&self, capability: &'static str) -> Result<()> {
|
||||
self
|
||||
.manager()
|
||||
.runtime_authority
|
||||
.lock()
|
||||
.unwrap()
|
||||
.add_capability(capability.parse().expect("invalid capability"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Prevent implementation details from leaking out of the [`Manager`] trait.
|
||||
|
||||
@ -175,7 +175,7 @@ pub struct Asset {
|
||||
|
||||
#[default_runtime(crate::Wry, wry)]
|
||||
pub struct AppManager<R: Runtime> {
|
||||
pub runtime_authority: RuntimeAuthority,
|
||||
pub runtime_authority: Mutex<RuntimeAuthority>,
|
||||
pub window: window::WindowManager<R>,
|
||||
pub webview: webview::WebviewManager<R>,
|
||||
#[cfg(all(desktop, feature = "tray-icon"))]
|
||||
@ -245,7 +245,7 @@ impl<R: Runtime> AppManager<R> {
|
||||
}
|
||||
|
||||
Self {
|
||||
runtime_authority: context.runtime_authority,
|
||||
runtime_authority: Mutex::new(context.runtime_authority),
|
||||
window: window::WindowManager {
|
||||
windows: Mutex::default(),
|
||||
default_icon: context.default_window_icon,
|
||||
|
||||
@ -139,11 +139,13 @@ impl<R: Runtime, C: DeserializeOwned> PluginApi<R, C> {
|
||||
}
|
||||
|
||||
/// Gets the global scope defined on the permissions that are part of the app ACL.
|
||||
pub fn scope<T: ScopeObject>(&self) -> crate::Result<&ScopeValue<T>> {
|
||||
pub fn scope<T: ScopeObject>(&self) -> crate::Result<ScopeValue<T>> {
|
||||
self
|
||||
.handle
|
||||
.manager
|
||||
.runtime_authority
|
||||
.lock()
|
||||
.unwrap()
|
||||
.scope_manager
|
||||
.get_global_scope_typed(&self.handle, self.name)
|
||||
}
|
||||
|
||||
@ -1118,6 +1118,8 @@ fn main() {
|
||||
};
|
||||
let resolved_acl = manager
|
||||
.runtime_authority
|
||||
.lock()
|
||||
.unwrap()
|
||||
.resolve_access(
|
||||
&request.cmd,
|
||||
message.webview.label(),
|
||||
@ -1142,15 +1144,19 @@ fn main() {
|
||||
if request.cmd != crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND && invoke.acl.is_none() {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
invoke
|
||||
.resolver
|
||||
.reject(manager.runtime_authority.resolve_access_message(
|
||||
plugin,
|
||||
&command_name,
|
||||
invoke.message.webview.window().label(),
|
||||
invoke.message.webview.label(),
|
||||
&acl_origin,
|
||||
));
|
||||
invoke.resolver.reject(
|
||||
manager
|
||||
.runtime_authority
|
||||
.lock()
|
||||
.unwrap()
|
||||
.resolve_access_message(
|
||||
plugin,
|
||||
&command_name,
|
||||
invoke.message.webview.window().label(),
|
||||
invoke.message.webview.label(),
|
||||
&acl_origin,
|
||||
),
|
||||
);
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
invoke
|
||||
|
||||
Loading…
Reference in New Issue
Block a user