From 6b38682d711fb74feddcc06c4da18f8e771858df Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 25 Jul 2020 04:33:51 -0400 Subject: implement rbw unlocked --- CHANGELOG.md | 2 ++ src/bin/rbw-agent/actions.rs | 14 ++++++++++++++ src/bin/rbw-agent/agent.rs | 9 +++++++++ src/bin/rbw/actions.rs | 4 ++++ src/bin/rbw/commands.rs | 7 +++++++ src/bin/rbw/main.rs | 5 +++++ src/protocol.rs | 1 + 7 files changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a666665..07983a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ * `rbw get --full` now displays URIs, TOTP secrets, and custom fields. * Add `rbw code` for generating TOTP codes based on secrets stored in Bitwarden. +* Add `rbw unlocked` which will exit with success if the agent is unlocked and + failure if the agent is locked. ## [0.4.6] - 2020-07-11 diff --git a/src/bin/rbw-agent/actions.rs b/src/bin/rbw-agent/actions.rs index a01f510..1a5a3c5 100644 --- a/src/bin/rbw-agent/actions.rs +++ b/src/bin/rbw-agent/actions.rs @@ -357,6 +357,20 @@ pub async fn lock( Ok(()) } +pub async fn check_lock( + sock: &mut crate::sock::Sock, + state: std::sync::Arc>, + _tty: Option<&str>, +) -> anyhow::Result<()> { + if state.read().await.needs_unlock() { + return Err(anyhow::anyhow!("agent is locked")); + } + + respond_ack(sock).await?; + + Ok(()) +} + pub async fn sync( sock: &mut crate::sock::Sock, ack: bool, diff --git a/src/bin/rbw-agent/agent.rs b/src/bin/rbw-agent/agent.rs index 2d9b08e..23f684b 100644 --- a/src/bin/rbw-agent/agent.rs +++ b/src/bin/rbw-agent/agent.rs @@ -143,6 +143,15 @@ async fn handle_request( .await?; true } + rbw::protocol::Action::CheckLock => { + crate::actions::check_lock( + sock, + state.clone(), + req.tty.as_deref(), + ) + .await?; + false + } rbw::protocol::Action::Lock => { crate::actions::lock(sock, state.clone()).await?; false diff --git a/src/bin/rbw/actions.rs b/src/bin/rbw/actions.rs index 9e64bbf..2c7d699 100644 --- a/src/bin/rbw/actions.rs +++ b/src/bin/rbw/actions.rs @@ -10,6 +10,10 @@ pub fn unlock() -> anyhow::Result<()> { simple_action(rbw::protocol::Action::Unlock) } +pub fn unlocked() -> anyhow::Result<()> { + simple_action(rbw::protocol::Action::CheckLock) +} + pub fn sync() -> anyhow::Result<()> { simple_action(rbw::protocol::Action::Sync) } diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs index e5858b6..f514153 100644 --- a/src/bin/rbw/commands.rs +++ b/src/bin/rbw/commands.rs @@ -466,6 +466,13 @@ pub fn unlock() -> anyhow::Result<()> { Ok(()) } +pub fn unlocked() -> anyhow::Result<()> { + ensure_agent()?; + crate::actions::unlocked()?; + + Ok(()) +} + pub fn sync() -> anyhow::Result<()> { ensure_agent()?; crate::actions::login()?; diff --git a/src/bin/rbw/main.rs b/src/bin/rbw/main.rs index f1903e7..2bb4360 100644 --- a/src/bin/rbw/main.rs +++ b/src/bin/rbw/main.rs @@ -22,6 +22,9 @@ enum Opt { #[structopt(about = "Unlock the local Bitwarden database")] Unlock, + #[structopt(about = "Check if the local Bitwarden database is unlocked")] + Unlocked, + #[structopt(about = "Update the local copy of the Bitwarden database")] Sync, @@ -207,6 +210,7 @@ impl Opt { } Self::Login => "login".to_string(), Self::Unlock => "unlock".to_string(), + Self::Unlocked => "unlocked".to_string(), Self::Sync => "sync".to_string(), Self::List { .. } => "list".to_string(), Self::Get { .. } => "get".to_string(), @@ -275,6 +279,7 @@ fn main(opt: Opt) { }, Opt::Login => commands::login(), Opt::Unlock => commands::unlock(), + Opt::Unlocked => commands::unlocked(), Opt::Sync => commands::sync(), Opt::List { fields } => commands::list(&fields), Opt::Get { diff --git a/src/protocol.rs b/src/protocol.rs index 68506b2..203e6b9 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -21,6 +21,7 @@ pub struct Request { pub enum Action { Login, Unlock, + CheckLock, Lock, Sync, Decrypt { -- cgit v1.2.3-54-g00ecf