index : bitwarden-ssh-agent.git

ascending towards madness

use std::process::{Command, Output, Stdio};
use serde::Deserialize;
use anyhow::{anyhow, Result, Context};

/// Represents a Bitwarden folder.
#[derive(Default, Debug, Clone, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BitwardenFolder {
	object: String,
	id: String,
	name: String
}

/// Gets the user's logged-in status from Bitwarden.
pub fn is_logged_in() -> Result<bool> {
	let logged_in = Command::new("bw")
	.arg("login")
	.arg("--check")
	.output()?;

	Ok(logged_in.stdout.len() > 0)
}

/// Gets a session token from Bitwarden.
pub fn get_session_token() -> Result<String> {
	let mut token = String::new();
	let mut operation = String::new();

	// No session token found. check to see if Bitwarden needs a login or is locked
	if is_logged_in()? {
		println!("Vault is locked.");
		operation.push_str("unlock")

	}
	else {
		println!("You are not logged in.");
		operation.push_str("login")
	}

	let success: Output = exec_interactive_command("bw", 
			["--raw", &operation].to_vec());
	if success.status.success() {			
		token.push_str(&String::from_utf8(success.stdout)?);
	}

	Ok(token)
}

/// Execute an interactive command.
/// 
/// The resulting output will be returned as `Output`. This is a modified version of:
/// 
/// https://users.rust-lang.org/t/command-if-a-child-process-is-asking-for-input-how-to-forward-the-question-to-the-user/37490/3
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;
}