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 serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use state::TypeMap;
|
||||
|
||||
use tauri_utils::acl::capability::CapabilityFile;
|
||||
use tauri_utils::acl::manifest::Manifest;
|
||||
use tauri_utils::acl::{
|
||||
capability::{Capability, CapabilityFile, PermissionEntry},
|
||||
manifest::Manifest,
|
||||
Value, APP_ACL_KEY,
|
||||
};
|
||||
use tauri_utils::acl::{
|
||||
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::{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 {
|
||||
#[doc(hidden)]
|
||||
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.
|
||||
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();
|
||||
match capability {
|
||||
match capability.build() {
|
||||
CapabilityFile::Capability(c) => {
|
||||
capabilities.insert(c.identifier.clone(), c);
|
||||
}
|
||||
|
@ -24,7 +24,10 @@ mod command;
|
||||
pub(crate) mod format_callback;
|
||||
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 command::{private, CommandArg, CommandItem};
|
||||
|
||||
|
@ -69,7 +69,7 @@ pub use cocoa;
|
||||
#[doc(hidden)]
|
||||
pub use embed_plist;
|
||||
pub use error::{Error, Result};
|
||||
use ipc::RuntimeAuthority;
|
||||
use ipc::{RuntimeAuthority, RuntimeCapability};
|
||||
pub use resources::{Resource, ResourceId, ResourceTable};
|
||||
#[cfg(target_os = "ios")]
|
||||
#[doc(hidden)]
|
||||
@ -888,13 +888,13 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
fn add_capability(&self, capability: &'static str) -> Result<()> {
|
||||
fn add_capability(&self, capability: impl RuntimeCapability) -> Result<()> {
|
||||
self
|
||||
.manager()
|
||||
.runtime_authority
|
||||
.lock()
|
||||
.unwrap()
|
||||
.add_capability(capability.parse().expect("invalid capability"))
|
||||
.add_capability(capability)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,7 @@ use tauri_runtime::{
|
||||
window::dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
WindowDispatch,
|
||||
};
|
||||
use tauri_utils::{
|
||||
acl::APP_ACL_KEY,
|
||||
config::{WebviewUrl, WindowConfig},
|
||||
};
|
||||
use tauri_utils::config::{WebviewUrl, WindowConfig};
|
||||
pub use url::Url;
|
||||
|
||||
use crate::{
|
||||
@ -1192,7 +1189,7 @@ fn main() {
|
||||
{
|
||||
let (key, command_name) = plugin_command
|
||||
.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(
|
||||
manager
|
||||
.runtime_authority
|
||||
|
Loading…
Reference in New Issue
Block a user