Skip to content

Commit 258494b

Browse files
authored
feat(core): add Manager::add_capability, closes #8799 (#8806)
* 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
1 parent f284f9c commit 258494b

File tree

8 files changed

+98
-55
lines changed

8 files changed

+98
-55
lines changed

.changes/acl-scope-refactor.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch:breaking
3+
---
4+
5+
Removed the lifetime parameter from `ipc::GlobalScope` and `ipc::CommandScope`.

.changes/runtime-add-capability.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch:enhance
3+
---
4+
5+
Added `Manager::add_capability` to add a capability file at runtime.

core/tauri-utils/src/acl/resolved.rs

+1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ struct ResolvedCommandTemp {
338338
pub scope: Vec<ScopeKey>,
339339
pub resolved_scope_key: Option<ScopeKey>,
340340
}
341+
341342
fn resolve_command(
342343
commands: &mut BTreeMap<CommandKey, ResolvedCommandTemp>,
343344
command: String,

core/tauri/src/ipc/authority.rs

+45-43
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5+
use std::collections::BTreeMap;
56
use std::fmt::{Debug, Display};
6-
use std::{collections::BTreeMap, ops::Deref};
7+
use std::sync::Arc;
78

89
use serde::de::DeserializeOwned;
910
use state::TypeMap;
@@ -335,11 +336,18 @@ impl RuntimeAuthority {
335336
/// List of allowed and denied objects that match either the command-specific or plugin global scope criterias.
336337
#[derive(Debug)]
337338
pub struct ScopeValue<T: ScopeObject> {
338-
allow: Vec<T>,
339-
deny: Vec<T>,
339+
allow: Arc<Vec<T>>,
340+
deny: Arc<Vec<T>>,
340341
}
341342

342343
impl<T: ScopeObject> ScopeValue<T> {
344+
fn clone(&self) -> Self {
345+
Self {
346+
allow: self.allow.clone(),
347+
deny: self.deny.clone(),
348+
}
349+
}
350+
343351
/// What this access scope allows.
344352
pub fn allows(&self) -> &Vec<T> {
345353
&self.allow
@@ -351,27 +359,11 @@ impl<T: ScopeObject> ScopeValue<T> {
351359
}
352360
}
353361

354-
#[derive(Debug)]
355-
enum OwnedOrRef<'a, T: Debug> {
356-
Owned(T),
357-
Ref(&'a T),
358-
}
359-
360-
impl<'a, T: Debug> Deref for OwnedOrRef<'a, T> {
361-
type Target = T;
362-
fn deref(&self) -> &Self::Target {
363-
match self {
364-
Self::Owned(t) => t,
365-
Self::Ref(r) => r,
366-
}
367-
}
368-
}
369-
370362
/// Access scope for a command that can be retrieved directly in the command function.
371363
#[derive(Debug)]
372-
pub struct CommandScope<'a, T: ScopeObject>(OwnedOrRef<'a, ScopeValue<T>>);
364+
pub struct CommandScope<T: ScopeObject>(ScopeValue<T>);
373365

374-
impl<'a, T: ScopeObject> CommandScope<'a, T> {
366+
impl<T: ScopeObject> CommandScope<T> {
375367
/// What this access scope allows.
376368
pub fn allows(&self) -> &Vec<T> {
377369
&self.0.allow
@@ -383,33 +375,35 @@ impl<'a, T: ScopeObject> CommandScope<'a, T> {
383375
}
384376
}
385377

386-
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for CommandScope<'a, T> {
378+
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for CommandScope<T> {
387379
/// Grabs the [`ResolvedScope`] from the [`CommandItem`] and returns the associated [`CommandScope`].
388380
fn from_command(command: CommandItem<'a, R>) -> Result<Self, InvokeError> {
389381
if let Some(scope_id) = command.acl.as_ref().and_then(|resolved| resolved.scope) {
390-
Ok(CommandScope(OwnedOrRef::Ref(
382+
Ok(CommandScope(
391383
command
392384
.message
393385
.webview
394386
.manager()
395387
.runtime_authority
388+
.lock()
389+
.unwrap()
396390
.scope_manager
397391
.get_command_scope_typed(command.message.webview.app_handle(), &scope_id)?,
398-
)))
392+
))
399393
} else {
400-
Ok(CommandScope(OwnedOrRef::Owned(ScopeValue {
401-
allow: Vec::new(),
402-
deny: Vec::new(),
403-
})))
394+
Ok(CommandScope(ScopeValue {
395+
allow: Default::default(),
396+
deny: Default::default(),
397+
}))
404398
}
405399
}
406400
}
407401

408402
/// Global access scope that can be retrieved directly in the command function.
409403
#[derive(Debug)]
410-
pub struct GlobalScope<'a, T: ScopeObject>(&'a ScopeValue<T>);
404+
pub struct GlobalScope<T: ScopeObject>(ScopeValue<T>);
411405

412-
impl<'a, T: ScopeObject> GlobalScope<'a, T> {
406+
impl<T: ScopeObject> GlobalScope<T> {
413407
/// What this access scope allows.
414408
pub fn allows(&self) -> &Vec<T> {
415409
&self.0.allow
@@ -421,7 +415,7 @@ impl<'a, T: ScopeObject> GlobalScope<'a, T> {
421415
}
422416
}
423417

424-
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for GlobalScope<'a, T> {
418+
impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for GlobalScope<T> {
425419
/// Grabs the [`ResolvedScope`] from the [`CommandItem`] and returns the associated [`GlobalScope`].
426420
fn from_command(command: CommandItem<'a, R>) -> Result<Self, InvokeError> {
427421
command
@@ -437,6 +431,8 @@ impl<'a, R: Runtime, T: ScopeObject> CommandArg<'a, R> for GlobalScope<'a, T> {
437431
.webview
438432
.manager()
439433
.runtime_authority
434+
.lock()
435+
.unwrap()
440436
.scope_manager
441437
.get_global_scope_typed(command.message.webview.app_handle(), plugin)
442438
.map_err(InvokeError::from_error)
@@ -476,9 +472,9 @@ impl ScopeManager {
476472
&self,
477473
app: &AppHandle<R>,
478474
plugin: &str,
479-
) -> crate::Result<&ScopeValue<T>> {
480-
match self.global_scope_cache.try_get() {
481-
Some(cached) => Ok(cached),
475+
) -> crate::Result<ScopeValue<T>> {
476+
match self.global_scope_cache.try_get::<ScopeValue<T>>() {
477+
Some(cached) => Ok(cached.clone()),
482478
None => {
483479
let mut allow: Vec<T> = Vec::new();
484480
let mut deny: Vec<T> = Vec::new();
@@ -498,9 +494,12 @@ impl ScopeManager {
498494
}
499495
}
500496

501-
let scope = ScopeValue { allow, deny };
502-
let _ = self.global_scope_cache.set(scope);
503-
Ok(self.global_scope_cache.get())
497+
let scope = ScopeValue {
498+
allow: Arc::new(allow),
499+
deny: Arc::new(deny),
500+
};
501+
self.global_scope_cache.set(scope.clone());
502+
Ok(scope)
504503
}
505504
}
506505
}
@@ -509,10 +508,10 @@ impl ScopeManager {
509508
&self,
510509
app: &AppHandle<R>,
511510
key: &ScopeKey,
512-
) -> crate::Result<&ScopeValue<T>> {
511+
) -> crate::Result<ScopeValue<T>> {
513512
let cache = self.command_cache.get(key).unwrap();
514-
match cache.try_get() {
515-
Some(cached) => Ok(cached),
513+
match cache.try_get::<ScopeValue<T>>() {
514+
Some(cached) => Ok(cached.clone()),
516515
None => {
517516
let resolved_scope = self
518517
.command_scope
@@ -535,10 +534,13 @@ impl ScopeManager {
535534
);
536535
}
537536

538-
let value = ScopeValue { allow, deny };
537+
let value = ScopeValue {
538+
allow: Arc::new(allow),
539+
deny: Arc::new(deny),
540+
};
539541

540-
let _ = cache.set(value);
541-
Ok(cache.get())
542+
let _ = cache.set(value.clone());
543+
Ok(value)
542544
}
543545
}
544546
}

core/tauri/src/lib.rs

+22
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,28 @@ pub trait Manager<R: Runtime>: sealed::ManagerBase<R> {
966966
fn path(&self) -> &crate::path::PathResolver<R> {
967967
self.state::<crate::path::PathResolver<R>>().inner()
968968
}
969+
970+
/// Adds a capability to the app.
971+
///
972+
/// # Examples
973+
/// ```
974+
/// use tauri::Manager;
975+
///
976+
/// tauri::Builder::default()
977+
/// .setup(|app| {
978+
/// #[cfg(feature = "beta")]
979+
/// app.add_capability(include_str!("../capabilities/beta.json"));
980+
/// Ok(())
981+
/// });
982+
/// ```
983+
fn add_capability(&self, capability: &'static str) -> Result<()> {
984+
self
985+
.manager()
986+
.runtime_authority
987+
.lock()
988+
.unwrap()
989+
.add_capability(capability.parse().expect("invalid capability"))
990+
}
969991
}
970992

971993
/// Prevent implementation details from leaking out of the [`Manager`] trait.

core/tauri/src/manager/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ pub struct Asset {
175175

176176
#[default_runtime(crate::Wry, wry)]
177177
pub struct AppManager<R: Runtime> {
178-
pub runtime_authority: RuntimeAuthority,
178+
pub runtime_authority: Mutex<RuntimeAuthority>,
179179
pub window: window::WindowManager<R>,
180180
pub webview: webview::WebviewManager<R>,
181181
#[cfg(all(desktop, feature = "tray-icon"))]
@@ -245,7 +245,7 @@ impl<R: Runtime> AppManager<R> {
245245
}
246246

247247
Self {
248-
runtime_authority: context.runtime_authority,
248+
runtime_authority: Mutex::new(context.runtime_authority),
249249
window: window::WindowManager {
250250
windows: Mutex::default(),
251251
default_icon: context.default_window_icon,

core/tauri/src/plugin.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,13 @@ impl<R: Runtime, C: DeserializeOwned> PluginApi<R, C> {
139139
}
140140

141141
/// Gets the global scope defined on the permissions that are part of the app ACL.
142-
pub fn scope<T: ScopeObject>(&self) -> crate::Result<&ScopeValue<T>> {
142+
pub fn scope<T: ScopeObject>(&self) -> crate::Result<ScopeValue<T>> {
143143
self
144144
.handle
145145
.manager
146146
.runtime_authority
147+
.lock()
148+
.unwrap()
147149
.scope_manager
148150
.get_global_scope_typed(&self.handle, self.name)
149151
}

core/tauri/src/webview/mod.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,8 @@ fn main() {
11181118
};
11191119
let resolved_acl = manager
11201120
.runtime_authority
1121+
.lock()
1122+
.unwrap()
11211123
.resolve_access(
11221124
&request.cmd,
11231125
message.webview.label(),
@@ -1142,15 +1144,19 @@ fn main() {
11421144
if request.cmd != crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND && invoke.acl.is_none() {
11431145
#[cfg(debug_assertions)]
11441146
{
1145-
invoke
1146-
.resolver
1147-
.reject(manager.runtime_authority.resolve_access_message(
1148-
plugin,
1149-
&command_name,
1150-
invoke.message.webview.window().label(),
1151-
invoke.message.webview.label(),
1152-
&acl_origin,
1153-
));
1147+
invoke.resolver.reject(
1148+
manager
1149+
.runtime_authority
1150+
.lock()
1151+
.unwrap()
1152+
.resolve_access_message(
1153+
plugin,
1154+
&command_name,
1155+
invoke.message.webview.window().label(),
1156+
invoke.message.webview.label(),
1157+
&acl_origin,
1158+
),
1159+
);
11541160
}
11551161
#[cfg(not(debug_assertions))]
11561162
invoke

0 commit comments

Comments
 (0)