feat(core): add support for linux capabilities
This commit is contained in:
		
							parent
							
								
									c381da94f9
								
							
						
					
					
						commit
						72d7c19e9f
					
				
							
								
								
									
										39
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										39
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							|  | @ -132,6 +132,17 @@ dependencies = [ | ||||||
|  "pkg-config", |  "pkg-config", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "caps" | ||||||
|  | version = "0.5.2" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c088f2dddef283f86b023ab1ebe2301c653326834996458b2f48d29b804e9540" | ||||||
|  | dependencies = [ | ||||||
|  |  "errno", | ||||||
|  |  "libc", | ||||||
|  |  "thiserror", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "cc" | name = "cc" | ||||||
| version = "1.0.66" | version = "1.0.66" | ||||||
|  | @ -412,11 +423,33 @@ dependencies = [ | ||||||
|  "syn 1.0.67", |  "syn 1.0.67", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "errno" | ||||||
|  | version = "0.2.7" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" | ||||||
|  | dependencies = [ | ||||||
|  |  "errno-dragonfly", | ||||||
|  |  "libc", | ||||||
|  |  "winapi 0.3.9", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "errno-dragonfly" | ||||||
|  | version = "0.1.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" | ||||||
|  | dependencies = [ | ||||||
|  |  "gcc", | ||||||
|  |  "libc", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "espanso" | name = "espanso" | ||||||
| version = "2.0.0" | version = "2.0.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "anyhow", |  "anyhow", | ||||||
|  |  "caps", | ||||||
|  "clap", |  "clap", | ||||||
|  "colored", |  "colored", | ||||||
|  "crossbeam", |  "crossbeam", | ||||||
|  | @ -774,6 +807,12 @@ dependencies = [ | ||||||
|  "new_debug_unreachable", |  "new_debug_unreachable", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "gcc" | ||||||
|  | version = "0.3.55" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "getrandom" | name = "getrandom" | ||||||
| version = "0.1.16" | version = "0.1.16" | ||||||
|  |  | ||||||
|  | @ -66,4 +66,7 @@ widestring = "0.4.3" | ||||||
| libc = "0.2.98" | libc = "0.2.98" | ||||||
| 
 | 
 | ||||||
| [target.'cfg(target_os="macos")'.dependencies] | [target.'cfg(target_os="macos")'.dependencies] | ||||||
| espanso-mac-utils = { path = "../espanso-mac-utils" }  | espanso-mac-utils = { path = "../espanso-mac-utils" }  | ||||||
|  | 
 | ||||||
|  | [target.'cfg(target_os="linux")'.dependencies] | ||||||
|  | caps = "0.5.2" | ||||||
							
								
								
									
										32
									
								
								espanso/src/capabilities/fallback.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								espanso/src/capabilities/fallback.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of espanso. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2019-2021 Federico Terzi | ||||||
|  |  * | ||||||
|  |  * espanso is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * espanso is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | use anyhow::Result; | ||||||
|  | 
 | ||||||
|  | pub fn can_use_capabilities() -> bool { | ||||||
|  |   false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn grant_capabilities() -> Result<()> { | ||||||
|  |   Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn clear_capabilities() -> Result<()> { | ||||||
|  |   Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								espanso/src/capabilities/linux.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								espanso/src/capabilities/linux.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of espanso. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2019-2021 Federico Terzi | ||||||
|  |  * | ||||||
|  |  * espanso is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * espanso is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  |  */ | ||||||
|  | use anyhow::Result; | ||||||
|  | use caps::{CapSet, Capability}; | ||||||
|  | use log::error; | ||||||
|  | 
 | ||||||
|  | pub fn can_use_capabilities() -> bool { | ||||||
|  |   match caps::has_cap(None, CapSet::Permitted, Capability::CAP_DAC_OVERRIDE) { | ||||||
|  |     Ok(has_cap) => has_cap, | ||||||
|  |     Err(err) => { | ||||||
|  |       error!("error while checking if capabilities are enabled: {}", err); | ||||||
|  |       false | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn grant_capabilities() -> Result<()> { | ||||||
|  |   caps::raise(None, CapSet::Effective, Capability::CAP_DAC_OVERRIDE)?; | ||||||
|  |   Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn clear_capabilities() -> Result<()> { | ||||||
|  |   caps::clear(None, CapSet::Effective)?; | ||||||
|  |   caps::clear(None, CapSet::Permitted)?; | ||||||
|  |   Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								espanso/src/capabilities/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								espanso/src/capabilities/mod.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of espanso. | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2019-2021 Federico Terzi | ||||||
|  |  * | ||||||
|  |  * espanso is free software: you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * espanso is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #[cfg(target_os = "linux")] | ||||||
|  | mod linux; | ||||||
|  | #[cfg(target_os = "linux")] | ||||||
|  | pub use linux::*; | ||||||
|  | 
 | ||||||
|  | #[cfg(not(target_os = "linux"))] | ||||||
|  | mod fallback; | ||||||
|  | #[cfg(not(target_os = "linux"))] | ||||||
|  | pub use fallback::*; | ||||||
|  | 
 | ||||||
|  | @ -42,6 +42,7 @@ pub struct CliModule { | ||||||
|   pub requires_config: bool, |   pub requires_config: bool, | ||||||
|   pub subcommand: String, |   pub subcommand: String, | ||||||
|   pub show_in_dock: bool, |   pub show_in_dock: bool, | ||||||
|  |   pub requires_linux_capabilities: bool, | ||||||
|   pub entry: fn(CliModuleArgs)->i32, |   pub entry: fn(CliModuleArgs)->i32, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -55,6 +56,7 @@ impl Default for CliModule { | ||||||
|       requires_config: false, 
 |       requires_config: false, 
 | ||||||
|       subcommand: "".to_string(), 
 |       subcommand: "".to_string(), 
 | ||||||
|       show_in_dock: false, |       show_in_dock: false, | ||||||
|  |       requires_linux_capabilities: false, | ||||||
|       entry: |_| {0}, |       entry: |_| {0}, | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -18,7 +18,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
| use espanso_detect::event::{InputEvent, KeyboardEvent, Status}; | use espanso_detect::{SourceCreationOptions, event::{InputEvent, KeyboardEvent, Status}}; | ||||||
| use log::{error}; | use log::{error}; | ||||||
| use thiserror::Error; | use thiserror::Error; | ||||||
| 
 | 
 | ||||||
|  | @ -33,8 +33,7 @@ pub mod secure_input; | ||||||
| pub mod sequencer; | pub mod sequencer; | ||||||
| pub mod ui; | pub mod ui; | ||||||
| 
 | 
 | ||||||
| // TODO: pass options
 | pub fn init_and_spawn(source_options: SourceCreationOptions) -> Result<(DetectSource, ModifierStateStore, Sequencer)> { | ||||||
| pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore, Sequencer)> { |  | ||||||
|   let (sender, receiver) = crossbeam::channel::unbounded(); |   let (sender, receiver) = crossbeam::channel::unbounded(); | ||||||
|   let (init_tx, init_rx) = crossbeam::channel::unbounded(); |   let (init_tx, init_rx) = crossbeam::channel::unbounded(); | ||||||
| 
 | 
 | ||||||
|  | @ -46,7 +45,7 @@ pub fn init_and_spawn() -> Result<(DetectSource, ModifierStateStore, Sequencer)> | ||||||
|   if let Err(error) = std::thread::Builder::new() |   if let Err(error) = std::thread::Builder::new() | ||||||
|     .name("detect thread".to_string()) |     .name("detect thread".to_string()) | ||||||
|     .spawn( |     .spawn( | ||||||
|       move || match espanso_detect::get_source(Default::default()) { |       move || match espanso_detect::get_source(source_options) { | ||||||
|         Ok(mut source) => { |         Ok(mut source) => { | ||||||
|           if source.initialize().is_err() { |           if source.initialize().is_err() { | ||||||
|             init_tx |             init_tx | ||||||
|  |  | ||||||
|  | @ -22,18 +22,39 @@ use std::thread::JoinHandle; | ||||||
| use anyhow::Result; | use anyhow::Result; | ||||||
| use crossbeam::channel::Receiver; | use crossbeam::channel::Receiver; | ||||||
| use espanso_config::{config::ConfigStore, matches::store::MatchStore}; | use espanso_config::{config::ConfigStore, matches::store::MatchStore}; | ||||||
|  | use espanso_detect::SourceCreationOptions; | ||||||
|  | use espanso_inject::InjectorCreationOptions; | ||||||
| use espanso_path::Paths; | use espanso_path::Paths; | ||||||
| use espanso_ui::{event::UIEvent, UIRemote}; | use espanso_ui::{event::UIEvent, UIRemote}; | ||||||
| use log::info; | use log::{debug, error, info, warn}; | ||||||
| 
 | 
 | ||||||
| use crate::{cli::worker::{engine::{dispatch::executor::{ | use crate::{ | ||||||
|  |   cli::worker::{ | ||||||
|  |     engine::{ | ||||||
|  |       dispatch::executor::{ | ||||||
|         clipboard_injector::ClipboardInjectorAdapter, context_menu::ContextMenuHandlerAdapter, |         clipboard_injector::ClipboardInjectorAdapter, context_menu::ContextMenuHandlerAdapter, | ||||||
|         event_injector::EventInjectorAdapter, icon::IconHandlerAdapter, |         event_injector::EventInjectorAdapter, icon::IconHandlerAdapter, | ||||||
|         key_injector::KeyInjectorAdapter, |         key_injector::KeyInjectorAdapter, | ||||||
|       }, process::middleware::{image_resolve::PathProviderAdapter, match_select::MatchSelectorAdapter, matcher::{convert::MatchConverter, regex::{RegexMatcherAdapter, RegexMatcherAdapterOptions}, rolling::{RollingMatcherAdapter, RollingMatcherAdapterOptions}}, multiplex::MultiplexAdapter, render::{ |       }, | ||||||
|  |       process::middleware::{ | ||||||
|  |         image_resolve::PathProviderAdapter, | ||||||
|  |         match_select::MatchSelectorAdapter, | ||||||
|  |         matcher::{ | ||||||
|  |           convert::MatchConverter, | ||||||
|  |           regex::{RegexMatcherAdapter, RegexMatcherAdapterOptions}, | ||||||
|  |           rolling::{RollingMatcherAdapter, RollingMatcherAdapterOptions}, | ||||||
|  |         }, | ||||||
|  |         multiplex::MultiplexAdapter, | ||||||
|  |         render::{ | ||||||
|           extension::{clipboard::ClipboardAdapter, form::FormProviderAdapter}, |           extension::{clipboard::ClipboardAdapter, form::FormProviderAdapter}, | ||||||
|           RendererAdapter, |           RendererAdapter, | ||||||
|         }}}, match_cache::MatchCache}, engine::event::ExitMode}; |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |     match_cache::MatchCache, | ||||||
|  |   }, | ||||||
|  |   engine::event::ExitMode, | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| use super::secure_input::SecureInputEvent; | use super::secure_input::SecureInputEvent; | ||||||
| 
 | 
 | ||||||
|  | @ -41,6 +62,7 @@ pub mod dispatch; | ||||||
| pub mod funnel; | pub mod funnel; | ||||||
| pub mod process; | pub mod process; | ||||||
| 
 | 
 | ||||||
|  | #[allow(clippy::too_many_arguments)] | ||||||
| pub fn initialize_and_spawn( | pub fn initialize_and_spawn( | ||||||
|   paths: Paths, |   paths: Paths, | ||||||
|   config_store: Box<dyn ConfigStore>, |   config_store: Box<dyn ConfigStore>, | ||||||
|  | @ -49,6 +71,7 @@ pub fn initialize_and_spawn( | ||||||
|   exit_signal: Receiver<ExitMode>, |   exit_signal: Receiver<ExitMode>, | ||||||
|   ui_event_receiver: Receiver<UIEvent>, |   ui_event_receiver: Receiver<UIEvent>, | ||||||
|   secure_input_receiver: Receiver<SecureInputEvent>, |   secure_input_receiver: Receiver<SecureInputEvent>, | ||||||
|  |   use_evdev_backend: bool, | ||||||
| ) -> Result<JoinHandle<ExitMode>> { | ) -> Result<JoinHandle<ExitMode>> { | ||||||
|   let handle = std::thread::Builder::new() |   let handle = std::thread::Builder::new() | ||||||
|     .name("engine thread".to_string()) |     .name("engine thread".to_string()) | ||||||
|  | @ -66,18 +89,35 @@ pub fn initialize_and_spawn( | ||||||
|       let modulo_form_ui = crate::gui::modulo::form::ModuloFormUI::new(&modulo_manager); |       let modulo_form_ui = crate::gui::modulo::form::ModuloFormUI::new(&modulo_manager); | ||||||
|       let modulo_search_ui = crate::gui::modulo::search::ModuloSearchUI::new(&modulo_manager); |       let modulo_search_ui = crate::gui::modulo::search::ModuloSearchUI::new(&modulo_manager); | ||||||
| 
 | 
 | ||||||
|  |       let has_granted_capabilities = grant_linux_capabilities(use_evdev_backend); | ||||||
|  | 
 | ||||||
|  |       // TODO: pass all the options
 | ||||||
|       let (detect_source, modifier_state_store, sequencer) = |       let (detect_source, modifier_state_store, sequencer) = | ||||||
|         super::engine::funnel::init_and_spawn().expect("failed to initialize detector module"); |         super::engine::funnel::init_and_spawn(SourceCreationOptions { | ||||||
|  |           use_evdev: use_evdev_backend, | ||||||
|  |           ..Default::default() | ||||||
|  |         }) | ||||||
|  |         .expect("failed to initialize detector module"); | ||||||
|       let exit_source = super::engine::funnel::exit::ExitSource::new(exit_signal, &sequencer); |       let exit_source = super::engine::funnel::exit::ExitSource::new(exit_signal, &sequencer); | ||||||
|       let ui_source = super::engine::funnel::ui::UISource::new(ui_event_receiver, &sequencer); |       let ui_source = super::engine::funnel::ui::UISource::new(ui_event_receiver, &sequencer); | ||||||
|       let secure_input_source = super::engine::funnel::secure_input::SecureInputSource::new(secure_input_receiver, &sequencer); |       let secure_input_source = super::engine::funnel::secure_input::SecureInputSource::new( | ||||||
|       let sources: Vec<&dyn crate::engine::funnel::Source> = |         secure_input_receiver, | ||||||
|         vec![&detect_source, &exit_source, &ui_source, &secure_input_source]; |         &sequencer, | ||||||
|  |       ); | ||||||
|  |       let sources: Vec<&dyn crate::engine::funnel::Source> = vec![ | ||||||
|  |         &detect_source, | ||||||
|  |         &exit_source, | ||||||
|  |         &ui_source, | ||||||
|  |         &secure_input_source, | ||||||
|  |       ]; | ||||||
|       let funnel = crate::engine::funnel::default(&sources); |       let funnel = crate::engine::funnel::default(&sources); | ||||||
| 
 | 
 | ||||||
|       let rolling_matcher = RollingMatcherAdapter::new(&match_converter.get_rolling_matches(), RollingMatcherAdapterOptions { |       let rolling_matcher = RollingMatcherAdapter::new( | ||||||
|         char_word_separators: config_manager.default().word_separators(), |         &match_converter.get_rolling_matches(), | ||||||
|       }); |         RollingMatcherAdapterOptions { | ||||||
|  |           char_word_separators: config_manager.default().word_separators(), | ||||||
|  |         }, | ||||||
|  |       ); | ||||||
|       let regex_matcher = RegexMatcherAdapter::new( |       let regex_matcher = RegexMatcherAdapter::new( | ||||||
|         &match_converter.get_regex_matches(), |         &match_converter.get_regex_matches(), | ||||||
|         &RegexMatcherAdapterOptions { |         &RegexMatcherAdapterOptions { | ||||||
|  | @ -92,8 +132,11 @@ pub fn initialize_and_spawn( | ||||||
|       let selector = MatchSelectorAdapter::new(&modulo_search_ui, &match_cache); |       let selector = MatchSelectorAdapter::new(&modulo_search_ui, &match_cache); | ||||||
|       let multiplexer = MultiplexAdapter::new(&match_cache); |       let multiplexer = MultiplexAdapter::new(&match_cache); | ||||||
| 
 | 
 | ||||||
|       let injector = espanso_inject::get_injector(Default::default()) |       let injector = espanso_inject::get_injector(InjectorCreationOptions { | ||||||
|         .expect("failed to initialize injector module"); // TODO: handle the options
 |         use_evdev: use_evdev_backend, | ||||||
|  |         ..Default::default() | ||||||
|  |       }) | ||||||
|  |       .expect("failed to initialize injector module"); // TODO: handle the options
 | ||||||
|       let clipboard = espanso_clipboard::get_clipboard(Default::default()) |       let clipboard = espanso_clipboard::get_clipboard(Default::default()) | ||||||
|         .expect("failed to initialize clipboard module"); // TODO: handle options
 |         .expect("failed to initialize clipboard module"); // TODO: handle options
 | ||||||
| 
 | 
 | ||||||
|  | @ -161,6 +204,13 @@ pub fn initialize_and_spawn( | ||||||
|         &icon_adapter, |         &icon_adapter, | ||||||
|       ); |       ); | ||||||
| 
 | 
 | ||||||
|  |       // Disable previously granted linux capabilities if not needed anymore
 | ||||||
|  |       if has_granted_capabilities { | ||||||
|  |         if let Err(err) = crate::capabilities::clear_capabilities() { | ||||||
|  |           error!("unable to revoke linux capabilities: {}", err); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       let mut engine = crate::engine::Engine::new(&funnel, &mut processor, &dispatcher); |       let mut engine = crate::engine::Engine::new(&funnel, &mut processor, &dispatcher); | ||||||
|       let exit_mode = engine.run(); |       let exit_mode = engine.run(); | ||||||
| 
 | 
 | ||||||
|  | @ -172,3 +222,30 @@ pub fn initialize_and_spawn( | ||||||
| 
 | 
 | ||||||
|   Ok(handle) |   Ok(handle) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | fn grant_linux_capabilities(use_evdev_backend: bool) -> bool { | ||||||
|  |   if use_evdev_backend { | ||||||
|  |     if crate::capabilities::can_use_capabilities() { | ||||||
|  |       debug!("using linux capabilities to grant permissions needed by EVDEV backend"); | ||||||
|  |       if let Err(err) = crate::capabilities::grant_capabilities() { | ||||||
|  |         error!("unable to grant CAP_DAC_OVERRIDE capability: {}", err); | ||||||
|  |         false | ||||||
|  |       } else { | ||||||
|  |         debug!("successfully granted permissions using capabilities"); | ||||||
|  |         true | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       warn!("EVDEV backend is being used, but without enabling linux capabilities."); | ||||||
|  |       warn!("  Although you CAN run espanso EVDEV backend as root, it's not recommended due"); | ||||||
|  |       warn!( | ||||||
|  |         "  to security reasons. Espanso supports linux capabilities to limit the attack surface" | ||||||
|  |       ); | ||||||
|  |       warn!("  area by only leveraging on the CAP_DAC_OVERRIDE capability (needed to work with"); | ||||||
|  |       warn!("  /dev/input/* devices to detect and inject text) and disabling it as soon as the"); | ||||||
|  |       warn!("  initial setup is completed."); | ||||||
|  |       false | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     false | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ pub fn new() -> CliModule { | ||||||
|   CliModule { |   CliModule { | ||||||
|     requires_paths: true, |     requires_paths: true, | ||||||
|     requires_config: true, |     requires_config: true, | ||||||
|  |     requires_linux_capabilities: true, | ||||||
|     enable_logs: true, |     enable_logs: true, | ||||||
|     log_mode: super::LogMode::AppendOnly, |     log_mode: super::LogMode::AppendOnly, | ||||||
|     subcommand: "worker".to_string(), |     subcommand: "worker".to_string(), | ||||||
|  | @ -81,6 +82,12 @@ fn worker_main(args: CliModuleArgs) -> i32 { | ||||||
| 
 | 
 | ||||||
|   // TODO: show config loading errors in a GUI, if any
 |   // TODO: show config loading errors in a GUI, if any
 | ||||||
| 
 | 
 | ||||||
|  |   let use_evdev_backend = if cfg!(feature = "wayland") { | ||||||
|  |     true | ||||||
|  |   } else { | ||||||
|  |     std::env::var("USE_EVDEV").unwrap_or_else(|_| "false".to_string()) == "true" | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   let icon_paths = |   let icon_paths = | ||||||
|     crate::icon::load_icon_paths(&paths.runtime).expect("unable to initialize icons"); |     crate::icon::load_icon_paths(&paths.runtime).expect("unable to initialize icons"); | ||||||
| 
 | 
 | ||||||
|  | @ -112,6 +119,7 @@ fn worker_main(args: CliModuleArgs) -> i32 { | ||||||
|     engine_exit_receiver, |     engine_exit_receiver, | ||||||
|     engine_ui_event_receiver, |     engine_ui_event_receiver, | ||||||
|     engine_secure_input_receiver, |     engine_secure_input_receiver, | ||||||
|  |     use_evdev_backend, | ||||||
|   ) |   ) | ||||||
|   .expect("unable to initialize engine"); |   .expect("unable to initialize engine"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -35,6 +35,7 @@ use simplelog::{ | ||||||
| 
 | 
 | ||||||
| use crate::cli::{LogMode, PathsOverrides}; | use crate::cli::{LogMode, PathsOverrides}; | ||||||
| 
 | 
 | ||||||
|  | mod capabilities; | ||||||
| mod cli; | mod cli; | ||||||
| mod config; | mod config; | ||||||
| mod engine; | mod engine; | ||||||
|  | @ -401,6 +402,13 @@ fn main() { | ||||||
|       log_panics::init(); |       log_panics::init(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // If the process doesn't require linux capabilities, disable them
 | ||||||
|  |     if !handler.requires_linux_capabilities { | ||||||
|  |       if let Err(err) = crate::capabilities::clear_capabilities() { | ||||||
|  |         error!("unable to clear linux capabilities: {}", err); | ||||||
|  |       } 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // If explicitly requested, we show the Dock icon on macOS
 |     // If explicitly requested, we show the Dock icon on macOS
 | ||||||
|     // We need to enable this selectively, otherwise we would end up with multiple
 |     // We need to enable this selectively, otherwise we would end up with multiple
 | ||||||
|     // dock icons due to the multi-process nature of espanso.
 |     // dock icons due to the multi-process nature of espanso.
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user