feat: update to tauri beta, add permissions (#862)

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
Co-authored-by: Lucas Nogueira <lucas@crabnebula.dev>
This commit is contained in:
Tillmann
2024-02-04 03:14:41 +09:00
committed by GitHub
parent 506ce4835b
commit d198c01486
387 changed files with 21883 additions and 943 deletions
+82 -48
View File
@@ -4,11 +4,10 @@
use crate::open::Program;
use crate::process::Command;
use crate::{Manager, Runtime};
use regex::Regex;
use std::collections::HashMap;
use tauri::ipc::ScopeObject;
use tauri::Manager;
/// Allowed representation of `Execute` command arguments.
#[derive(Debug, Clone, serde::Deserialize)]
@@ -55,19 +54,12 @@ impl From<Vec<String>> for ExecuteArgs {
}
}
/// Shell scope configuration.
#[derive(Debug, Clone)]
pub struct ScopeConfig {
/// The validation regex that `shell > open` paths must match against.
pub open: Option<Regex>,
/// All allowed commands, using their unique command name as the keys.
pub scopes: HashMap<String, ScopeAllowedCommand>,
}
/// A configured scoped shell command.
#[derive(Debug, Clone)]
pub struct ScopeAllowedCommand {
/// Name of the command (key).
pub name: String,
/// The shell command to be called.
pub command: std::path::PathBuf,
@@ -78,6 +70,47 @@ pub struct ScopeAllowedCommand {
pub sidecar: bool,
}
impl ScopeObject for ScopeAllowedCommand {
type Error = crate::Error;
fn deserialize<R: tauri::Runtime>(
app: &tauri::AppHandle<R>,
raw: tauri::utils::acl::Value,
) -> Result<Self, Self::Error> {
let scope = serde_json::from_value::<crate::scope_entry::Entry>(raw.into())?;
let args = match scope.args.clone() {
crate::scope_entry::ShellAllowedArgs::Flag(true) => None,
crate::scope_entry::ShellAllowedArgs::Flag(false) => Some(Vec::new()),
crate::scope_entry::ShellAllowedArgs::List(list) => {
let list = list.into_iter().map(|arg| match arg {
crate::scope_entry::ShellAllowedArg::Fixed(fixed) => {
crate::scope::ScopeAllowedArg::Fixed(fixed)
}
crate::scope_entry::ShellAllowedArg::Var { validator } => {
let validator = Regex::new(&validator)
.unwrap_or_else(|e| panic!("invalid regex {validator}: {e}"));
crate::scope::ScopeAllowedArg::Var { validator }
}
});
Some(list.collect())
}
};
let command = if let Ok(path) = app.path().parse(&scope.command) {
path
} else {
scope.command.clone()
};
Ok(Self {
name: scope.name,
command,
args,
sidecar: scope.sidecar,
})
}
}
/// A configured argument to a scoped shell command.
#[derive(Debug, Clone)]
pub enum ScopeAllowedArg {
@@ -98,9 +131,18 @@ impl ScopeAllowedArg {
}
}
/// Scope for filesystem access.
/// Scope for the open command
pub struct OpenScope {
/// The validation regex that `shell > open` paths must match against.
pub open: Option<Regex>,
}
/// Scope for shell process spawning.
#[derive(Clone)]
pub struct Scope(ScopeConfig);
pub struct ShellScope<'a> {
/// All allowed commands, using their unique command name as the keys.
pub scopes: Vec<&'a ScopeAllowedCommand>,
}
/// All errors that can happen while validating a scoped command.
#[derive(Debug, thiserror::Error)]
@@ -147,17 +189,33 @@ pub enum Error {
Io(#[from] std::io::Error),
}
impl Scope {
/// Creates a new shell scope.
pub(crate) fn new<R: Runtime, M: Manager<R>>(manager: &M, mut scope: ScopeConfig) -> Self {
for cmd in scope.scopes.values_mut() {
if let Ok(path) = manager.path().parse(&cmd.command) {
cmd.command = path;
impl OpenScope {
/// Open a path in the default (or specified) browser.
///
/// The path is validated against the `plugins > shell > open` validation regex, which
/// defaults to `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+`.
pub fn open(&self, path: &str, with: Option<Program>) -> Result<(), Error> {
// ensure we pass validation if the configuration has one
if let Some(regex) = &self.open {
if !regex.is_match(path) {
return Err(Error::Validation {
index: 0,
validation: regex.as_str().into(),
});
}
}
Self(scope)
}
// The prevention of argument escaping is handled by the usage of std::process::Command::arg by
// the `open` dependency. This behavior should be re-confirmed during upgrades of `open`.
match with.map(Program::name) {
Some(program) => ::open::with_detached(path, program),
None => ::open::that_detached(path),
}
.map_err(Into::into)
}
}
impl<'a> ShellScope<'a> {
/// Validates argument inputs and creates a Tauri sidecar [`Command`].
pub fn prepare_sidecar(
&self,
@@ -180,7 +238,7 @@ impl Scope {
args: ExecuteArgs,
sidecar: Option<&str>,
) -> Result<Command, Error> {
let command = match self.0.scopes.get(command_name) {
let command = match self.scopes.iter().find(|s| s.name == command_name) {
Some(command) => command,
None => return Err(Error::NotFound(command_name.into())),
};
@@ -245,28 +303,4 @@ impl Scope {
Ok(command.args(args))
}
/// Open a path in the default (or specified) browser.
///
/// The path is validated against the `plugins > shell > open` validation regex, which
/// defaults to `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+`.
pub fn open(&self, path: &str, with: Option<Program>) -> Result<(), Error> {
// ensure we pass validation if the configuration has one
if let Some(regex) = &self.0.open {
if !regex.is_match(path) {
return Err(Error::Validation {
index: 0,
validation: regex.as_str().into(),
});
}
}
// The prevention of argument escaping is handled by the usage of std::process::Command::arg by
// the `open` dependency. This behavior should be re-confirmed during upgrades of `open`.
match with.map(Program::name) {
Some(program) => ::open::with_detached(path, program),
None => ::open::that_detached(path),
}
.map_err(Into::into)
}
}