From dd7ef574e84ca6c1a548422904c6865048ae8e30 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 18 Apr 2020 01:30:07 -0400 Subject: implement editing a string in a text editor --- Cargo.lock | 1 + Cargo.toml | 1 + src/edit.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/error.rs | 15 ++++++++++++++- src/lib.rs | 2 ++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/edit.rs diff --git a/Cargo.lock b/Cargo.lock index c157b72..b9545da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1157,6 +1157,7 @@ dependencies = [ "serde_json", "sha2", "snafu", + "tempfile", "tokio", "uuid", "zeroize", diff --git a/Cargo.toml b/Cargo.toml index 526d8f3..aeb27b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ serde = { version = "*", features = ["derive"] } serde_json = "*" sha2 = "*" snafu = "*" +tempfile = "*" tokio = { version = "*", features = ["full"] } uuid = { version = "*", features = ["v4"] } zeroize = "*" diff --git a/src/edit.rs b/src/edit.rs new file mode 100644 index 0000000..8325072 --- /dev/null +++ b/src/edit.rs @@ -0,0 +1,54 @@ +use crate::prelude::*; + +use std::io::{Read as _, Write as _}; + +pub fn edit(contents: &str, help: &str) -> Result { + let editor = + std::env::var_os("EDITOR").unwrap_or_else(|| "/usr/bin/vim".into()); + let editor = std::path::Path::new(&editor); + + let mut args = vec![]; + match editor.file_name() { + Some(editor) => match editor.to_str() { + Some("vim") => { + // disable swap files and viminfo for password entry + args.push(std::ffi::OsStr::new("-ni")); + args.push(std::ffi::OsStr::new("NONE")); + } + _ => { + // other editor support welcomed + } + }, + None => { + return Err(Error::InvalidEditor { + editor: editor.as_os_str().to_os_string(), + }) + } + } + + let dir = tempfile::tempdir().unwrap(); + let file = dir.path().join("rbw"); + let mut fh = std::fs::File::create(&file).unwrap(); + fh.write_all(contents.as_bytes()).unwrap(); + fh.write_all(help.as_bytes()).unwrap(); + drop(fh); + + args.push(file.as_os_str()); + let res = std::process::Command::new(&editor) + .args(&args) + .status() + .unwrap(); + if !res.success() { + return Err(Error::FailedToRunEditor { + editor: editor.to_owned(), + res, + }); + } + + let mut fh = std::fs::File::open(&file).unwrap(); + let mut contents = String::new(); + fh.read_to_string(&mut contents).unwrap(); + drop(fh); + + Ok(contents) +} diff --git a/src/error.rs b/src/error.rs index 71c8285..8c253c9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,9 +9,19 @@ pub enum Error { #[snafu(display("failed to decrypt: {}", source))] Decrypt { source: block_modes::BlockModeError }, - #[snafu(display("failed to parse pinentry output ({:?})", out,))] + #[snafu(display("failed to parse pinentry output ({:?})", out))] FailedToParsePinentry { out: String }, + #[snafu(display( + "failed to run editor {}: {:?}", + editor.to_string_lossy(), + res + ))] + FailedToRunEditor { + editor: std::path::PathBuf, + res: std::process::ExitStatus, + }, + // no Error impl // #[snafu(display("failed to expand with hkdf: {}", source))] // HkdfExpand { source: hkdf::InvalidLength }, @@ -30,6 +40,9 @@ pub enum Error { #[snafu(display("invalid cipherstring"))] InvalidCipherString, + #[snafu(display("invalid value for $EDITOR: {}", editor.to_string_lossy()))] + InvalidEditor { editor: std::ffi::OsString }, + #[snafu(display("invalid mac"))] InvalidMac, diff --git a/src/lib.rs b/src/lib.rs index 6ae5f7e..12c8c6e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![allow(clippy::missing_errors_doc)] #![allow(clippy::must_use_candidate)] #![allow(clippy::similar_names)] +#![allow(clippy::single_match)] pub mod actions; pub mod api; @@ -11,6 +12,7 @@ pub mod cipherstring; pub mod config; pub mod db; pub mod dirs; +pub mod edit; pub mod error; pub mod identity; pub mod locked; -- cgit v1.2.3-54-g00ecf