// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT use clap::Parser; use crate::{ Result, error::{Context, ErrorExt}, }; use colored::Colorize; use tauri_utils::acl::{APP_ACL_KEY, manifest::Manifest}; use std::{collections::BTreeMap, fs::read_to_string}; #[derive(Debug, Parser)] #[clap(about = "List permissions available to your application")] pub struct Options { /// Name of the plugin to list permissions. plugin: Option, /// Permission identifier filter. #[clap(short, long)] filter: Option, } pub fn command(options: Options) -> Result<()> { let dirs = crate::helpers::app_paths::resolve_dirs(); let acl_manifests_path = dirs .tauri .join("gen") .join("schemas") .join("acl-manifests.json"); if acl_manifests_path.exists() { let plugin_manifest_json = read_to_string(&acl_manifests_path) .fs_context("failed to read plugin manifest", acl_manifests_path)?; let acl = serde_json::from_str::>(&plugin_manifest_json) .context("failed to parse plugin manifest as JSON")?; for (key, manifest) in acl { if options .plugin .as_ref() .map(|p| p != &key) .unwrap_or_default() { continue; } let mut permissions = Vec::new(); let prefix = if key == APP_ACL_KEY { "".to_string() } else { format!("{}:", key.magenta()) }; if let Some(default) = manifest.default_permission { if options .filter .as_ref() .map(|f| "default".contains(f)) .unwrap_or(true) { permissions.push(format!( "{prefix}{}\n{}\nPermissions: {}", "default".cyan(), default.description, default .permissions .iter() .map(|c| c.cyan().to_string()) .collect::>() .join(", ") )); } } for set in manifest.permission_sets.values() { if options .filter .as_ref() .map(|f| set.identifier.contains(f)) .unwrap_or(true) { permissions.push(format!( "{prefix}{}\n{}\nPermissions: {}", set.identifier.cyan(), set.description, set .permissions .iter() .map(|c| c.cyan().to_string()) .collect::>() .join(", ") )); } } for permission in manifest.permissions.into_values() { if options .filter .as_ref() .map(|f| permission.identifier.contains(f)) .unwrap_or(true) { permissions.push(format!( "{prefix}{}{}{}{}", permission.identifier.cyan(), permission .description .map(|d| format!("\n{d}")) .unwrap_or_default(), if permission.commands.allow.is_empty() { "".to_string() } else { format!( "\n{}: {}", "Allow commands".bold(), permission .commands .allow .iter() .map(|c| c.green().to_string()) .collect::>() .join(", ") ) }, if permission.commands.deny.is_empty() { "".to_string() } else { format!( "\n{}: {}", "Deny commands".bold(), permission .commands .deny .iter() .map(|c| c.red().to_string()) .collect::>() .join(", ") ) }, )); } } if !permissions.is_empty() { println!("{}\n", permissions.join("\n\n")); } } Ok(()) } else { crate::error::bail!("permission file not found, please build your application once first") } }