use std::path::PathBuf;
use clap::Parser;
use crate::{
acl::FileFormat,
error::{Context, ErrorExt},
helpers::{app_paths::resolve_tauri_dir, prompts},
Result,
};
use tauri_utils::acl::{manifest::PermissionFile, Commands, Permission};
#[derive(Debug, Parser)]
#[clap(about = "Create a new permission file")]
pub struct Options {
identifier: Option<String>,
#[clap(long)]
description: Option<String>,
#[clap(short, long, value_delimiter = ',')]
allow: Option<Vec<String>>,
#[clap(short, long, value_delimiter = ',')]
deny: Option<Vec<String>>,
#[clap(long, default_value_t = FileFormat::Json)]
format: FileFormat,
#[clap(short, long)]
out: Option<PathBuf>,
}
pub fn command(options: Options) -> Result<()> {
let identifier = match options.identifier {
Some(i) => i,
None => prompts::input("What's the permission identifier?", None, false, false)?.unwrap(),
};
let description = match options.description {
Some(d) => Some(d),
None => prompts::input::<String>("What's the permission description?", None, false, true)?
.and_then(|d| if d.is_empty() { None } else { Some(d) }),
};
let allow: Vec<String> = options
.allow
.map(FromIterator::from_iter)
.unwrap_or_default();
let deny: Vec<String> = options
.deny
.map(FromIterator::from_iter)
.unwrap_or_default();
let permission = Permission {
version: None,
identifier,
description,
commands: Commands { allow, deny },
scope: Default::default(),
platforms: Default::default(),
};
let path = match options.out {
Some(o) => o
.canonicalize()
.fs_context("failed to canonicalize permission file path", o.clone())?,
None => {
let dir = match resolve_tauri_dir() {
Some(t) => t,
None => std::env::current_dir().context("failed to resolve current directory")?,
};
let permissions_dir = dir.join("permissions");
permissions_dir.join(format!(
"{}.{}",
permission.identifier,
options.format.extension()
))
}
};
if path.exists() {
let msg = format!(
"Permission already exists at {}",
dunce::simplified(&path).display()
);
let overwrite = prompts::confirm(&format!("{msg}, overwrite?"), Some(false))?;
if overwrite {
std::fs::remove_file(&path).fs_context("failed to remove permission file", path.clone())?;
} else {
crate::error::bail!(msg);
}
}
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).fs_context(
"failed to create permission directory",
parent.to_path_buf(),
)?;
}
std::fs::write(
&path,
options
.format
.serialize(&PermissionFile {
default: None,
set: Vec::new(),
permission: vec![permission],
})
.context("failed to serialize permission")?,
)
.fs_context("failed to write permission file", path.clone())?;
log::info!(action = "Created"; "permission at {}", dunce::simplified(&path).display());
Ok(())
}