aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-03-25 18:44:21 -0400
committerJesse Luehrs <doy@tozt.net>2023-03-25 23:14:16 -0400
commit5eab3c4b33f2b0b594993a095eae86f88828827d (patch)
treea2ce6133546bd03a56ad2ae65f1ad0478ab8ee91
parentb659cc500476a7b4b94bc6659d46922be9465b99 (diff)
downloadrbw-5eab3c4b33f2b0b594993a095eae86f88828827d.tar.gz
rbw-5eab3c4b33f2b0b594993a095eae86f88828827d.zip
sync the db every hour, like other bitwarden clients
-rw-r--r--CHANGELOG.md3
-rw-r--r--README.md3
-rw-r--r--src/bin/rbw-agent/actions.rs12
-rw-r--r--src/bin/rbw-agent/agent.rs32
-rw-r--r--src/bin/rbw/commands.rs6
-rw-r--r--src/config.rs8
6 files changed, 55 insertions, 9 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f14a4cd..b1cecb0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,9 @@
* `rbw get` now supports a `--raw` option to display the entire contents of
the entry in JSON format (#97, classabbyamp)
+* `rbw` now automatically syncs the database from the server at a specified
+ interval while it is running. This defaults to once an hour, but is
+ configurable via the `sync_interval` option
## [1.5.0] - 2023-02-18
diff --git a/README.md b/README.md
index 5efe1f8..7ea61ee 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,9 @@ configuration options:
* `lock_timeout`: The number of seconds to keep the master keys in memory for
before requiring the password to be entered again. Defaults to `3600` (one
hour).
+* `sync_interval`: `rbw` will automatically sync the database from the server
+ at an interval of this many seconds, while the agent is running. Setting
+ this value to `0` disables this behavior. Defaults to `3600` (one hour).
* `pinentry`: The
[pinentry](https://www.gnupg.org/related_software/pinentry/index.html)
executable to use. Defaults to `pinentry`.
diff --git a/src/bin/rbw-agent/actions.rs b/src/bin/rbw-agent/actions.rs
index e857a1e..7b5dc58 100644
--- a/src/bin/rbw-agent/actions.rs
+++ b/src/bin/rbw-agent/actions.rs
@@ -130,7 +130,6 @@ pub async fn login(
protected_key,
)) => {
login_success(
- sock,
state,
access_token,
refresh_token,
@@ -166,11 +165,10 @@ pub async fn login(
tty,
&email,
password.clone(),
- provider
+ provider,
)
.await?;
login_success(
- sock,
state,
access_token,
refresh_token,
@@ -307,7 +305,6 @@ async fn two_factor(
}
async fn login_success(
- sock: &mut crate::sock::Sock,
state: std::sync::Arc<tokio::sync::RwLock<crate::agent::State>>,
access_token: String,
refresh_token: String,
@@ -329,7 +326,7 @@ async fn login_success(
db.protected_key = Some(protected_key.to_string());
save_db(&db).await?;
- sync(sock, false).await?;
+ sync(None).await?;
let db = load_db().await?;
let Some(protected_private_key) = db.protected_private_key
@@ -497,8 +494,7 @@ pub async fn check_lock(
}
pub async fn sync(
- sock: &mut crate::sock::Sock,
- ack: bool,
+ sock: Option<&mut crate::sock::Sock>,
) -> anyhow::Result<()> {
let mut db = load_db().await?;
@@ -527,7 +523,7 @@ pub async fn sync(
db.entries = entries;
save_db(&db).await?;
- if ack {
+ if let Some(sock) = sock {
respond_ack(sock).await?;
}
diff --git a/src/bin/rbw-agent/agent.rs b/src/bin/rbw-agent/agent.rs
index 8fa6768..7dcab16 100644
--- a/src/bin/rbw-agent/agent.rs
+++ b/src/bin/rbw-agent/agent.rs
@@ -7,6 +7,8 @@ pub struct State {
Option<std::collections::HashMap<String, rbw::locked::Keys>>,
pub timeout: crate::timeout::Timeout,
pub timeout_duration: std::time::Duration,
+ pub sync_timeout: crate::timeout::Timeout,
+ pub sync_timeout_duration: std::time::Duration,
}
impl State {
@@ -29,10 +31,15 @@ impl State {
self.org_keys = None;
self.timeout.clear();
}
+
+ pub fn set_sync_timeout(&mut self) {
+ self.sync_timeout.set(self.sync_timeout_duration);
+ }
}
pub struct Agent {
timer_r: tokio::sync::mpsc::UnboundedReceiver<()>,
+ sync_timer_r: tokio::sync::mpsc::UnboundedReceiver<()>,
state: std::sync::Arc<tokio::sync::RwLock<State>>,
}
@@ -41,14 +48,23 @@ impl Agent {
let config = rbw::config::Config::load()?;
let timeout_duration =
std::time::Duration::from_secs(config.lock_timeout);
+ let sync_timeout_duration =
+ std::time::Duration::from_secs(config.sync_interval);
let (timeout, timer_r) = crate::timeout::Timeout::new();
+ let (sync_timeout, sync_timer_r) = crate::timeout::Timeout::new();
+ if sync_timeout_duration > std::time::Duration::ZERO {
+ sync_timeout.set(sync_timeout_duration);
+ }
Ok(Self {
timer_r,
+ sync_timer_r,
state: std::sync::Arc::new(tokio::sync::RwLock::new(State {
priv_key: None,
org_keys: None,
timeout,
timeout_duration,
+ sync_timeout,
+ sync_timeout_duration,
})),
})
}
@@ -60,6 +76,7 @@ impl Agent {
enum Event {
Request(std::io::Result<tokio::net::UnixStream>),
Timeout(()),
+ Sync(()),
}
let mut stream = futures_util::stream::select_all([
tokio_stream::wrappers::UnixListenerStream::new(listener)
@@ -70,6 +87,11 @@ impl Agent {
)
.map(Event::Timeout)
.boxed(),
+ tokio_stream::wrappers::UnboundedReceiverStream::new(
+ self.sync_timer_r,
+ )
+ .map(Event::Sync)
+ .boxed(),
]);
while let Some(event) = stream.next().await {
match event {
@@ -94,6 +116,14 @@ impl Agent {
Event::Timeout(()) => {
self.state.write().await.clear();
}
+ Event::Sync(()) => {
+ // this could fail if we aren't logged in, but we don't
+ // care about that
+ tokio::spawn(async move {
+ let _ = crate::actions::sync(None).await;
+ });
+ self.state.write().await.set_sync_timeout();
+ }
}
}
Ok(())
@@ -141,7 +171,7 @@ async fn handle_request(
false
}
rbw::protocol::Action::Sync => {
- crate::actions::sync(sock, true).await?;
+ crate::actions::sync(Some(sock)).await?;
false
}
rbw::protocol::Action::Decrypt {
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index 668cb89..5d51f70 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -639,6 +639,12 @@ pub fn config_set(key: &str, value: &str) -> anyhow::Result<()> {
config.lock_timeout = timeout;
}
}
+ "sync_interval" => {
+ let interval = value
+ .parse()
+ .context("failed to parse value for sync_interval")?;
+ config.sync_interval = interval;
+ }
"pinentry" => config.pinentry = value.to_string(),
_ => return Err(anyhow::anyhow!("invalid config key: {}", key)),
}
diff --git a/src/config.rs b/src/config.rs
index 91aa449..d70a21b 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -10,6 +10,8 @@ pub struct Config {
pub identity_url: Option<String>,
#[serde(default = "default_lock_timeout")]
pub lock_timeout: u64,
+ #[serde(default = "default_sync_interval")]
+ pub sync_interval: u64,
#[serde(default = "default_pinentry")]
pub pinentry: String,
pub client_cert_path: Option<std::path::PathBuf>,
@@ -25,6 +27,7 @@ impl Default for Config {
base_url: None,
identity_url: None,
lock_timeout: default_lock_timeout(),
+ sync_interval: default_sync_interval(),
pinentry: default_pinentry(),
client_cert_path: None,
device_id: None,
@@ -38,6 +41,11 @@ pub fn default_lock_timeout() -> u64 {
}
#[must_use]
+pub fn default_sync_interval() -> u64 {
+ 3600
+}
+
+#[must_use]
pub fn default_pinentry() -> String {
"pinentry".to_string()
}