From ed0303806dadfbd6fac90ffacadb457ed0a07f48 Mon Sep 17 00:00:00 2001 From: ByteAtATime Date: Sat, 12 Jul 2025 18:42:36 -0700 Subject: [PATCH] feat: use linux capabilities to set up file permissions --- src-tauri/Cargo.lock | 11 +++++++++++ src-tauri/Cargo.toml | 1 + src-tauri/src/capabilities/linux.rs | 17 +++++++++++++++++ src-tauri/src/capabilities/mod.rs | 2 ++ src-tauri/src/lib.rs | 1 + src-tauri/src/snippets/input_manager.rs | 20 ++++++++++++++++++-- 6 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src-tauri/src/capabilities/linux.rs create mode 100644 src-tauri/src/capabilities/mod.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c2db08b..8138b84 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -649,6 +649,16 @@ dependencies = [ "serde", ] +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror 1.0.69", +] + [[package]] name = "cargo-platform" version = "0.1.9" @@ -4603,6 +4613,7 @@ dependencies = [ "arboard", "bincode", "bytes", + "caps", "chrono", "enigo 0.5.0", "evdev", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index eaf5109..de46e8c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -64,6 +64,7 @@ notify = "6.1.1" notify-debouncer-full = "0.3.1" percent-encoding = "2.3.1" tauri-plugin-os = "2" +caps = "0.5.5" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-global-shortcut = "2" diff --git a/src-tauri/src/capabilities/linux.rs b/src-tauri/src/capabilities/linux.rs new file mode 100644 index 0000000..d21d4cb --- /dev/null +++ b/src-tauri/src/capabilities/linux.rs @@ -0,0 +1,17 @@ +use anyhow::Result; +use caps::{CapSet, Capability}; + +pub fn grant_capability() -> Result<()> { + caps::raise(None, CapSet::Effective, Capability::CAP_DAC_OVERRIDE)?; + Ok(()) +} + +pub fn revoke_capability() -> Result<()> { + caps::clear(None, CapSet::Effective)?; + caps::clear(None, CapSet::Permitted)?; + Ok(()) +} + +pub fn can_use_capability() -> bool { + caps::has_cap(None, CapSet::Permitted, Capability::CAP_DAC_OVERRIDE).unwrap_or(false) +} diff --git a/src-tauri/src/capabilities/mod.rs b/src-tauri/src/capabilities/mod.rs new file mode 100644 index 0000000..8daba25 --- /dev/null +++ b/src-tauri/src/capabilities/mod.rs @@ -0,0 +1,2 @@ +#[cfg(target_os = "linux")] +pub mod linux; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 139350c..9d71a5e 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -2,6 +2,7 @@ mod ai; mod app; mod browser_extension; mod cache; +mod capabilities; mod clipboard; pub mod clipboard_history; mod desktop; diff --git a/src-tauri/src/snippets/input_manager.rs b/src-tauri/src/snippets/input_manager.rs index 1089e13..076916d 100644 --- a/src-tauri/src/snippets/input_manager.rs +++ b/src-tauri/src/snippets/input_manager.rs @@ -9,6 +9,8 @@ use std::sync::{atomic::Ordering, Arc, Mutex}; use std::thread; use std::time::Duration; +#[cfg(target_os = "linux")] +use crate::capabilities; #[cfg(target_os = "linux")] use evdev::{uinput::VirtualDevice, KeyCode}; #[cfg(target_os = "linux")] @@ -305,8 +307,22 @@ impl EvdevInputManager { #[cfg(target_os = "linux")] impl InputManager for EvdevInputManager { fn start_listening(&self, callback: Box) -> Result<()> { - let devices = evdev::enumerate() - .map(|t| t.1) + let has_granted_capabilities = if capabilities::linux::can_use_capability() { + capabilities::linux::grant_capability().is_ok() + } else { + false + }; + + let devices: Vec<_> = evdev::enumerate().map(|(_, device)| device).collect(); + + if has_granted_capabilities { + if let Err(e) = capabilities::linux::revoke_capability() { + eprintln!("[Warning] Could not revoke capabilities: {}", e); + } + } + + let devices = devices + .into_iter() .filter(|d| { d.supported_keys() .map_or(false, |keys| keys.contains(evdev::KeyCode::KEY_ENTER))