allow the app to define custom capabilities

This commit is contained in:
Lucas Nogueira 2023-07-30 17:36:20 -03:00
parent 708cb9fa28
commit b82899b96b
No known key found for this signature in database
GPG Key ID: 7C32FCA95C8C95D7
10 changed files with 451 additions and 350 deletions

View File

@ -21,6 +21,7 @@ use serde::Deserialize;
use tauri_utils::{
config::Config,
namespace::{MemberResolution, NamespaceLockFile},
plugin::Capability,
resources::{external_binaries, resource_relpath, ResourcePaths},
};
@ -233,6 +234,7 @@ impl WindowsAttributes {
pub struct Attributes {
#[allow(dead_code)]
windows_attributes: WindowsAttributes,
capabilities: Vec<Capability>,
}
impl Attributes {
@ -247,6 +249,19 @@ impl Attributes {
self.windows_attributes = windows_attributes;
self
}
/// Appends a capability JSON. See [`Capability`].
#[must_use]
pub fn capability(mut self, capability: impl AsRef<str>) -> Self {
let capability: Capability =
serde_json::from_str(capability.as_ref()).expect("failed to deserialize capability");
assert!(
!capability.id.is_empty(),
"capability must have an identifier"
);
self.capabilities.push(capability);
self
}
}
/// Run all build time helpers for your Tauri Application.
@ -479,7 +494,20 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
}
}
let manifests = plugin::manifests();
let mut manifests = plugin::manifests();
const APP_MANIFEST_KEY: &str = "__app__";
manifests.insert(
APP_MANIFEST_KEY.into(),
tauri_utils::plugin::Manifest {
plugin: "".into(),
default_capability: None,
capabilities: attributes.capabilities,
features: Vec::new(),
scope_type: Vec::new(),
},
);
let mut resolution = HashMap::<String, MemberResolution>::new();
for namespace in &config.namespaces {
@ -496,13 +524,17 @@ pub fn try_build(attributes: Attributes) -> Result<()> {
let (plugin, capability) = manifests.find_capability(capability).unwrap_or_else(|| {
panic!("could not find capability specification matching id {capability}")
});
member_resolution.commands.extend(
capability
.features
.into_iter()
.map(|f| format!("plugin:{plugin}|{f}"))
.collect::<Vec<_>>(),
);
if plugin == APP_MANIFEST_KEY {
member_resolution.commands.extend(capability.features);
} else {
member_resolution.commands.extend(
capability
.features
.into_iter()
.map(|f| format!("plugin:{plugin}|{f}"))
.collect::<Vec<_>>(),
);
}
}
}
}

View File

@ -454,7 +454,7 @@ fn runtime_authority_codegen(root: &TokenStream, lockfile: NamespaceLockFile) ->
let commands = &r.commands;
let resolution = quote!(#root::runtime_authority::MemberResolution {
member: #member.into(),
commands: vec![#(#commands)*.into()]
commands: vec![#(#commands.into(),)*]
});
quote!(authority.add_member(#resolution);)
});

View File

@ -6,7 +6,10 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{
collections::HashMap,
ops::{Deref, DerefMut},
};
const DEFAULT_CAPABILITY_ID: &str = "default";
@ -34,6 +37,12 @@ pub struct Capability {
/// The identifier of the capability. Must be unique.
#[serde(default)]
pub id: String,
/// The component this capability refers to.
///
/// Currently the possible values are plugin names.
///
/// When no value is set, it referes to the application itself.
pub component: Option<String>,
/// Describes the capability in a human readable format.
pub description: String,
/// List of features enabled by this capability.
@ -48,6 +57,7 @@ pub struct Capability {
#[derive(Debug, Serialize, Deserialize)]
pub struct Manifest {
/// Plugin name.
#[serde(skip_serializing_if = "String::is_empty", default)]
pub plugin: String,
/// Default capability.
pub default_capability: Option<Capability>,
@ -77,7 +87,7 @@ impl Manifest {
.expect("failed to deserialize default capability");
assert!(
capability.id.is_empty(),
"default capability cannot have an specific identifier"
"default capability cannot have an identifier"
);
capability.id = DEFAULT_CAPABILITY_ID.into();
self.default_capability.replace(capability);
@ -90,7 +100,7 @@ impl Manifest {
serde_json::from_str(capability.as_ref()).expect("failed to deserialize default capability");
assert!(
!capability.id.is_empty(),
"capability must have an specific identifier"
"capability must have an identifier"
);
self.capabilities.push(capability);
self
@ -121,6 +131,20 @@ impl Manifest {
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ManifestMap(HashMap<String, Manifest>);
impl Deref for ManifestMap {
type Target = HashMap<String, Manifest>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ManifestMap {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<HashMap<String, Manifest>> for ManifestMap {
fn from(value: HashMap<String, Manifest>) -> Self {
Self(value)

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@ tauri-plugin-cli = { git = "https://github.com/tauri-apps/plugins-workspace", br
[patch.crates-io]
tauri = { path = "../../../core/tauri" }
tauri-build = { path = "../../../core/tauri-build" }
tao = { path = "../../../../tao" }
[patch.'https://github.com/tauri-apps/tauri']
tauri = { path = "../../../core/tauri" }

View File

@ -3,7 +3,10 @@
// SPDX-License-Identifier: MIT
fn main() {
tauri_build::build();
tauri_build::try_build(
tauri_build::Attributes::new().capability(include_str!("./capabilities/allow-commands.json")),
)
.expect("failed to run tauri-build");
let mut codegen = tauri_build::CodegenContext::new();
if !cfg!(feature = "custom-protocol") {

View File

@ -0,0 +1,8 @@
{
"id": "allow-all-api-commands",
"description": "Allows all application defined commands",
"features": [
"log_operation",
"perform_request"
]
}

View File

@ -111,6 +111,6 @@
"id": "main",
"description": "Main window namespace",
"members": ["main"],
"capabilities": ["allow-ping"]
"capabilities": ["allow-all-api-commands", "allow-ping"]
}]
}

View File

@ -8,15 +8,37 @@
"main"
],
"capabilities": [
"allow-all-api-commands",
"allow-ping"
]
}
],
"plugins": {
"__app__": {
"default_capability": null,
"capabilities": [
{
"id": "allow-all-api-commands",
"component": null,
"description": "Allows all application defined commands",
"features": [
"log_operation",
"perform_request"
],
"scope": {
"allowed": [],
"blocked": []
}
}
],
"features": [],
"scope_type": []
},
"sample": {
"plugin": "sample",
"default_capability": {
"id": "default",
"component": null,
"description": "Default empty capability set",
"features": [],
"scope": {
@ -27,6 +49,7 @@
"capabilities": [
{
"id": "allow-ping",
"component": null,
"description": "Allows the ping command",
"features": [
"ping"
@ -49,6 +72,8 @@
{
"member": "main",
"commands": [
"log_operation",
"perform_request",
"plugin:sample|ping"
]
}

File diff suppressed because one or more lines are too long