mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-08-16 19:30:27 +03:00
feat(core): dynamic runtime capability (#9036)
* feat(core): dynamic runtime capability * local(), windows(), webviews() * enhance identation
This commit is contained in:
parent
a77be97474
commit
03098b5315
5
.changes/runtime-capability-dynamic.md
Normal file
5
.changes/runtime-capability-dynamic.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"tauri": patch:enhance
|
||||||
|
---
|
||||||
|
|
||||||
|
`Manager::add_capability` now allows adding a dynamically defined capability instead of only relying on static strings.
|
@ -7,15 +7,18 @@ use std::fmt::{Debug, Display};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::Serialize;
|
||||||
use state::TypeMap;
|
use state::TypeMap;
|
||||||
|
|
||||||
use tauri_utils::acl::capability::CapabilityFile;
|
use tauri_utils::acl::{
|
||||||
use tauri_utils::acl::manifest::Manifest;
|
capability::{Capability, CapabilityFile, PermissionEntry},
|
||||||
|
manifest::Manifest,
|
||||||
|
Value, APP_ACL_KEY,
|
||||||
|
};
|
||||||
use tauri_utils::acl::{
|
use tauri_utils::acl::{
|
||||||
resolved::{CommandKey, Resolved, ResolvedCommand, ResolvedScope, ScopeKey},
|
resolved::{CommandKey, Resolved, ResolvedCommand, ResolvedScope, ScopeKey},
|
||||||
ExecutionContext,
|
ExecutionContext, Scopes,
|
||||||
};
|
};
|
||||||
use tauri_utils::acl::{Value, APP_ACL_KEY};
|
|
||||||
|
|
||||||
use crate::{ipc::InvokeError, sealed::ManagerBase, Runtime};
|
use crate::{ipc::InvokeError, sealed::ManagerBase, Runtime};
|
||||||
use crate::{AppHandle, Manager};
|
use crate::{AppHandle, Manager};
|
||||||
@ -62,6 +65,140 @@ impl Origin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A capability that can be added at runtime.
|
||||||
|
pub trait RuntimeCapability {
|
||||||
|
/// Creates the capability file.
|
||||||
|
fn build(self) -> CapabilityFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> RuntimeCapability for T {
|
||||||
|
fn build(self) -> CapabilityFile {
|
||||||
|
self.as_ref().parse().expect("invalid capability")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A builder for a [`Capability`].
|
||||||
|
pub struct CapabilityBuilder(Capability);
|
||||||
|
|
||||||
|
impl CapabilityBuilder {
|
||||||
|
/// Creates a new capability builder with a unique identifier.
|
||||||
|
pub fn new(identifier: impl Into<String>) -> Self {
|
||||||
|
Self(Capability {
|
||||||
|
identifier: identifier.into(),
|
||||||
|
description: "".into(),
|
||||||
|
remote: None,
|
||||||
|
local: true,
|
||||||
|
windows: Vec::new(),
|
||||||
|
webviews: Vec::new(),
|
||||||
|
permissions: Vec::new(),
|
||||||
|
platforms: Vec::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows this capability to be used by a remote URL.
|
||||||
|
pub fn remote(mut self, url: String) -> Self {
|
||||||
|
self
|
||||||
|
.0
|
||||||
|
.remote
|
||||||
|
.get_or_insert_with(Default::default)
|
||||||
|
.urls
|
||||||
|
.push(url);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether this capability is applied on local app URLs or not. Defaults to `true`.
|
||||||
|
pub fn local(mut self, local: bool) -> Self {
|
||||||
|
self.0.local = local;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link this capability to the given window label.
|
||||||
|
pub fn window(mut self, window: impl Into<String>) -> Self {
|
||||||
|
self.0.windows.push(window.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link this capability to the a list of window labels.
|
||||||
|
pub fn windows(mut self, windows: impl IntoIterator<Item = impl Into<String>>) -> Self {
|
||||||
|
self.0.windows.extend(windows.into_iter().map(|w| w.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link this capability to the given webview label.
|
||||||
|
pub fn webview(mut self, webview: impl Into<String>) -> Self {
|
||||||
|
self.0.webviews.push(webview.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Link this capability to the a list of window labels.
|
||||||
|
pub fn webviews(mut self, webviews: impl IntoIterator<Item = impl Into<String>>) -> Self {
|
||||||
|
self
|
||||||
|
.0
|
||||||
|
.webviews
|
||||||
|
.extend(webviews.into_iter().map(|w| w.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new permission to this capability.
|
||||||
|
pub fn permission(mut self, permission: impl Into<String>) -> Self {
|
||||||
|
let permission = permission.into();
|
||||||
|
self.0.permissions.push(PermissionEntry::PermissionRef(
|
||||||
|
permission
|
||||||
|
.clone()
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or_else(|_| panic!("invalid permission identifier '{permission}'")),
|
||||||
|
));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new scoped permission to this capability.
|
||||||
|
pub fn permission_scoped<T: Serialize>(
|
||||||
|
mut self,
|
||||||
|
permission: impl Into<String>,
|
||||||
|
allowed: Vec<T>,
|
||||||
|
denied: Vec<T>,
|
||||||
|
) -> Self {
|
||||||
|
let permission = permission.into();
|
||||||
|
let identifier = permission
|
||||||
|
.clone()
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or_else(|_| panic!("invalid permission identifier '{permission}'"));
|
||||||
|
|
||||||
|
let allowed_scope = allowed
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| {
|
||||||
|
serde_json::to_value(a)
|
||||||
|
.expect("failed to serialize scope")
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let denied_scope = denied
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| {
|
||||||
|
serde_json::to_value(a)
|
||||||
|
.expect("failed to serialize scope")
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let scope = Scopes {
|
||||||
|
allow: Some(allowed_scope),
|
||||||
|
deny: Some(denied_scope),
|
||||||
|
};
|
||||||
|
|
||||||
|
self
|
||||||
|
.0
|
||||||
|
.permissions
|
||||||
|
.push(PermissionEntry::ExtendedPermission { identifier, scope });
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RuntimeCapability for CapabilityBuilder {
|
||||||
|
fn build(self) -> CapabilityFile {
|
||||||
|
CapabilityFile::Capability(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RuntimeAuthority {
|
impl RuntimeAuthority {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn new(acl: BTreeMap<String, Manifest>, resolved_acl: Resolved) -> Self {
|
pub fn new(acl: BTreeMap<String, Manifest>, resolved_acl: Resolved) -> Self {
|
||||||
@ -102,9 +239,9 @@ impl RuntimeAuthority {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the given capability to the runtime authority.
|
/// Adds the given capability to the runtime authority.
|
||||||
pub fn add_capability(&mut self, capability: CapabilityFile) -> crate::Result<()> {
|
pub fn add_capability(&mut self, capability: impl RuntimeCapability) -> crate::Result<()> {
|
||||||
let mut capabilities = BTreeMap::new();
|
let mut capabilities = BTreeMap::new();
|
||||||
match capability {
|
match capability.build() {
|
||||||
CapabilityFile::Capability(c) => {
|
CapabilityFile::Capability(c) => {
|
||||||
capabilities.insert(c.identifier.clone(), c);
|
capabilities.insert(c.identifier.clone(), c);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,10 @@ mod command;
|
|||||||
pub(crate) mod format_callback;
|
pub(crate) mod format_callback;
|
||||||
pub(crate) mod protocol;
|
pub(crate) mod protocol;
|
||||||
|
|
||||||
pub use authority::{CommandScope, GlobalScope, Origin, RuntimeAuthority, ScopeObject, ScopeValue};
|
pub use authority::{
|
||||||
|
CapabilityBuilder, CommandScope, GlobalScope, Origin, RuntimeAuthority, RuntimeCapability,
|
||||||
|
ScopeObject, ScopeValue,
|
||||||
|
};
|
||||||
pub use channel::{Channel, JavaScriptChannelId};
|
pub use channel::{Channel, JavaScriptChannelId};
|
||||||
pub use command::{private, CommandArg, CommandItem};
|
pub use command::{private, CommandArg, CommandItem};
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ pub use cocoa;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use embed_plist;
|
pub use embed_plist;
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
use ipc::RuntimeAuthority;
|
use ipc::{RuntimeAuthority, RuntimeCapability};
|
||||||
pub use resources::{Resource, ResourceId, ResourceTable};
|
pub use resources::{Resource, ResourceId, ResourceTable};
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -888,13 +888,13 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
|
|||||||
/// Ok(())
|
/// Ok(())
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
fn add_capability(&self, capability: &'static str) -> Result<()> {
|
fn add_capability(&self, capability: impl RuntimeCapability) -> Result<()> {
|
||||||
self
|
self
|
||||||
.manager()
|
.manager()
|
||||||
.runtime_authority
|
.runtime_authority
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_capability(capability.parse().expect("invalid capability"))
|
.add_capability(capability)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,7 @@ use tauri_runtime::{
|
|||||||
window::dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
window::dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
WindowDispatch,
|
WindowDispatch,
|
||||||
};
|
};
|
||||||
use tauri_utils::{
|
use tauri_utils::config::{WebviewUrl, WindowConfig};
|
||||||
acl::APP_ACL_KEY,
|
|
||||||
config::{WebviewUrl, WindowConfig},
|
|
||||||
};
|
|
||||||
pub use url::Url;
|
pub use url::Url;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -1192,7 +1189,7 @@ fn main() {
|
|||||||
{
|
{
|
||||||
let (key, command_name) = plugin_command
|
let (key, command_name) = plugin_command
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| (APP_ACL_KEY, request.cmd.clone()));
|
.unwrap_or_else(|| (tauri_utils::acl::APP_ACL_KEY, request.cmd.clone()));
|
||||||
invoke.resolver.reject(
|
invoke.resolver.reject(
|
||||||
manager
|
manager
|
||||||
.runtime_authority
|
.runtime_authority
|
||||||
|
Loading…
Reference in New Issue
Block a user