aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock235
-rw-r--r--Cargo.toml4
-rw-r--r--src/bin/rbw-agent/agent.rs11
-rw-r--r--src/bin/rbw-agent/main.rs1
-rw-r--r--src/bin/rbw-agent/notifications.rs166
5 files changed, 399 insertions, 18 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1d8112b..c484789 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -81,6 +81,12 @@ checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
[[package]]
name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
+[[package]]
+name = "base64"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
@@ -371,6 +377,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
name = "form_urlencoded"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -380,58 +401,87 @@ dependencies = [
]
[[package]]
+name = "futures"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
name = "futures-channel"
-version = "0.3.27"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
+checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
dependencies = [
"futures-core",
+ "futures-sink",
]
[[package]]
name = "futures-core"
-version = "0.3.27"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
+checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
[[package]]
name = "futures-io"
-version = "0.3.27"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
+checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]]
name = "futures-macro"
-version = "0.3.27"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
+checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.10",
]
[[package]]
name = "futures-sink"
-version = "0.3.27"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
+checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[package]]
name = "futures-task"
-version = "0.3.27"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879"
+checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
[[package]]
name = "futures-util"
-version = "0.3.27"
+version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
+checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
+ "futures-channel",
"futures-core",
"futures-io",
"futures-macro",
+ "futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
@@ -776,6 +826,24 @@ dependencies = [
]
[[package]]
+name = "native-tls"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
name = "nix"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -854,12 +922,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
+name = "openssl"
+version = "0.10.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.10",
+]
+
+[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
+name = "openssl-sys"
+version = "0.9.84"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
name = "os_str_bytes"
version = "6.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -900,6 +1006,12 @@ dependencies = [
]
[[package]]
+name = "paste"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+
+[[package]]
name = "pbkdf2"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -959,6 +1071,12 @@ dependencies = [
]
[[package]]
+name = "pkg-config"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+
+[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1022,7 +1140,7 @@ dependencies = [
"arrayvec",
"async-trait",
"base32",
- "base64",
+ "base64 0.21.0",
"block-padding",
"cbc",
"clap",
@@ -1030,6 +1148,8 @@ dependencies = [
"daemonize",
"directories",
"env_logger",
+ "futures",
+ "futures-channel",
"futures-util",
"hkdf",
"hmac",
@@ -1043,6 +1163,7 @@ dependencies = [
"rand",
"region",
"reqwest",
+ "rmpv",
"rsa",
"serde",
"serde_json",
@@ -1056,6 +1177,7 @@ dependencies = [
"thiserror",
"tokio",
"tokio-stream",
+ "tokio-tungstenite",
"totp-lite",
"url",
"uuid",
@@ -1117,7 +1239,7 @@ version = "0.11.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ba30cc2c0cd02af1222ed216ba659cdb2f879dfe3181852fe7c50b1d0005949"
dependencies = [
- "base64",
+ "base64 0.21.0",
"bytes",
"encoding_rs",
"futures-core",
@@ -1166,6 +1288,27 @@ dependencies = [
]
[[package]]
+name = "rmp"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f"
+dependencies = [
+ "byteorder",
+ "num-traits",
+ "paste",
+]
+
+[[package]]
+name = "rmpv"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de8813b3a2f95c5138fe5925bfb8784175d88d6bff059ba8ce090aa891319754"
+dependencies = [
+ "num-traits",
+ "rmp",
+]
+
+[[package]]
name = "rsa"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1229,7 +1372,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
- "base64",
+ "base64 0.21.0",
]
[[package]]
@@ -1598,6 +1741,16 @@ dependencies = [
]
[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1620,6 +1773,20 @@ dependencies = [
]
[[package]]
+name = "tokio-tungstenite"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
+dependencies = [
+ "futures-util",
+ "log",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tungstenite",
+]
+
+[[package]]
name = "tokio-util"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1678,6 +1845,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
+name = "tungstenite"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
+dependencies = [
+ "base64 0.13.1",
+ "byteorder",
+ "bytes",
+ "http",
+ "httparse",
+ "log",
+ "native-tls",
+ "rand",
+ "sha1",
+ "thiserror",
+ "url",
+ "utf-8",
+]
+
+[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1738,6 +1925,12 @@ dependencies = [
]
[[package]]
+name = "utf-8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+
+[[package]]
name = "uuid"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1747,6 +1940,12 @@ dependencies = [
]
[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 778e9d4..f2925f0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,6 +27,8 @@ clap_complete = "4.1.5"
daemonize = "0.5.0"
directories = "5.0.0"
env_logger = "0.10.0"
+futures = "0.3.28"
+futures-channel = "0.3.28"
futures-util = "0.3.27"
hkdf = "0.12.3"
hmac = { version = "0.12.1", features = ["std"] }
@@ -57,6 +59,8 @@ totp-lite = "2.0.0"
url = "2.3.1"
uuid = { version = "1.3.0", features = ["v4"] }
zeroize = "1.5.7"
+rmpv = "1.0.0"
+tokio-tungstenite = { version = "*", features = ["native-tls"] }
[package.metadata.deb]
depends = "pinentry"
diff --git a/src/bin/rbw-agent/agent.rs b/src/bin/rbw-agent/agent.rs
index 7dcab16..9523c78 100644
--- a/src/bin/rbw-agent/agent.rs
+++ b/src/bin/rbw-agent/agent.rs
@@ -73,6 +73,17 @@ impl Agent {
self,
listener: tokio::net::UnixListener,
) -> anyhow::Result<()> {
+ tokio::spawn(async move {
+ let config = rbw::config::Config::load_async().await.expect("Error loading config");
+ let mut websocket_url = config.base_url.clone().expect("Config is missing base url").replace("https://", "wss://") + "/notifications/hub?access_token=";
+ if let Some(email) = &config.email {
+ let db = rbw::db::Db::load_async(&config.server_name().as_str(), email).await.expect("Error loading db");
+ let access_token = db.access_token.expect("Error getting access token");
+ websocket_url = websocket_url + &access_token;
+ crate::notifications::subscribe_to_notifications(websocket_url).await;
+ }
+ });
+
enum Event {
Request(std::io::Result<tokio::net::UnixStream>),
Timeout(()),
diff --git a/src/bin/rbw-agent/main.rs b/src/bin/rbw-agent/main.rs
index 81eee3a..5e0fa61 100644
--- a/src/bin/rbw-agent/main.rs
+++ b/src/bin/rbw-agent/main.rs
@@ -21,6 +21,7 @@ mod daemon;
mod debugger;
mod sock;
mod timeout;
+mod notifications;
async fn tokio_main(
startup_ack: Option<crate::daemon::StartupAck>,
diff --git a/src/bin/rbw-agent/notifications.rs b/src/bin/rbw-agent/notifications.rs
new file mode 100644
index 0000000..ffdefe9
--- /dev/null
+++ b/src/bin/rbw-agent/notifications.rs
@@ -0,0 +1,166 @@
+use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
+use futures_util::{StreamExt, SinkExt};
+
+struct SyncCipherUpdate {
+ id: String
+}
+
+struct SyncCipherCreate {
+ id: String
+}
+
+enum NotificationMessage {
+ SyncCipherUpdate(SyncCipherUpdate),
+ SyncCipherCreate(SyncCipherCreate),
+ SyncLoginDelete,
+ SyncFolderDelete,
+ SyncCiphers,
+
+ SyncVault,
+ SyncOrgKeys,
+ SyncFolderCreate,
+ SyncFolderUpdate,
+ SyncCipherDelete,
+ SyncSettings,
+
+ Logout,
+
+ SyncSendCreate,
+ SyncSendUpdate,
+ SyncSendDelete,
+
+ AuthRequest,
+ AuthRequestResponse,
+
+ None,
+}
+
+fn parse_messagepack(data: &[u8]) -> Option<NotificationMessage> {
+ if data.len() < 2 {
+ return None;
+ }
+
+ // the first few bytes with th 0x80 bit set, plus one byte terminating the length contain the length of the message
+ let len_buffer_length = data.iter().position(|&x| (x & 0x80) == 0 )? + 1;
+
+ println!("len_buffer_length: {:?}", len_buffer_length);
+ println!("data: {:?}", data);
+ let unpacked_messagepack = rmpv::decode::read_value(&mut &data[len_buffer_length..]).ok().unwrap();
+ println!("unpacked_messagepack: {:?}", unpacked_messagepack);
+ if !unpacked_messagepack.is_array() {
+ return None;
+ }
+ let unpacked_message = unpacked_messagepack.as_array().unwrap();
+ println!("unpacked_message: {:?}", unpacked_message);
+ let message_type = unpacked_message.iter().next()?.as_u64()?;
+ let message = unpacked_message.iter().skip(4).next()?.as_array()?.first()?.as_map()?;
+ let payload = message.iter().filter(|x| x.0.as_str().unwrap() == "Payload").next()?.1.as_map()?;
+ println!("message_type: {:?}", message_type);
+ println!("payload: {:?}", payload);
+
+ let message = match message_type {
+ 0 => {
+ let id = payload.iter().filter(|x| x.0.as_str().unwrap() == "Id").next()?.1.as_str()?;
+
+ Some(NotificationMessage::SyncCipherUpdate(
+ SyncCipherUpdate {
+ id: id.to_string()
+ }
+ ))
+ },
+ 1 => {
+ let id = payload.iter().filter(|x| x.0.as_str().unwrap() == "Id").next()?.1.as_str()?;
+
+ Some(NotificationMessage::SyncCipherCreate(
+ SyncCipherCreate {
+ id: id.to_string()
+ }
+ ))
+ },
+ 2 => Some(NotificationMessage::SyncLoginDelete),
+ 3 => Some(NotificationMessage::SyncFolderDelete),
+ 4 => Some(NotificationMessage::SyncCiphers),
+ 5 => Some(NotificationMessage::SyncVault),
+ 6 => Some(NotificationMessage::SyncOrgKeys),
+ 7 => Some(NotificationMessage::SyncFolderCreate),
+ 8 => Some(NotificationMessage::SyncFolderUpdate),
+ 9 => Some(NotificationMessage::SyncCipherDelete),
+ 10 => Some(NotificationMessage::SyncSettings),
+ 11 => Some(NotificationMessage::Logout),
+ 12 => Some(NotificationMessage::SyncSendCreate),
+ 13 => Some(NotificationMessage::SyncSendUpdate),
+ 14 => Some(NotificationMessage::SyncSendDelete),
+ 15 => Some(NotificationMessage::AuthRequest),
+ 16 => Some(NotificationMessage::AuthRequestResponse),
+ 100 => Some(NotificationMessage::None),
+ _ => None
+ };
+
+ return message;
+}
+
+pub async fn subscribe_to_notifications(url: String) {
+ let url = url::Url::parse(url.as_str()).unwrap();
+
+ let (ws_stream, _response) = connect_async(url).await.expect("Failed to connect");
+
+ let (mut write, read) = ws_stream.split();
+
+ write.send(Message::Text("{\"protocol\":\"messagepack\",\"version\":1}\n".to_string())).await.unwrap();
+
+ let read_future = read.for_each(|message| async {
+ match message {
+ Ok(Message::Binary(binary)) => {
+ let msg = parse_messagepack(&binary);
+ match msg {
+ Some(NotificationMessage::SyncCipherUpdate(update)) => {
+ println!("Websocket sent SyncCipherUpdate for id: {:?}", update.id);
+ crate::actions::sync(None).await.unwrap();
+ println!("Synced")
+ },
+ Some(NotificationMessage::SyncCipherCreate(update)) => {
+ println!("Websocket sent SyncCipherUpdate for id: {:?}", update.id);
+ crate::actions::sync(None).await.unwrap();
+ println!("Synced")
+ },
+ Some(NotificationMessage::SyncLoginDelete) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::SyncFolderDelete) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::SyncCiphers) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::SyncVault) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::SyncOrgKeys) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::SyncFolderCreate) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::SyncFolderUpdate) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::SyncCipherDelete) => {
+ crate::actions::sync(None).await.unwrap();
+ },
+ Some(NotificationMessage::Logout) => {
+ println!("Websocket sent Logout");
+ // todo: proper logout?
+ std::process::exit(0);
+ },
+ _ => {}
+ }
+ },
+ Err(e) => {
+ println!("websocket error: {:?}", e);
+ },
+ _ => {}
+ }
+ });
+
+ read_future.await;
+}