feat: use linux capabilities to set up file permissions

This commit is contained in:
ByteAtATime 2025-07-12 18:42:36 -07:00
parent 7b2720b8c2
commit ed0303806d
No known key found for this signature in database
6 changed files with 50 additions and 2 deletions

11
src-tauri/Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -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)
}

View file

@ -0,0 +1,2 @@
#[cfg(target_os = "linux")]
pub mod linux;

View file

@ -2,6 +2,7 @@ mod ai;
mod app;
mod browser_extension;
mod cache;
mod capabilities;
mod clipboard;
pub mod clipboard_history;
mod desktop;

View file

@ -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<dyn Fn(InputEvent) + Send + Sync>) -> 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))