Skip to content

Commit

Permalink
Add permissions for clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
Exidex committed Sep 14, 2024
1 parent a6e056c commit 1fe349d
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 18 deletions.
3 changes: 2 additions & 1 deletion dev_plugin/gauntlet.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,5 @@ os = 'windows'
[permissions]
environment = ["RUST_LOG"]
system = ["systemMemoryInfo"]
network = ["upload.wikimedia.org", "api.github.com"]
network = ["upload.wikimedia.org", "api.github.com"]
clipboard = ["read", "write", "clear"]
20 changes: 20 additions & 0 deletions rust/server/src/plugins/data_db_repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,34 @@ pub enum DbPluginType {

#[derive(Debug, Deserialize, Serialize)]
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>,
#[serde(default)]
pub run_subprocess: Vec<String>,
#[serde(default)]
pub system: Vec<String>,
#[serde(default)]
pub clipboard: Vec<DbPluginClipboardPermissions>,
}

#[derive(Debug, Deserialize, Serialize)]
pub enum DbPluginClipboardPermissions {
#[serde(rename = "read")]
Read,
#[serde(rename = "write")]
Write,
#[serde(rename = "clear")]
Clear
}

#[derive(Debug, Deserialize, Serialize)]
Expand Down
86 changes: 79 additions & 7 deletions rust/server/src/plugins/js/clipboard.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::cell::RefCell;
use std::io::Cursor;

use std::rc::Rc;
use anyhow::anyhow;
use arboard::ImageData;
use deno_core::op;
use deno_core::{op, OpState};
use image::RgbaImage;
use serde::{Deserialize, Serialize};
use tokio::task::spawn_blocking;
use crate::plugins::js::{PluginClipboardPermissions, PluginData};

