aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/edit.rs54
-rw-r--r--src/error.rs15
-rw-r--r--src/lib.rs2
5 files changed, 72 insertions, 1 deletions
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<String> {
+ 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;