mirror of https://github.com/tauri-apps/tauri
feat: Add option to generate default permissions for inlined plugins (#10559)
* feat: Add option to allow all commands by default * option to use a list of permissions, move logic to tauri-build * fix plugin * add utils change file --------- Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
parent
213c0b1b8e
commit
0bb7b0f352
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"tauri-build": patch:feat
|
||||||
|
---
|
||||||
|
|
||||||
|
Added `InlinedPlugin::default_permission` to autogenerate the default permission of an inlined plugin.
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"tauri-utils": patch:enhance
|
||||||
|
---
|
||||||
|
|
||||||
|
Return autogenerated permissions from `autogenerate_command_permissions`.
|
|
@ -42,6 +42,19 @@ const ACL_MANIFESTS_FILE_NAME: &str = "acl-manifests.json";
|
||||||
pub struct InlinedPlugin {
|
pub struct InlinedPlugin {
|
||||||
commands: &'static [&'static str],
|
commands: &'static [&'static str],
|
||||||
permissions_path_pattern: Option<&'static str>,
|
permissions_path_pattern: Option<&'static str>,
|
||||||
|
default: Option<DefaultPermissionRule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Variants of a generated default permission that can be used on an [`InlinedPlugin`].
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DefaultPermissionRule {
|
||||||
|
/// Allow all commands from [`InlinedPlugin::commands`].
|
||||||
|
AllowAllCommands,
|
||||||
|
/// Allow the given list of permissions.
|
||||||
|
///
|
||||||
|
/// Note that the list refers to permissions instead of command names,
|
||||||
|
/// so for example a command called `execute` would need to be allowed as `allow-execute`.
|
||||||
|
Allow(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlinedPlugin {
|
impl InlinedPlugin {
|
||||||
|
@ -65,6 +78,14 @@ impl InlinedPlugin {
|
||||||
self.permissions_path_pattern.replace(pattern);
|
self.permissions_path_pattern.replace(pattern);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a default permission for the plugin using the given rule.
|
||||||
|
///
|
||||||
|
/// Alternatively you can pull a permission in the filesystem in the permissions directory, see [`Self::permissions_path_pattern`].
|
||||||
|
pub fn default_permission(mut self, default: DefaultPermissionRule) -> Self {
|
||||||
|
self.default.replace(default);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tauri application permission manifest.
|
/// Tauri application permission manifest.
|
||||||
|
@ -337,12 +358,35 @@ pub fn inline_plugins(
|
||||||
let mut permission_files = if plugin.commands.is_empty() {
|
let mut permission_files = if plugin.commands.is_empty() {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
tauri_utils::acl::build::autogenerate_command_permissions(
|
let autogenerated = tauri_utils::acl::build::autogenerate_command_permissions(
|
||||||
&plugin_out_dir,
|
&plugin_out_dir,
|
||||||
plugin.commands,
|
plugin.commands,
|
||||||
"",
|
"",
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let default_permissions = plugin.default.map(|default| match default {
|
||||||
|
DefaultPermissionRule::AllowAllCommands => autogenerated.allowed,
|
||||||
|
DefaultPermissionRule::Allow(permissions) => permissions,
|
||||||
|
});
|
||||||
|
if let Some(default_permissions) = default_permissions {
|
||||||
|
let default_permission_toml = format!(
|
||||||
|
r###"# Automatically generated - DO NOT EDIT!
|
||||||
|
[default]
|
||||||
|
permissions = [{default_permissions}]
|
||||||
|
"###,
|
||||||
|
default_permissions = default_permissions
|
||||||
|
.iter()
|
||||||
|
.map(|p| format!("\"{p}\""))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",")
|
||||||
|
);
|
||||||
|
|
||||||
|
let default_permission_toml_path = plugin_out_dir.join("default.toml");
|
||||||
|
|
||||||
|
write_if_changed(&default_permission_toml, &default_permission_toml_path);
|
||||||
|
}
|
||||||
|
|
||||||
tauri_utils::acl::build::define_permissions(
|
tauri_utils::acl::build::define_permissions(
|
||||||
&plugin_out_dir.join("*").to_string_lossy(),
|
&plugin_out_dir.join("*").to_string_lossy(),
|
||||||
name,
|
name,
|
||||||
|
@ -384,6 +428,12 @@ pub fn inline_plugins(
|
||||||
Ok(acl_manifests)
|
Ok(acl_manifests)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_if_changed(content: &str, path: &Path) {
|
||||||
|
if content != read_to_string(path).unwrap_or_default() {
|
||||||
|
std::fs::write(path, content).unwrap_or_else(|_| panic!("unable to autogenerate {path:?}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn app_manifest_permissions(
|
pub fn app_manifest_permissions(
|
||||||
out_dir: &Path,
|
out_dir: &Path,
|
||||||
manifest: AppManifest,
|
manifest: AppManifest,
|
||||||
|
|
|
@ -373,6 +373,17 @@ impl Attributes {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the given list of plugins to the list of inlined plugins (a plugin that is part of your application).
|
||||||
|
///
|
||||||
|
/// See [`InlinedPlugin`] for more information.
|
||||||
|
pub fn plugins<I>(mut self, plugins: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = (&'static str, InlinedPlugin)>,
|
||||||
|
{
|
||||||
|
self.inlined_plugins.extend(plugins);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the application manifest for the Access Control List.
|
/// Sets the application manifest for the Access Control List.
|
||||||
///
|
///
|
||||||
/// See [`AppManifest`] for more information.
|
/// See [`AppManifest`] for more information.
|
||||||
|
|
|
@ -388,13 +388,21 @@ fn parse_permissions(paths: Vec<PathBuf>) -> Result<Vec<PermissionFile>, Error>
|
||||||
Ok(permissions)
|
Ok(permissions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Permissions that are generated from commands using [`autogenerate_command_permissions`].
|
||||||
|
pub struct AutogeneratedPermissions {
|
||||||
|
/// The allow permissions generated from commands.
|
||||||
|
pub allowed: Vec<String>,
|
||||||
|
/// The deny permissions generated from commands.
|
||||||
|
pub denied: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Autogenerate permission files for a list of commands.
|
/// Autogenerate permission files for a list of commands.
|
||||||
pub fn autogenerate_command_permissions(
|
pub fn autogenerate_command_permissions(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
commands: &[&str],
|
commands: &[&str],
|
||||||
license_header: &str,
|
license_header: &str,
|
||||||
schema_ref: bool,
|
schema_ref: bool,
|
||||||
) {
|
) -> AutogeneratedPermissions {
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
create_dir_all(path).expect("unable to create autogenerated commands dir");
|
create_dir_all(path).expect("unable to create autogenerated commands dir");
|
||||||
}
|
}
|
||||||
|
@ -418,8 +426,14 @@ pub fn autogenerate_command_permissions(
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut autogenerated = AutogeneratedPermissions {
|
||||||
|
allowed: Vec::new(),
|
||||||
|
denied: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
for command in commands {
|
for command in commands {
|
||||||
let slugified_command = command.replace('_', "-");
|
let slugified_command = command.replace('_', "-");
|
||||||
|
|
||||||
let toml = format!(
|
let toml = format!(
|
||||||
r###"{license_header}# Automatically generated - DO NOT EDIT!
|
r###"{license_header}# Automatically generated - DO NOT EDIT!
|
||||||
{schema_entry}
|
{schema_entry}
|
||||||
|
@ -436,9 +450,21 @@ commands.deny = ["{command}"]
|
||||||
);
|
);
|
||||||
|
|
||||||
let out_path = path.join(format!("{command}.toml"));
|
let out_path = path.join(format!("{command}.toml"));
|
||||||
if toml != read_to_string(&out_path).unwrap_or_default() {
|
write_if_changed(&toml, &out_path);
|
||||||
std::fs::write(out_path, toml)
|
|
||||||
.unwrap_or_else(|_| panic!("unable to autogenerate ${command}.toml"));
|
autogenerated
|
||||||
}
|
.allowed
|
||||||
|
.push(format!("allow-{slugified_command}"));
|
||||||
|
autogenerated
|
||||||
|
.denied
|
||||||
|
.push(format!("deny-{slugified_command}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
autogenerated
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_if_changed(content: &str, path: &Path) {
|
||||||
|
if content != read_to_string(path).unwrap_or_default() {
|
||||||
|
std::fs::write(path, content).unwrap_or_else(|_| panic!("unable to autogenerate {path:?}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue