aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bin/rbw-agent/actions.rs54
-rw-r--r--src/bin/rbw-agent/agent.rs26
-rw-r--r--src/bin/rbw/actions.rs6
-rw-r--r--src/bin/rbw/commands.rs10
-rw-r--r--src/protocol.rs3
5 files changed, 66 insertions, 33 deletions
diff --git a/src/bin/rbw-agent/actions.rs b/src/bin/rbw-agent/actions.rs
index 1974736..c44f601 100644
--- a/src/bin/rbw-agent/actions.rs
+++ b/src/bin/rbw-agent/actions.rs
@@ -1,4 +1,5 @@
use anyhow::Context as _;
+use copypasta::ClipboardProvider as _;
pub async fn register(
sock: &mut crate::sock::Sock,
@@ -79,7 +80,7 @@ pub async fn register(
pub async fn login(
sock: &mut crate::sock::Sock,
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
tty: Option<&str>,
) -> anyhow::Result<()> {
let db = load_db().await.unwrap_or_else(|_| rbw::db::Db::new());
@@ -311,7 +312,7 @@ async fn two_factor(
}
async fn login_success(
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
access_token: String,
refresh_token: String,
kdf: rbw::api::KdfType,
@@ -356,7 +357,7 @@ async fn login_success(
match res {
Ok((keys, org_keys)) => {
- let mut state = state.write().await;
+ let mut state = state.lock().await;
state.priv_key = Some(keys);
state.org_keys = Some(org_keys);
}
@@ -368,10 +369,10 @@ async fn login_success(
pub async fn unlock(
sock: &mut crate::sock::Sock,
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
tty: Option<&str>,
) -> anyhow::Result<()> {
- if state.read().await.needs_unlock() {
+ if state.lock().await.needs_unlock() {
let db = load_db().await?;
let Some(kdf) = db.kdf
@@ -464,11 +465,11 @@ pub async fn unlock(
}
async fn unlock_success(
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
keys: rbw::locked::Keys,
org_keys: std::collections::HashMap<String, rbw::locked::Keys>,
) -> anyhow::Result<()> {
- let mut state = state.write().await;
+ let mut state = state.lock().await;
state.priv_key = Some(keys);
state.org_keys = Some(org_keys);
Ok(())
@@ -476,9 +477,9 @@ async fn unlock_success(
pub async fn lock(
sock: &mut crate::sock::Sock,
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
) -> anyhow::Result<()> {
- state.write().await.clear();
+ state.lock().await.clear();
respond_ack(sock).await?;
@@ -487,10 +488,10 @@ pub async fn lock(
pub async fn check_lock(
sock: &mut crate::sock::Sock,
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
_tty: Option<&str>,
) -> anyhow::Result<()> {
- if state.read().await.needs_unlock() {
+ if state.lock().await.needs_unlock() {
return Err(anyhow::anyhow!("agent is locked"));
}
@@ -538,11 +539,11 @@ pub async fn sync(
pub async fn decrypt(
sock: &mut crate::sock::Sock,
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
cipherstring: &str,
org_id: Option<&str>,
) -> anyhow::Result<()> {
- let state = state.read().await;
+ let state = state.lock().await;
let Some(keys) = state.key(org_id)
else {
return Err(anyhow::anyhow!(
@@ -565,11 +566,11 @@ pub async fn decrypt(
pub async fn encrypt(
sock: &mut crate::sock::Sock,
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
plaintext: &str,
org_id: Option<&str>,
) -> anyhow::Result<()> {
- let state = state.read().await;
+ let state = state.lock().await;
let Some(keys) = state.key(org_id)
else {
return Err(anyhow::anyhow!(
@@ -587,6 +588,25 @@ pub async fn encrypt(
Ok(())
}
+pub async fn clipboard_store(
+ sock: &mut crate::sock::Sock,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
+ text: &str,
+) -> anyhow::Result<()> {
+ state
+ .lock()
+ .await
+ .clipboard
+ .set_contents(text.to_owned())
+ .map_err(|e| {
+ anyhow::anyhow!("couldn't store value to clipboard: {e}")
+ })?;
+
+ respond_ack(sock).await?;
+
+ Ok(())
+}
+
pub async fn version(sock: &mut crate::sock::Sock) -> anyhow::Result<()> {
sock.send(&rbw::protocol::Response::Version {
version: rbw::protocol::version(),
@@ -663,7 +683,7 @@ async fn config_pinentry() -> anyhow::Result<String> {
}
pub async fn subscribe_to_notifications(
- state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<crate::agent::State>>,
) -> anyhow::Result<()> {
// access token might be out of date, so we do a sync to refresh it
sync(None).await?;
@@ -685,7 +705,7 @@ pub async fn subscribe_to_notifications(
+ "/notifications/hub?access_token=";
websocket_url.push_str(&access_token);
- let mut state = state.write().await;
+ let mut state = state.lock().await;
let err = state
.notifications_handler
.connect(websocket_url)
diff --git a/src/bin/rbw-agent/agent.rs b/src/bin/rbw-agent/agent.rs
index d4b3341..fe46e3b 100644
--- a/src/bin/rbw-agent/agent.rs
+++ b/src/bin/rbw-agent/agent.rs
@@ -12,6 +12,7 @@ pub struct State {
pub sync_timeout: crate::timeout::Timeout,
pub sync_timeout_duration: std::time::Duration,
pub notifications_handler: crate::notifications::Handler,
+ pub clipboard: copypasta::ClipboardContext,
}
impl State {
@@ -43,7 +44,7 @@ impl State {
pub struct Agent {
timer_r: tokio::sync::mpsc::UnboundedReceiver<()>,
sync_timer_r: tokio::sync::mpsc::UnboundedReceiver<()>,
- state: std::sync::Arc<tokio::sync::RwLock<State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<State>>,
}
impl Agent {
@@ -59,10 +60,13 @@ impl Agent {
sync_timeout.set(sync_timeout_duration);
}
let notifications_handler = crate::notifications::Handler::new();
+ let clipboard = copypasta::ClipboardContext::new().map_err(|e| {
+ anyhow::anyhow!("couldn't create clipboard context: {e}")
+ })?;
Ok(Self {
timer_r,
sync_timer_r,
- state: std::sync::Arc::new(tokio::sync::RwLock::new(State {
+ state: std::sync::Arc::new(tokio::sync::Mutex::new(State {
priv_key: None,
org_keys: None,
timeout,
@@ -70,6 +74,7 @@ impl Agent {
sync_timeout,
sync_timeout_duration,
notifications_handler,
+ clipboard,
})),
})
}
@@ -95,7 +100,7 @@ impl Agent {
notifications::NotificationMessage,
> = {
self.state
- .write()
+ .lock()
.await
.notifications_handler
.get_channel()
@@ -148,7 +153,7 @@ impl Agent {
});
}
Event::Timeout(()) => {
- self.state.write().await.clear();
+ self.state.lock().await.clear();
}
Event::Sync(()) => {
// this could fail if we aren't logged in, but we don't
@@ -159,7 +164,7 @@ impl Agent {
if let Err(e) = result {
eprintln!("failed to sync: {e:#}");
} else if !state
- .write()
+ .lock()
.await
.notifications_handler
.is_connected()
@@ -174,7 +179,7 @@ impl Agent {
}
}
});
- self.state.write().await.set_sync_timeout();
+ self.state.lock().await.set_sync_timeout();
}
}
}
@@ -184,7 +189,7 @@ impl Agent {
async fn handle_request(
sock: &mut crate::sock::Sock,
- state: std::sync::Arc<tokio::sync::RwLock<State>>,
+ state: std::sync::Arc<tokio::sync::Mutex<State>>,
) -> anyhow::Result<()> {
let req = sock.recv().await?;
let req = match req {
@@ -249,6 +254,11 @@ async fn handle_request(
.await?;
true
}
+ rbw::protocol::Action::ClipboardStore { text } => {
+ crate::actions::clipboard_store(sock, state.clone(), text)
+ .await?;
+ true
+ }
rbw::protocol::Action::Quit => std::process::exit(0),
rbw::protocol::Action::Version => {
crate::actions::version(sock).await?;
@@ -257,7 +267,7 @@ async fn handle_request(
};
if set_timeout {
- state.write().await.set_timeout();
+ state.lock().await.set_timeout();
}
Ok(())
diff --git a/src/bin/rbw/actions.rs b/src/bin/rbw/actions.rs
index 29cd6fe..e0e7a2e 100644
--- a/src/bin/rbw/actions.rs
+++ b/src/bin/rbw/actions.rs
@@ -101,6 +101,12 @@ pub fn encrypt(
}
}
+pub fn clipboard_store(text: &str) -> anyhow::Result<()> {
+ simple_action(rbw::protocol::Action::ClipboardStore {
+ text: text.to_string(),
+ })
+}
+
pub fn version() -> anyhow::Result<u32> {
let mut sock = connect()?;
sock.send(&rbw::protocol::Request {
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index 03f07b3..10f981d 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -1,5 +1,4 @@
use anyhow::Context as _;
-use copypasta::{ClipboardContext, ClipboardProvider};
use serde::Serialize;
use std::io;
use std::io::prelude::Write;
@@ -741,13 +740,8 @@ pub fn config_unset(key: &str) -> anyhow::Result<()> {
}
fn clipboard_store(val: &str) -> anyhow::Result<()> {
- let mut ctx = ClipboardContext::new().map_err(|e| {
- anyhow::anyhow!("couldn't create clipboard context: {e}")
- })?;
-
- ctx.set_contents(val.to_owned()).map_err(|e| {
- anyhow::anyhow!("couldn't store value to clipboard: {e}")
- })?;
+ ensure_agent()?;
+ crate::actions::clipboard_store(val)?;
Ok(())
}
diff --git a/src/protocol.rs b/src/protocol.rs
index f9a9d28..e883441 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -34,6 +34,9 @@ pub enum Action {
plaintext: String,
org_id: Option<String>,
},
+ ClipboardStore {
+ text: String,
+ },
Quit,
Version,
}