refactor(core): simplify shell scope, input only string arrays (#3372)

This commit is contained in:
Lucas Fernandes Nogueira 2022-02-09 13:44:52 -03:00 committed by GitHub
parent 55726f236c
commit 7aca0a6233
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 72 deletions

View File

@ -376,25 +376,22 @@ fn get_allowed_clis(root: &TokenStream, scope: &ShellAllowlistScope) -> TokenStr
ShellAllowedArg::Fixed(fixed) => {
quote!(#root::scope::ShellScopeAllowedArg::Fixed(#fixed.into()))
}
ShellAllowedArg::Var { name, validate } => {
let validate = match validate {
None => quote!(::std::option::Option::None),
Some(regex) => match regex::Regex::new(regex) {
Ok(regex) => {
let regex = regex.as_str();
quote!(::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap()))
}
Err(error) => {
let error = error.to_string();
quote!({
compile_error!(#error);
::std::option::Option::Some(#root::regex::Regex::new(#regex).unwrap())
})
}
},
ShellAllowedArg::Var { validator } => {
let validator = match regex::Regex::new(validator) {
Ok(regex) => {
let regex = regex.as_str();
quote!(#root::regex::Regex::new(#regex).unwrap())
}
Err(error) => {
let error = error.to_string();
quote!({
compile_error!(#error);
#root::regex::Regex::new(#validator).unwrap()
})
}
};
quote!(#root::scope::ShellScopeAllowedArg::Var { name: #name.into(), validate: #validate })
quote!(#root::scope::ShellScopeAllowedArg::Var { validator: #validator })
}
_ => panic!("unknown shell scope arg, unable to prepare"),
});

View File

@ -930,19 +930,14 @@ pub enum ShellAllowedArg {
/// A variable that is set while calling the command from the webview API.
///
Var {
/// The name of the variable to be passed in.
/// [regex] validator to require passed values to conform to an expected input.
///
/// This will try to match the key of the passed arguments object from the webview API.
name: String,
/// Optional [regex] validator to require passed values to conform to an expected input.
///
/// This will require the argument value passed to this variable to match the `validate` regex
/// This will require the argument value passed to this variable to match the `validator` regex
/// before it will be executed.
///
/// [regex]: https://docs.rs/regex/latest/regex/#syntax
#[serde(default)]
validate: Option<String>,
validator: String,
},
}
@ -2427,10 +2422,9 @@ mod build {
let fixed = str_lit(fixed);
quote!(#prefix::Fixed(#fixed))
}
Self::Var { name, validate } => {
let name = str_lit(name);
let validate = opt_str_lit(validate.as_ref());
quote!(#prefix::Var { name: #name, validate: #validate })
Self::Var { validator } => {
let validator = str_lit(validator);
quote!(#prefix::Var { validator: #validator })
}
})
}

File diff suppressed because one or more lines are too long

View File

@ -135,7 +135,11 @@ impl Cmd {
.prepare(&program, args, false)
{
Ok(cmd) => cmd,
Err(_) => return Err(crate::Error::ProgramNotAllowed(PathBuf::from(program))),
Err(e) => {
#[cfg(debug_assertions)]
eprintln!("{}", e);
return Err(crate::Error::ProgramNotAllowed(PathBuf::from(program)));
}
}
};
#[cfg(any(shell_execute, shell_sidecar))]

View File

@ -24,9 +24,6 @@ pub enum ExecuteArgs {
/// Multiple string arguments
List(Vec<String>),
/// Multiple string arguments in a key-value fashion
Map(HashMap<String, String>),
}
impl ExecuteArgs {
@ -36,7 +33,6 @@ impl ExecuteArgs {
Self::None => true,
Self::Single(s) if s.is_empty() => true,
Self::List(l) => l.is_empty(),
Self::Map(m) => m.is_empty(),
_ => false,
}
}
@ -60,12 +56,6 @@ impl From<Vec<String>> for ExecuteArgs {
}
}
impl From<HashMap<String, String>> for ExecuteArgs {
fn from(map: HashMap<String, String>) -> Self {
Self::Map(map)
}
}
/// Shell scope configuration.
#[derive(Debug, Clone)]
pub struct ScopeConfig {
@ -95,13 +85,10 @@ pub enum ScopeAllowedArg {
/// A non-configurable argument.
Fixed(String),
/// An argument with a value to be evaluated at runtime, optionally must pass a regex validation.
/// An argument with a value to be evaluated at runtime, must pass a regex validation.
Var {
/// The key name of the argument variable
name: String,
/// The validation, if set, that the variable value must pass in order to be called.
validate: Option<Regex>,
/// The validation that the variable value must pass in order to be called.
validator: Regex,
},
}
@ -157,13 +144,15 @@ pub enum ScopeError {
NotFound(String),
/// A command variable has no value set in the arguments.
#[error("Scoped command argument {0} was not found")]
#[error(
"Scoped command argument at position {0} must match regex validation {1} but it was not found"
)]
#[cfg(any(shell_execute, shell_sidecar))]
#[cfg_attr(
doc_cfg,
doc(cfg(any(feature = "shell-execute", feature = "shell-sidecar")))
)]
MissingVar(String),
MissingVar(usize, String),
/// At least one argument did not pass input validation.
#[cfg(shell_scope)]
@ -171,10 +160,10 @@ pub enum ScopeError {
doc_cfg,
doc(cfg(any(feature = "shell-execute", feature = "shell-open")))
)]
#[error("Scoped command argument {var} was found, but failed regex validation {validation}")]
#[error("Scoped command argument at position {index} was found, but failed regex validation {validation}")]
Validation {
/// Name of the variable.
var: String,
/// Index of the variable.
index: usize,
/// Regex that the variable value failed to match.
validation: String,
@ -229,28 +218,23 @@ impl Scope {
(None, ExecuteArgs::None) => Ok(vec![]),
(None, ExecuteArgs::List(list)) => Ok(list),
(None, ExecuteArgs::Single(string)) => Ok(vec![string]),
(None, _) => Err(ScopeError::InvalidInput(command_name.into())),
(Some(list), ExecuteArgs::Map(args)) => list
(Some(list), ExecuteArgs::List(args)) => list
.iter()
.map(|arg| match arg {
.enumerate()
.map(|(i, arg)| match arg {
ScopeAllowedArg::Fixed(fixed) => Ok(fixed.to_string()),
ScopeAllowedArg::Var { name, validate } => {
ScopeAllowedArg::Var { validator } => {
let value = args
.get(name)
.ok_or_else(|| ScopeError::MissingVar(name.into()))?
.get(i)
.ok_or_else(|| ScopeError::MissingVar(i, validator.to_string()))?
.to_string();
match validate {
None => Ok(value),
Some(regex) => {
if regex.is_match(&value) {
Ok(value)
} else {
Err(ScopeError::Validation {
var: name.into(),
validation: regex.as_str().into(),
})
}
}
if validator.is_match(&value) {
Ok(value)
} else {
Err(ScopeError::Validation {
index: i,
validation: validator.to_string(),
})
}
}
})
@ -286,7 +270,7 @@ impl Scope {
if let Some(regex) = &self.0.open {
if !regex.is_match(path) {
return Err(ScopeError::Validation {
var: "open".into(),
index: 0,
validation: regex.as_str().into(),
});
}

View File

@ -65,7 +65,7 @@ interface ChildProcess {
async function execute(
onEvent: (event: CommandEvent) => void,
program: string,
args?: string | string[] | { [key: string]: string },
args: string | string[] = [],
options?: InternalSpawnOptions
): Promise<number> {
if (typeof args === 'object') {