Skip to content

Commit

Permalink
Enable saving read-only/root files via pkexec (Fixes #249) (#304)
Browse files Browse the repository at this point in the history
* Enable saving read-only/root files via pkexec (Fixes #249)

This update addresses the issue where users couldn't open Cosmic Edit as root. It allows users to save read-only or root files using pkexec for privilege escalation, all within the graphical interface of Cosmic Edit, eliminating the need to open the terminal.

Changes:

    Implemented pkexec functionality for saving read-only/root files.
    Added a confirmation dialog for file modifications.

This feature resolves issue #249 and streamlines the process, ensuring a smoother experience for users managing protected files directly within Cosmic Edit.

* Secure pkexec handling with piped stdin and escape safety

Enhanced permission handling by using `pkexec` with `tee` and piped stdin. This implementation avoids shell injection risks and ensures proper handling of special escape characters in the input. The approach securely writes text content to files with elevated privileges while maintaining robustness against potentially malicious inputs.

* Update tab.rs

* Log Errors but dont crash

* Update tab.rs

* Update tab.rs

* Clean up after child (sounds weird...)
  • Loading branch information
silverhadch authored Jan 23, 2025
1 parent a88a4ce commit 8e7c6bc
Showing 1 changed file with 61 additions and 19 deletions.
80 changes: 61 additions & 19 deletions src/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ use cosmic_text::{Attrs, Buffer, Cursor, Edit, Selection, Shaping, SyntaxEditor,
use notify::Watcher;
use regex::Regex;
use std::{
io::Write,
fs,
path::PathBuf,
process::{Command, Stdio},
sync::{Arc, Mutex},
};


use crate::{fl, git::GitDiff, Config, SYNTAX_SYSTEM};

pub enum Tab {
Expand Down Expand Up @@ -45,7 +48,7 @@ pub struct EditorTab {
impl EditorTab {
pub fn new(config: &Config) -> Self {
//TODO: do not repeat, used in App::init
let attrs = cosmic_text::Attrs::new().family(cosmic_text::Family::Monospace);
let attrs = Attrs::new().family(cosmic_text::Family::Monospace);

let mut buffer = Buffer::new_empty(config.metrics());
buffer.set_text(
Expand Down Expand Up @@ -144,26 +147,65 @@ impl EditorTab {
}

pub fn save(&mut self) {
if let Some(path) = &self.path_opt {
let mut editor = self.editor.lock().unwrap();
let mut text = String::new();
editor.with_buffer(|buffer| {
for line in buffer.lines.iter() {
text.push_str(line.text());
text.push_str(line.ending().as_str());
}
});
match fs::write(path, text) {
Ok(()) => {
editor.save_point();
log::info!("saved {:?}", path);
}
Err(err) => {
log::error!("failed to save {:?}: {}", path, err);
if let Some(path) = &self.path_opt {
let mut editor = self.editor.lock().unwrap();
let mut text = String::new();

editor.with_buffer(|buffer| {
for line in buffer.lines.iter() {
text.push_str(line.text());
text.push_str(line.ending().as_str());
}
});

match fs::write(path, &text) {
Ok(()) => {
editor.save_point();
log::info!("saved {:?}", path);
}
Err(err) => {
if err.kind() == std::io::ErrorKind::PermissionDenied {
log::warn!("Permission denied. Attempting to save with pkexec.");

if let Ok(mut output) = Command::new("pkexec")
.arg("tee")
.arg(path)
.stdin(Stdio::piped())
.stdout(Stdio::null()) // Redirect stdout to /dev/null
.stderr(Stdio::inherit()) // Retain stderr for error visibility
.spawn()
{
if let Some(mut stdin) = output.stdin.take() {
if let Err(e) = stdin.write_all(text.as_bytes()) {
log::error!("Failed to write to stdin: {}", e);
}
} else {
log::error!("Failed to access stdin of pkexec process.");
}

// Ensure the child process is reaped
match output.wait() {
Ok(status) => {
if status.success() {
// Mark the editor's state as saved if the process succeeds
editor.save_point();
log::info!("File saved successfully with pkexec.");
} else {
log::error!("pkexec process exited with a non-zero status: {:?}", status);
}
}
Err(e) => {
log::error!("Failed to wait on pkexec process: {}", e);
}
}
} else {
log::error!("Failed to spawn pkexec process. Check permissions or path.");
}
}
}
} else {
log::warn!("tab has no path yet");
}
} else {
log::warn!("tab has no path yet");
}
}

Expand Down

0 comments on commit 8e7c6bc

Please sign in to comment.