From f13146ee7cf99b7823bfcd7c162705c2445ea859 Mon Sep 17 00:00:00 2001 From: ranfdev Date: Wed, 15 Nov 2023 10:00:45 +0100 Subject: [PATCH] apply authentication data to requests --- ntfy-daemon/src/models.rs | 8 +++++ ntfy-daemon/src/system_client.rs | 3 +- ntfy-daemon/src/topic_listener.rs | 59 +++++++++++++++++++++++++------ 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/ntfy-daemon/src/models.rs b/ntfy-daemon/src/models.rs index 23ce3ea..4e824ba 100644 --- a/ntfy-daemon/src/models.rs +++ b/ntfy-daemon/src/models.rs @@ -157,6 +157,14 @@ impl Subscription { .append_pair("since", &since.to_string()); Ok(url) } + pub fn build_auth_url(server: &str, topic: &str) -> Result { + let mut url = url::Url::parse(server)?; + url.path_segments_mut() + .map_err(|_| url::ParseError::RelativeUrlWithCannotBeABaseBase)? + .push(topic) + .push("auth"); + Ok(url) + } pub fn validate(self) -> Result> { let mut errs = vec![]; if let Err(e) = validate_topic(&self.topic) { diff --git a/ntfy-daemon/src/system_client.rs b/ntfy-daemon/src/system_client.rs index 0004114..93f2d99 100644 --- a/ntfy-daemon/src/system_client.rs +++ b/ntfy-daemon/src/system_client.rs @@ -493,8 +493,7 @@ impl system_notifier::Server for SystemNotifier { let password = params.get()?.get_password()?.to_str()?; info!("validating account"); - let url = models::Subscription::build_url(server, "stats", 0) - .map_err(|e| capnp::Error::failed(e.to_string()))?; + let url = models::Subscription::build_auth_url(server, "stats")?; http.get(url) .basic_auth(username, Some(password)) diff --git a/ntfy-daemon/src/topic_listener.rs b/ntfy-daemon/src/topic_listener.rs index e2a3564..560d19a 100644 --- a/ntfy-daemon/src/topic_listener.rs +++ b/ntfy-daemon/src/topic_listener.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::ops::ControlFlow; use std::sync::Arc; use std::time::Duration; @@ -61,16 +62,24 @@ pub fn build_client() -> anyhow::Result { .build()?) } -fn topic_request(endpoint: &str, topic: &str, since: u64) -> anyhow::Result { +fn topic_request( + client: &reqwest::Client, + endpoint: &str, + topic: &str, + since: u64, + username: Option<&str>, + password: Option<&str>, +) -> anyhow::Result { let url = models::Subscription::build_url(endpoint, topic, since)?; - let mut req = reqwest::Request::new(reqwest::Method::GET, url); - let headers = req.headers_mut(); - headers.append( - "Content-Type", - HeaderValue::from_static("application/x-ndjson"), - ); - headers.append("Transfer-Encoding", HeaderValue::from_static("chunked")); - Ok(req) + let mut req = client + .get(url) + .header("Content-Type", "application/x-ndjson") + .header("Transfer-Encoding", "chunked"); + if let Some(username) = username { + req = req.basic_auth(username, password); + } + + Ok(req.build()?) } async fn response_lines( @@ -161,8 +170,36 @@ impl TopicListener { #[instrument(skip_all)] async fn recv_and_forward(&mut self) -> anyhow::Result<()> { - let req = topic_request(&self.endpoint, &self.topic, self.since)?; - let res = self.env.http.execute(req).await?; + let (username, password) = { + let attrs = HashMap::from([("type", "password"), ("server", &self.endpoint)]); + let items = self + .env + .keyring + .search_items(attrs) + .await + .map_err(|e| capnp::Error::failed(e.to_string()))?; + + if let Some(item) = items.into_iter().next() { + let attrs = item + .attributes() + .await + .map_err(|e| capnp::Error::failed(e.to_string()))?; + let password = item.secret().await?; + let password = std::str::from_utf8(&*password)?; + (attrs.get("username").cloned(), Some(password.to_string())) + } else { + (None, None) + } + }; + let req = topic_request( + &self.env.http, + &self.endpoint, + &self.topic, + self.since, + username.as_deref(), + password.as_deref(), + ); + let res = self.env.http.execute(req?).await?; let reader = tokio_util::io::StreamReader::new( res.bytes_stream() .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string())),