Skip to content

Commit

Permalink
Rework permissions. Better validation. Remove ffi and high_resolution…
Browse files Browse the repository at this point in the history
…_time
  • Loading branch information
Exidex committed Sep 21, 2024
1 parent 007a6aa commit 079386c
Show file tree
Hide file tree
Showing 10 changed files with 404 additions and 132 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion dev_plugin/gauntlet.toml
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,12 @@ environment = ["RUST_LOG"]
system = ["systemMemoryInfo"]
network = ["upload.wikimedia.org", "api.github.com"]
clipboard = ["read", "write", "clear"]
main_search_bar = ["read"]
main_search_bar = ["read"]

[permissions.filesystem]
read = ["C:\\ProgramFiles", "C:/ProgramFiles", "/home/exidex"]
write = ["/home/exidex/.test"]

[permissions.exec]
command = ["ls"]
executable = ["/usr/bin/ls"]
1 change: 1 addition & 0 deletions rust/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ arboard = "3.4.0"
global-hotkey = "0.4.2"
ureq = "2.10.0"
bytes = "1.6.0"
typed-path = "0.9"

scenario_runner = { path = "../scenario_runner", optional = true }
itertools = "0.10.5"
Expand Down
27 changes: 19 additions & 8 deletions rust/server/src/plugins/data_db_repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use sqlx::{Error, Executor, Pool, Row, Sqlite, SqlitePool};
use sqlx::migrate::Migrator;
use sqlx::sqlite::SqliteConnectOptions;
use sqlx::types::Json;
use typed_path::TypedPathBuf;
use uuid::Uuid;
use common::model::{PhysicalKey, PhysicalShortcut};
use common::dirs::Dirs;
Expand Down Expand Up @@ -117,17 +118,11 @@ pub struct DbPluginPermissions {
#[serde(default)]
pub environment: Vec<String>,
#[serde(default)]
pub high_resolution_time: bool,
#[serde(default)]
pub network: Vec<String>,
#[serde(default)]
pub ffi: Vec<PathBuf>,
#[serde(default)]
pub fs_read_access: Vec<PathBuf>,
#[serde(default)]
pub fs_write_access: Vec<PathBuf>,
pub filesystem: DbPluginPermissionsFileSystem,
#[serde(default)]
pub run_subprocess: Vec<String>,
pub exec: DbPluginPermissionsExec,
#[serde(default)]
pub system: Vec<String>,
#[serde(default)]
Expand All @@ -136,6 +131,22 @@ pub struct DbPluginPermissions {
pub main_search_bar: Vec<DbPluginMainSearchBarPermissions>,
}

#[derive(Debug, Deserialize, Serialize, Default)]
pub struct DbPluginPermissionsFileSystem {
#[serde(default)]
pub read: Vec<String>,
#[serde(default)]
pub write: Vec<String>,
}

#[derive(Debug, Deserialize, Serialize, Default)]
pub struct DbPluginPermissionsExec {
#[serde(default)]
pub command: Vec<String>,
#[serde(default)]
pub executable: Vec<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub enum DbPluginClipboardPermissions {
#[serde(rename = "read")]
Expand Down
13 changes: 7 additions & 6 deletions rust/server/src/plugins/js/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use deno_core::{op, OpState};
use image::RgbaImage;
use serde::{Deserialize, Serialize};
use tokio::task::spawn_blocking;
use crate::plugins::js::{PluginClipboardPermissions, PluginData};
use crate::plugins::js::permissions::PluginPermissionsClipboard;
use crate::plugins::js::PluginData;

fn unknown_err_clipboard(err: arboard::Error) -> anyhow::Error {
anyhow!("UNKNOWN_ERROR: {:?}", err)
Expand Down Expand Up @@ -36,7 +37,7 @@ async fn clipboard_read(state: Rc<RefCell<OpState>>) -> anyhow::Result<Clipboard
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Read);
.contains(&PluginPermissionsClipboard::Read);

if !allow {
return Err(anyhow!("Plugin doesn't have 'read' permission for clipboard"));
Expand Down Expand Up @@ -98,7 +99,7 @@ async fn clipboard_read_text(state: Rc<RefCell<OpState>>) -> anyhow::Result<Opti
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Read);
.contains(&PluginPermissionsClipboard::Read);

if !allow {
return Err(anyhow!("Plugin doesn't have 'read' permission for clipboard"));
Expand Down Expand Up @@ -134,7 +135,7 @@ async fn clipboard_write(state: Rc<RefCell<OpState>>, data: ClipboardData) -> an
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Write);
.contains(&PluginPermissionsClipboard::Write);

if !allow {
return Err(anyhow!("Plugin doesn't have 'write' permission for clipboard"));
Expand Down Expand Up @@ -186,7 +187,7 @@ async fn clipboard_write_text(state: Rc<RefCell<OpState>>, data: String) -> anyh
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Write);
.contains(&PluginPermissionsClipboard::Write);

if !allow {
return Err(anyhow!("Plugin doesn't have 'write' permission for clipboard"));
Expand All @@ -213,7 +214,7 @@ async fn clipboard_clear(state: Rc<RefCell<OpState>>) -> anyhow::Result<()> {
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Clear);
.contains(&PluginPermissionsClipboard::Clear);

if !allow {
return Err(anyhow!("Plugin doesn't have 'clear' permission for clipboard"));
Expand Down
70 changes: 18 additions & 52 deletions rust/server/src/plugins/js/mod.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File;
use std::hash::Hash;
use std::net::SocketAddr;
use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::rc::Rc;
use std::str::FromStr;
use std::time::Duration;

use anyhow::{anyhow, Context};
use deno_core::{FastString, futures, ModuleLoader, ModuleSource, ModuleSourceFuture, ModuleType, op, OpState, ResolutionKind, serde_v8, StaticModuleLoader, v8};
use deno_core::futures::{FutureExt, Stream, StreamExt};
use deno_core::futures::executor::block_on;
use deno_core::futures::{FutureExt, Stream, StreamExt};
use deno_core::v8::{GetPropertyNamesArgs, KeyConversionMode, PropertyFilter};
use deno_core::{futures, op, serde_v8, v8, FastString, ModuleLoader, ModuleSource, ModuleSourceFuture, ModuleType, OpState, ResolutionKind, StaticModuleLoader};
use deno_runtime::BootstrapOptions;
use deno_runtime::deno_core::ModuleSpecifier;
use deno_runtime::deno_io::{Stdio, StdioPipe};
use deno_runtime::permissions::{Permissions, PermissionsContainer, PermissionsOptions};
use deno_runtime::permissions::{Descriptor, EnvDescriptor, NetDescriptor, Permissions, PermissionsContainer, PermissionsOptions, ReadDescriptor, UnaryPermission, WriteDescriptor};
use deno_runtime::worker::MainWorker;
use deno_runtime::worker::WorkerOptions;
use indexmap::IndexMap;
Expand All @@ -27,16 +30,17 @@ use tokio_util::sync::CancellationToken;
use common::dirs::Dirs;
use common::model::{EntrypointId, PhysicalKey, PluginId, SearchResultEntrypointType, UiPropertyValue, UiRenderLocation, UiWidget, UiWidgetId};
use common::rpc::frontend_api::FrontendApi;
use component_model::{Children, Component, create_component_model, Property, PropertyType, SharedType};
use component_model::{create_component_model, Children, Component, Property, PropertyType, SharedType};

use crate::model::{IntermediateUiEvent, JsUiEvent, JsUiPropertyValue, JsUiRenderLocation, JsUiRequestData, JsUiResponseData, JsUiWidget, PreferenceUserData};
use crate::plugins::applications::{DesktopEntry, get_apps};
use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_from_str, DbPluginEntrypointType, DbPluginPreference, DbPluginPreferenceUserData, DbReadPlugin, DbReadPluginEntrypoint, DbPluginClipboardPermissions};
use crate::plugins::applications::{get_apps, DesktopEntry};
use crate::plugins::data_db_repository::{db_entrypoint_from_str, DataDbRepository, DbPluginClipboardPermissions, DbPluginEntrypointType, DbPluginPreference, DbPluginPreferenceUserData, DbReadPlugin, DbReadPluginEntrypoint};
use crate::plugins::icon_cache::IconCache;
use crate::plugins::js::assets::{asset_data, asset_data_blocking};
use crate::plugins::js::clipboard::{clipboard_clear, clipboard_read, clipboard_read_text, clipboard_write, clipboard_write_text};
use crate::plugins::js::command_generators::get_command_generator_entrypoint_ids;
use crate::plugins::js::logs::{op_log_debug, op_log_error, op_log_info, op_log_trace, op_log_warn};
use crate::plugins::js::permissions::{permissions_to_deno, PluginPermissions, PluginPermissionsClipboard};
use crate::plugins::js::plugins::applications::{list_applications, open_application};
use crate::plugins::js::plugins::numbat::{run_numbat, NumbatContext};
use crate::plugins::js::plugins::settings::open_settings;
Expand All @@ -54,6 +58,7 @@ mod preferences;
mod search;
mod command_generators;
mod clipboard;
pub mod permissions;

pub struct PluginRuntimeData {
pub id: PluginId,
Expand All @@ -73,37 +78,11 @@ pub struct PluginCode {
pub js: HashMap<String, String>,
}

pub struct PluginPermissions {
pub environment: Vec<String>,
pub high_resolution_time: bool,
pub network: Vec<String>,
pub ffi: Vec<PathBuf>,
pub fs_read_access: Vec<PathBuf>,
pub fs_write_access: Vec<PathBuf>,
pub run_subprocess: Vec<String>,
pub system: Vec<String>,
pub clipboard: Vec<PluginClipboardPermissions>,
pub main_search_bar: Vec<PluginMainSearchBarPermissions>,
}

#[derive(Clone, Debug)]
pub struct PluginRuntimePermissions {
pub clipboard: Vec<PluginClipboardPermissions>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PluginClipboardPermissions {
Read,
Write,
Clear
pub clipboard: Vec<PluginPermissionsClipboard>,
}

#[derive(Clone, Debug)]
pub enum PluginMainSearchBarPermissions {
Read,
}


#[derive(Clone, Debug)]
pub enum PluginCommand {
One {
Expand Down Expand Up @@ -306,25 +285,6 @@ async fn start_js_runtime(
icon_cache: IconCache,
dirs: Dirs,
) -> anyhow::Result<()> {
let permissions_container = PermissionsContainer::new(Permissions::from_options(&PermissionsOptions {
allow_env: if permissions.environment.is_empty() { None } else { Some(permissions.environment) },
deny_env: None,
allow_hrtime: permissions.high_resolution_time,
deny_hrtime: false,
allow_net: if permissions.network.is_empty() { None } else { Some(permissions.network) },
deny_net: None,
allow_ffi: if permissions.ffi.is_empty() { None } else { Some(permissions.ffi) },
deny_ffi: None,
allow_read: if permissions.fs_read_access.is_empty() { None } else { Some(permissions.fs_read_access) },
deny_read: None,
allow_run: if permissions.run_subprocess.is_empty() { None } else { Some(permissions.run_subprocess) },
deny_run: None,
allow_sys: if permissions.system.is_empty() { None } else { Some(permissions.system) },
deny_sys: None,
allow_write: if permissions.fs_write_access.is_empty() { None } else { Some(permissions.fs_write_access) },
deny_write: None,
prompt: false,
})?);

let dev_plugin = plugin_id.to_string().starts_with("file://");

Expand Down Expand Up @@ -360,6 +320,8 @@ async fn start_js_runtime(
None
};

let permissions_container = permissions_to_deno(&permissions);

let runtime_permissions = PluginRuntimePermissions {
clipboard: permissions.clipboard,
};
Expand All @@ -368,6 +330,10 @@ async fn start_js_runtime(
unused_url,
permissions_container,
WorkerOptions {
bootstrap: BootstrapOptions {
is_tty: false,
..Default::default()
},
module_loader: Rc::new(CustomModuleLoader::new(code, dev_plugin)),
extensions: vec![plugin_ext::init_ops_and_esm(
EventReceiver::new(event_stream),
Expand Down
Loading

0 comments on commit 079386c

Please sign in to comment.