Skip to content

Commit

Permalink
apply authentication data to requests
Browse files Browse the repository at this point in the history
  • Loading branch information
ranfdev committed Nov 15, 2023
1 parent aae34e9 commit f13146e
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 13 deletions.
8 changes: 8 additions & 0 deletions ntfy-daemon/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ impl Subscription {
.append_pair("since", &since.to_string());
Ok(url)
}
pub fn build_auth_url(server: &str, topic: &str) -> Result<url::Url, crate::Error> {
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<Self, Vec<crate::Error>> {
let mut errs = vec![];
if let Err(e) = validate_topic(&self.topic) {
Expand Down
3 changes: 1 addition & 2 deletions ntfy-daemon/src/system_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
59 changes: 48 additions & 11 deletions ntfy-daemon/src/topic_listener.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::ops::ControlFlow;
use std::sync::Arc;
use std::time::Duration;
Expand Down Expand Up @@ -61,16 +62,24 @@ pub fn build_client() -> anyhow::Result<reqwest::Client> {
.build()?)
}

fn topic_request(endpoint: &str, topic: &str, since: u64) -> anyhow::Result<reqwest::Request> {
fn topic_request(
client: &reqwest::Client,
endpoint: &str,
topic: &str,
since: u64,
username: Option<&str>,
password: Option<&str>,
) -> anyhow::Result<reqwest::Request> {
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(
Expand Down Expand Up @@ -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())),
Expand Down

0 comments on commit f13146e

Please sign in to comment.