nostr-rs-relay

My dev fork of nostr-rs-relay
git clone git://jb55.com/nostr-rs-relay
Log | Files | Refs | README | LICENSE

commit 49598b2c9ee62e3adcb3cb75c48cf68a00e1e8d8
parent 54e6e0e5ce7b6e2eca01a86cbcc2b2931e290438
Author: Greg Heartsfield <scsibug@imap.cc>
Date:   Tue, 14 Dec 2021 21:38:26 -0600

fix: subscription event filtering bugs

Subscriptions properly filter using the authors tag.  Petname/keys are
correctly filtered (previously the event tags were incorrectly used).

Diffstat:
Msrc/conn.rs | 10+++++-----
Msrc/event.rs | 5+++++
Msrc/main.rs | 8++++----
Msrc/subscription.rs | 29++++++++++++++++++++++-------
4 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/src/conn.rs b/src/conn.rs @@ -45,15 +45,15 @@ impl ClientConn { self.client_id.to_string().chars().take(8).collect() } - /// Find the first subscription identifier that matches the event, - /// if any do. - pub fn get_matching_subscription(&self, e: &Event) -> Option<&str> { + /// Find all matching subscriptions. + pub fn get_matching_subscriptions(&self, e: &Event) -> Vec<&str> { + let mut v: Vec<&str> = vec![]; for (id, sub) in self.subscriptions.iter() { if sub.interested_in_event(e) { - return Some(id); + v.push(id); } } - None + return v; } /// Add a new subscription for this connection. diff --git a/src/event.rs b/src/event.rs @@ -154,6 +154,11 @@ impl Event { pub fn event_tag_match(&self, eventid: &str) -> bool { self.get_event_tags().contains(&eventid) } + + /// Check if a given event is referenced in an event tag. + pub fn pubkey_tag_match(&self, pubkey: &str) -> bool { + self.get_pubkey_tags().contains(&pubkey) + } } #[cfg(test)] diff --git a/src/main.rs b/src/main.rs @@ -129,16 +129,16 @@ async fn nostr_server( Ok(global_event) = bcast_rx.recv() => { // an event has been broadcast to all clients // first check if there is a subscription for this event. - let sub_name_opt = conn.get_matching_subscription(&global_event); - if let Some(sub_name) = sub_name_opt { + let matching_subs = conn.get_matching_subscriptions(&global_event); + for s in matching_subs { // TODO: serialize at broadcast time, instead of // once for each consumer. if let Ok(event_str) = serde_json::to_string(&global_event) { debug!("sub match: client: {}, sub: {}, event: {}", - cid, sub_name, + cid, s, global_event.get_event_id_prefix()); // create an event response and send it - let res = EventRes(sub_name.to_owned(),event_str); + let res = EventRes(s.to_owned(),event_str); nostr_stream.send(res).await.ok(); } else { warn!("could not convert event to string"); diff --git a/src/subscription.rs b/src/subscription.rs @@ -105,17 +105,21 @@ impl Subscription { } impl ReqFilter { - /// Check if this filter either matches, or does not care about an author. - fn author_match(&self, event: &Event) -> bool { + /// Check for a match within the authors list. + // TODO: Ambiguity; what if the array is empty? Should we + // consider that the same as null? + fn authors_match(&self, event: &Event) -> bool { self.authors .as_ref() .map(|vs| vs.contains(&event.pubkey.to_owned())) .unwrap_or(true) - && self - .author - .as_ref() - .map(|v| v == &event.pubkey) - .unwrap_or(true) + } + /// Check for a specific author match + fn author_match(&self, event: &Event) -> bool { + self.author + .as_ref() + .map(|v| v == &event.pubkey) + .unwrap_or(true) } /// Check if this filter either matches, or does not care about the event tags. fn event_match(&self, event: &Event) -> bool { @@ -125,6 +129,15 @@ impl ReqFilter { .unwrap_or(true) } + /// Check if this filter either matches, or does not care about + /// the pubkey/petname tags. + fn pubkey_match(&self, event: &Event) -> bool { + self.pubkey + .as_ref() + .map(|t| event.pubkey_tag_match(t)) + .unwrap_or(true) + } + /// Check if this filter either matches, or does not care about the kind. fn kind_match(&self, kind: u64) -> bool { self.kind.map(|v| v == kind).unwrap_or(true) @@ -136,6 +149,8 @@ impl ReqFilter { && self.since.map(|t| event.created_at > t).unwrap_or(true) && self.kind_match(event.kind) && self.author_match(event) + && self.authors_match(event) + && self.pubkey_match(event) && self.event_match(event) } }