fn unknown_err_clipboard(err: arboard::Error) -> anyhow::Error {
anyhow!("UNKNOWN_ERROR: {:?}", err)
Expand All @@ -26,7 +28,21 @@ struct ClipboardData {
}

#[op]
async fn clipboard_read() -> anyhow::Result<ClipboardData> {
async fn clipboard_read(state: Rc<RefCell<OpState>>) -> anyhow::Result<ClipboardData> {
{
let state = state.borrow();

let allow = state
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Read);

if !allow {
return Err(anyhow!("Plugin doesn't have 'read' permission for clipboard"));
}
}

spawn_blocking(|| {
let mut clipboard = arboard::Clipboard::new()
.map_err(|err| unknown_err_clipboard(err))?;
Expand Down Expand Up @@ -74,7 +90,21 @@ async fn clipboard_read() -> anyhow::Result<ClipboardData> {


#[op]
async fn clipboard_read_text() -> anyhow::Result<Option<String>> {
async fn clipboard_read_text(state: Rc<RefCell<OpState>>) -> anyhow::Result<Option<String>> {
{
let state = state.borrow();

let allow = state
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Read);

if !allow {
return Err(anyhow!("Plugin doesn't have 'read' permission for clipboard"));
}
}

spawn_blocking(|| {
let mut clipboard = arboard::Clipboard::new()
.map_err(|err| unknown_err_clipboard(err))?;
Expand All @@ -96,7 +126,21 @@ async fn clipboard_read_text() -> anyhow::Result<Option<String>> {
}

#[op]
async fn clipboard_write(data: ClipboardData) -> anyhow::Result<()> { // TODO deserialization broken, fix when migrating to deno's op2
async fn clipboard_write(state: Rc<RefCell<OpState>>, data: ClipboardData) -> anyhow::Result<()> { // TODO deserialization broken, fix when migrating to deno's op2
{
let state = state.borrow();

let allow = state
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Write);

if !allow {
return Err(anyhow!("Plugin doesn't have 'write' permission for clipboard"));
}
}

spawn_blocking(|| {
let mut clipboard = arboard::Clipboard::new()
.map_err(|err| unknown_err_clipboard(err))?;
Expand Down Expand Up @@ -134,7 +178,21 @@ async fn clipboard_write(data: ClipboardData) -> anyhow::Result<()> { // TODO de
}

#[op]
async fn clipboard_write_text(data: String) -> anyhow::Result<()> {
async fn clipboard_write_text(state: Rc<RefCell<OpState>>, data: String) -> anyhow::Result<()> {
{
let state = state.borrow();

let allow = state
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Write);

if !allow {
return Err(anyhow!("Plugin doesn't have 'write' permission for clipboard"));
}
}

spawn_blocking(|| {
let mut clipboard = arboard::Clipboard::new()
.map_err(|err| unknown_err_clipboard(err))?;
Expand All @@ -147,7 +205,21 @@ async fn clipboard_write_text(data: String) -> anyhow::Result<()> {
}

#[op]
async fn clipboard_clear() -> anyhow::Result<()> {
async fn clipboard_clear(state: Rc<RefCell<OpState>>) -> anyhow::Result<()> {
{
let state = state.borrow();

let allow = state
.borrow::<PluginData>()
.permissions()
.clipboard
.contains(&PluginClipboardPermissions::Clear);

if !allow {
return Err(anyhow!("Plugin doesn't have 'clear' permission for clipboard"));
}
}

spawn_blocking(|| {
let mut clipboard = arboard::Clipboard::new()
.map_err(|err| unknown_err_clipboard(err))?;
Expand Down
34 changes: 29 additions & 5 deletions rust/server/src/plugins/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use component_model::{Children, Component, create_component_model, Property, Pro

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};
use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_from_str, DbPluginEntrypointType, DbPluginPreference, DbPluginPreferenceUserData, DbReadPlugin, DbReadPluginEntrypoint, DbPluginClipboardPermissions};
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};
Expand Down Expand Up @@ -82,8 +82,22 @@ pub struct PluginPermissions {
pub fs_write_access: Vec<PathBuf>,
pub run_subprocess: Vec<String>,
pub system: Vec<String>,
pub clipboard: Vec<PluginClipboardPermissions>,
}

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

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PluginClipboardPermissions {
Read,
Write,
Clear
}


#[derive(Clone, Debug)]
pub enum PluginCommand {
One {
Expand Down Expand Up @@ -340,14 +354,18 @@ async fn start_js_runtime(
None
};

let runtime_permissions = PluginRuntimePermissions {
clipboard: permissions.clipboard,
};

let mut worker = MainWorker::bootstrap_from_options(
unused_url,
permissions_container,
WorkerOptions {
module_loader: Rc::new(CustomModuleLoader::new(code, dev_plugin)),
extensions: vec![plugin_ext::init_ops_and_esm(
EventReceiver::new(event_stream),
PluginData::new(plugin_id, plugin_uuid, inline_view_entrypoint_id),
PluginData::new(plugin_id, plugin_uuid, inline_view_entrypoint_id, runtime_permissions),
frontend_api,
ComponentModel::new(component_model),
repository,
Expand Down Expand Up @@ -682,15 +700,17 @@ fn from_intermediate_to_js_event(event: IntermediateUiEvent) -> JsUiEvent {
pub struct PluginData {
plugin_id: PluginId,
plugin_uuid: String,
inline_view_entrypoint_id: Option<String>
inline_view_entrypoint_id: Option<String>,
permissions: PluginRuntimePermissions
}

impl PluginData {
fn new(plugin_id: PluginId, plugin_uuid: String, inline_view_entrypoint_id: Option<String>) -> Self {
fn new(plugin_id: PluginId, plugin_uuid: String, inline_view_entrypoint_id: Option<String>, permissions: PluginRuntimePermissions) -> Self {
Self {
plugin_id,
plugin_uuid,
inline_view_entrypoint_id
inline_view_entrypoint_id,
permissions
}
}

Expand All @@ -705,6 +725,10 @@ impl PluginData {
fn inline_view_entrypoint_id(&self) -> Option<String> {
self.inline_view_entrypoint_id.clone()
}

fn permissions(&self) -> &PluginRuntimePermissions {
&self.permissions
}
}

pub struct ComponentModel {
Expand Down
27 changes: 26 additions & 1 deletion rust/server/src/plugins/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use itertools::Itertools;
use tracing_subscriber::fmt::format;
use common::model::{DownloadStatus, PluginId};
use crate::model::ActionShortcutKey;
use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_to_str, db_plugin_type_to_str, DbCode, DbPluginAction, DbPluginActionShortcutKind, DbPluginEntrypointType, DbPluginPermissions, DbPluginPreference, DbPluginPreferenceUserData, DbPluginType, DbPreferenceEnumValue, DbWritePlugin, DbWritePluginAssetData, DbWritePluginEntrypoint};
use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_to_str, db_plugin_type_to_str, DbCode, DbPluginAction, DbPluginActionShortcutKind, DbPluginEntrypointType, DbPluginPermissions, DbPluginPreference, DbPluginPreferenceUserData, DbPluginType, DbPreferenceEnumValue, DbWritePlugin, DbWritePluginAssetData, DbWritePluginEntrypoint, DbPluginClipboardPermissions};
use crate::plugins::download_status::DownloadStatusHolder;

pub struct PluginLoader {
Expand Down Expand Up @@ -321,6 +321,18 @@ impl PluginLoader {
})
.collect();

let clipboard = plugin_manifest.permissions
.clipboard
.into_iter()
.map(|permission| {
match permission {
PluginManifestClipboardPermissions::Read => DbPluginClipboardPermissions::Read,
PluginManifestClipboardPermissions::Write => DbPluginClipboardPermissions::Write,
PluginManifestClipboardPermissions::Clear => DbPluginClipboardPermissions::Clear,
}
})
.collect();

let permissions = DbPluginPermissions {
environment: plugin_manifest.permissions.environment,
high_resolution_time: plugin_manifest.permissions.high_resolution_time,
Expand All @@ -330,6 +342,7 @@ impl PluginLoader {
fs_write_access: plugin_manifest.permissions.fs_write_access,
run_subprocess: plugin_manifest.permissions.run_subprocess,
system: plugin_manifest.permissions.system,
clipboard,
};

Ok(PluginDownloadData {
Expand Down Expand Up @@ -814,4 +827,16 @@ pub struct PluginManifestPermissions {
run_subprocess: Vec<String>,
#[serde(default)]
system: Vec<String>,
#[serde(default)]
clipboard: Vec<PluginManifestClipboardPermissions>,
}

#[derive(Debug, Deserialize)]
pub enum PluginManifestClipboardPermissions {
#[serde(rename = "read")]
Read,
#[serde(rename = "write")]
Write,
#[serde(rename = "clear")]
Clear
}
18 changes: 15 additions & 3 deletions rust/server/src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use utils::channel::RequestSender;
use common::dirs::Dirs;
use crate::model::ActionShortcutKey;
use crate::plugins::config_reader::ConfigReader;
use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_from_str, DbPluginActionShortcutKind, DbPluginEntrypointType, DbPluginPreference, DbPluginPreferenceUserData, DbReadPluginEntrypoint};
use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_from_str, DbPluginActionShortcutKind, DbPluginEntrypointType, DbPluginPreference, DbPluginPreferenceUserData, DbReadPluginEntrypoint, DbPluginClipboardPermissions};
use crate::plugins::global_shortcut::{convert_physical_shortcut_to_hotkey, register_listener};
use crate::plugins::icon_cache::IconCache;
use crate::plugins::js::{AllPluginCommandData, OnePluginCommandData, PluginCode, PluginCommand, PluginPermissions, PluginRuntimeData, start_plugin_runtime};
use crate::plugins::js::{AllPluginCommandData, OnePluginCommandData, PluginCode, PluginCommand, PluginPermissions, PluginRuntimeData, start_plugin_runtime, PluginClipboardPermissions};
use crate::plugins::loader::PluginLoader;
use crate::plugins::run_status::RunStatusHolder;
use crate::search::SearchIndex;
Expand Down Expand Up @@ -553,6 +553,17 @@ impl ApplicationManager {
.await?;

let receiver = self.command_broadcaster.subscribe();

let clipboard_permissions = plugin.permissions
.clipboard
.into_iter()
.map(|permission| match permission {
DbPluginClipboardPermissions::Read => PluginClipboardPermissions::Read,
DbPluginClipboardPermissions::Write => PluginClipboardPermissions::Write,
DbPluginClipboardPermissions::Clear => PluginClipboardPermissions::Clear,
})
.collect();

let data = PluginRuntimeData {
id: plugin_id,
uuid: plugin.uuid,
Expand All @@ -566,7 +577,8 @@ impl ApplicationManager {
fs_read_access: plugin.permissions.fs_read_access,
fs_write_access: plugin.permissions.fs_write_access,
run_subprocess: plugin.permissions.run_subprocess,
system: plugin.permissions.system
system: plugin.permissions.system,
clipboard: clipboard_permissions,
},
command_receiver: receiver,
db_repository: self.db_repository.clone(),
Expand Down
2 changes: 1 addition & 1 deletion tools
Submodule tools updated 1 files
+1 −0 src/config.ts

0 comments on commit 1fe349d

Please sign in to comment.