feat: add retrieving and creating bitwarden sessions
Diff
src/main.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 97 insertions(+), 3 deletions(-)
@@ -1,5 +1,8 @@
use std::{env, process::{Command, Stdio, Output}};
use gumdrop::Options;
use anyhow::Result;
#[derive(Debug, Options)]
struct Cli {
#[options(help = "print help message and exit")]
@@ -13,12 +16,103 @@ struct Cli {
#[options(help = "custom field name where the key passphrase is stored", meta = "PASS", default = "passphrase")]
passphrase: String,
#[options(help = "session to use to log in to bitwarden-cli")]
session: Option<String>,
session: String,
#[options(help = "print version and exit")]
version: bool,
}
fn main() {
const SESSION_ENV_KEY: &str = "BW_SESSION";
fn main() -> Result<()> {
let args: Cli = Cli::parse_args_default_or_exit();
println!("{:#?}", args);
if args.version {
let name = env!("CARGO_PKG_NAME");
let version = env!("CARGO_PKG_VERSION");
println!("{} {}", name, version);
return Ok(());
}
let session: String = get_session(&args)?;
if !session.is_empty() {
println!("Successfully unlocked. To re-use this session, run:");
println!("export {}=\"{}\"", SESSION_ENV_KEY, session);
}
Ok(())
}
fn get_session(args: &Cli) -> Result<String> {
println!("Getting Bitwarden session...");
let mut session_key: String = String::new();
if args.session.trim().is_empty() {
let key = env::var(SESSION_ENV_KEY);
match key {
Ok(key) => {
println!("Existing Bitwarden session found.");
session_key.push_str(&key);
},
Err(_) => {
let logged_in = Command::new("bw")
.arg("login")
.arg("--check")
.arg("--quiet")
.output()?;
let mut operation = String::new();
if !logged_in.status.success() {
println!("Not logged in.");
operation.push_str("login");
}
else {
println!("Vault is locked.");
operation.push_str("unlock")
}
let success: Output = exec_interactive_command("bw", ["--raw", &operation].to_vec());
if success.status.success() {
session_key.push_str(&String::from_utf8(success.stdout)?);
}
}
}
}
else {
session_key.push_str(&args.session);
}
Ok(session_key)
}
pub fn exec_interactive_command(cmd: &str, args: Vec<&str>) -> Output {
let cli_command = match Command::new(cmd)
.args(&args)
.stdin(Stdio::inherit())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()
{
Err(err) => panic!("Error spawning: {}", err),
Ok(process) => process,
};
let output = cli_command.wait_with_output().unwrap();
return output;
}