From 95da8880e311d4932fd50febab6ef093e5915051 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 6 Apr 2020 22:40:00 -0400 Subject: start moving to an actual cli app --- Cargo.lock | 63 ++++++++++++++++++++++++++++ Cargo.toml | 1 + src/agent.rs | 17 ++++++++ src/bin/agent.rs | 32 ++++---------- src/bin/rbw.rs | 125 +++++++++++++++++++++++++++++++++++++++---------------- src/lib.rs | 1 + 6 files changed, 180 insertions(+), 59 deletions(-) create mode 100644 src/agent.rs diff --git a/Cargo.lock b/Cargo.lock index d7c2ae7..59dff78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,15 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.8", +] + [[package]] name = "arc-swap" version = "0.4.5" @@ -50,6 +59,17 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -165,6 +185,21 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -911,6 +946,7 @@ dependencies = [ "aes", "base64 0.11.0", "block-modes", + "clap", "directories", "fs2", "hkdf", @@ -1172,6 +1208,12 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "subtle" version = "1.0.0" @@ -1203,6 +1245,15 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "time" version = "0.1.42" @@ -1318,6 +1369,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -1350,6 +1407,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" + [[package]] name = "version_check" version = "0.9.1" diff --git a/Cargo.toml b/Cargo.toml index d4743ff..cfd4bfb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" aes = "*" base64 = "*" block-modes = "*" +clap = "*" directories = "*" fs2 = "*" hkdf = "*" diff --git a/src/agent.rs b/src/agent.rs new file mode 100644 index 0000000..4b9ac20 --- /dev/null +++ b/src/agent.rs @@ -0,0 +1,17 @@ +#[derive(serde::Serialize, serde::Deserialize, Debug)] +pub struct Message { + pub tty: Option, + pub action: Action, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[serde(tag = "type")] +pub enum Action { + Login, + Unlock, + Sync, + Decrypt { cipherstring: String }, + // add + // update + // remove +} diff --git a/src/bin/agent.rs b/src/bin/agent.rs index 6b73f56..50b13a1 100644 --- a/src/bin/agent.rs +++ b/src/bin/agent.rs @@ -3,24 +3,6 @@ use std::io::Write as _; use tokio::io::AsyncBufReadExt as _; use tokio::stream::StreamExt as _; -#[derive(serde::Deserialize, Debug)] -struct Message { - tty: Option, - action: Action, -} - -#[derive(serde::Deserialize, Debug)] -#[serde(tag = "type")] -enum Action { - Login, - Unlock, - Sync, - Decrypt { cipherstring: String }, - // add - // update - // remove -} - fn make_pidfile() -> std::fs::File { let runtime_dir = rbw::dirs::runtime_dir(); std::fs::create_dir_all(&runtime_dir).unwrap(); @@ -135,12 +117,16 @@ async fn handle_sock( let mut lines = buf.lines(); while let Some(line) = lines.next().await { let line = line.unwrap(); - let msg: Message = serde_json::from_str(&line).unwrap(); + let msg: rbw::agent::Message = serde_json::from_str(&line).unwrap(); match msg.action { - Action::Login => login(state.clone(), msg.tty.as_deref()).await, - Action::Unlock => unlock(state.clone(), msg.tty.as_deref()).await, - Action::Sync => sync(state.clone()).await, - Action::Decrypt { cipherstring } => { + rbw::agent::Action::Login => { + login(state.clone(), msg.tty.as_deref()).await + } + rbw::agent::Action::Unlock => { + unlock(state.clone(), msg.tty.as_deref()).await + } + rbw::agent::Action::Sync => sync(state.clone()).await, + rbw::agent::Action::Decrypt { cipherstring } => { decrypt(state.clone(), &cipherstring).await } } diff --git a/src/bin/rbw.rs b/src/bin/rbw.rs index 6c9bb11..910350b 100644 --- a/src/bin/rbw.rs +++ b/src/bin/rbw.rs @@ -1,44 +1,97 @@ -extern crate rbw; +use std::io::Write as _; -fn main() { - let client = - rbw::api::Client::new_self_hosted("https://bitwarden.tozt.net"); +fn send(msg: &rbw::agent::Message) { + let mut sock = std::os::unix::net::UnixStream::connect( + rbw::dirs::runtime_dir().join("socket"), + ) + .unwrap(); + sock.write_all(serde_json::to_string(msg).unwrap().as_bytes()) + .unwrap(); +} - let email = rprompt::prompt_reply_stderr("Email: ").unwrap(); - let password = rpassword::prompt_password_stderr("Password: ").unwrap(); +fn login() { + send(&rbw::agent::Message { + tty: std::env::var("TTY").ok(), + action: rbw::agent::Action::Login, + }) +} - let iterations = client.prelogin(&email).unwrap(); - let identity = - rbw::identity::Identity::new(&email, &password, iterations).unwrap(); +fn unlock() { + send(&rbw::agent::Message { + tty: std::env::var("TTY").ok(), + action: rbw::agent::Action::Unlock, + }) +} - let (access_token, _refresh_token, protected_key) = client - .login(&identity.email, &identity.master_password_hash) - .unwrap(); +fn sync() { + send(&rbw::agent::Message { + tty: std::env::var("TTY").ok(), + action: rbw::agent::Action::Sync, + }) +} - let protected_key = - rbw::cipherstring::CipherString::new(&protected_key).unwrap(); - let master_key = protected_key - .decrypt(&identity.enc_key, &identity.mac_key) - .unwrap(); +fn list() { + todo!() +} + +fn get() { + todo!() +} + +fn add() { + todo!() +} + +fn generate() { + todo!() +} + +fn edit() { + todo!() +} + +fn remove() { + todo!() +} + +fn lock() { + todo!() +} + +fn purge() { + todo!() +} + +fn main() { + let matches = clap::App::new("rbw") + .about("unofficial bitwarden cli") + .author(clap::crate_authors!()) + .version(clap::crate_version!()) + .subcommand(clap::SubCommand::with_name("login")) + .subcommand(clap::SubCommand::with_name("unlock")) + .subcommand(clap::SubCommand::with_name("sync")) + .subcommand(clap::SubCommand::with_name("list")) + .subcommand(clap::SubCommand::with_name("get")) + .subcommand(clap::SubCommand::with_name("add")) + .subcommand(clap::SubCommand::with_name("generate")) + .subcommand(clap::SubCommand::with_name("edit")) + .subcommand(clap::SubCommand::with_name("remove")) + .subcommand(clap::SubCommand::with_name("lock")) + .subcommand(clap::SubCommand::with_name("purge")) + .get_matches(); - let enc_key = &master_key[0..32]; - let mac_key = &master_key[32..64]; - - let (_, ciphers) = client.sync(&access_token).unwrap(); - for cipher in ciphers { - let secret_name = - rbw::cipherstring::CipherString::new(&cipher.name).unwrap(); - let name = secret_name.decrypt(enc_key, mac_key).unwrap(); - let secret_username = - rbw::cipherstring::CipherString::new(&cipher.login.username) - .unwrap(); - let username = secret_username.decrypt(enc_key, mac_key).unwrap(); - let secret_password = - rbw::cipherstring::CipherString::new(&cipher.login.password) - .unwrap(); - let password = secret_password.decrypt(enc_key, mac_key).unwrap(); - println!("{}:", String::from_utf8(name).unwrap()); - println!(" Username: {}", String::from_utf8(username).unwrap()); - println!(" Password: {}", String::from_utf8(password).unwrap()); + match matches.subcommand() { + ("login", Some(_)) => login(), + ("unlock", Some(_)) => unlock(), + ("sync", Some(_)) => sync(), + ("list", Some(_)) => list(), + ("get", Some(_)) => get(), + ("add", Some(_)) => add(), + ("generate", Some(_)) => generate(), + ("edit", Some(_)) => edit(), + ("remove", Some(_)) => remove(), + ("lock", Some(_)) => lock(), + ("purge", Some(_)) => purge(), + _ => unimplemented!(), } } diff --git a/src/lib.rs b/src/lib.rs index 175c37f..996098e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![allow(clippy::similar_names)] pub mod actions; +pub mod agent; pub mod api; pub mod cipherstring; pub mod dirs; -- cgit v1.2.3-54-g00ecf