feat: handle NIP-09 for deletion events

This commit is contained in:
Greg Heartsfield 2022-02-27 11:34:10 -06:00
parent ed3a6b9692
commit 1d499cf12b
4 changed files with 68 additions and 1 deletions

View File

@ -18,7 +18,7 @@ NIPs with a relay-specific implementation are listed here.
- [x] NIP-02: Hide old contact list events - [x] NIP-02: Hide old contact list events
- [ ] NIP-03: OpenTimestamps - [ ] NIP-03: OpenTimestamps
- [x] NIP-05: Mapping Nostr keys to DNS identifiers - [x] NIP-05: Mapping Nostr keys to DNS identifiers
- [ ] NIP-09: Event deletion - [x] NIP-09: Event deletion
- [x] NIP-11: Relay information document - [x] NIP-11: Relay information document
- [x] NIP-12: Generic tag search (_experimental_) - [x] NIP-12: Generic tag search (_experimental_)

View File

@ -332,6 +332,29 @@ pub fn write_event(conn: &mut PooledConnection, e: &Event) -> Result<usize> {
); );
} }
} }
// if this event is a deletion, hide the referenced events from the same author.
if e.kind == 5 {
let event_candidates = e.tag_values_by_name("e");
let mut params: Vec<Box<dyn ToSql>> = vec![];
// first parameter will be author
params.push(Box::new(hex::decode(&e.pubkey)?));
event_candidates
.iter()
.filter(|x| is_hex(x) && x.len() == 64)
.filter_map(|x| hex::decode(x).ok())
.for_each(|x| params.push(Box::new(x)));
let query = format!(
"UPDATE event SET hidden=TRUE WHERE author=?, event_hash IN ({})",
repeat_vars(params.len() - 1)
);
let mut stmt = tx.prepare(&query)?;
let update_count = stmt.execute(rusqlite::params_from_iter(params))?;
info!(
"hid {} deleted events for author {:?}",
update_count,
e.get_author_prefix()
);
}
tx.commit()?; tx.commit()?;
Ok(ins_count) Ok(ins_count)
} }

View File

@ -48,6 +48,8 @@ pub enum Error {
JoinError, JoinError,
#[error("Hyper Client error")] #[error("Hyper Client error")]
HyperError(hyper::Error), HyperError(hyper::Error),
#[error("Hex encoding error")]
HexError(hex::FromHexError),
#[error("Unknown/Undocumented")] #[error("Unknown/Undocumented")]
UnknownError, UnknownError,
} }
@ -58,6 +60,12 @@ pub enum Error {
// } // }
//} //}
impl From<hex::FromHexError> for Error {
fn from(h: hex::FromHexError) -> Self {
Error::HexError(h)
}
}
impl From<hyper::Error> for Error { impl From<hyper::Error> for Error {
fn from(h: hyper::Error) -> Self { fn from(h: hyper::Error) -> Self {
Error::HyperError(h) Error::HyperError(h)

View File

@ -124,6 +124,16 @@ impl Event {
self.pubkey.chars().take(8).collect() self.pubkey.chars().take(8).collect()
} }
/// Retrieve tag values
pub fn tag_values_by_name(&self, tag_name: &str) -> Vec<String> {
self.tags
.iter()
.filter(|x| x.len() > 1)
.filter(|x| x.get(0).unwrap() == tag_name)
.map(|x| x.get(1).unwrap().to_owned())
.collect()
}
/// Check if this event has a valid signature. /// Check if this event has a valid signature.
fn is_valid(&self) -> bool { fn is_valid(&self) -> bool {
// TODO: return a Result with a reason for invalid events // TODO: return a Result with a reason for invalid events
@ -335,6 +345,32 @@ mod tests {
assert_eq!(c, expected); assert_eq!(c, expected);
} }
#[test]
fn event_tag_select() {
let e = Event {
id: "999".to_owned(),
pubkey: "012345".to_owned(),
created_at: 501234,
kind: 1,
tags: vec![
vec!["j".to_owned(), "abc".to_owned()],
vec!["e".to_owned(), "foo".to_owned()],
vec!["e".to_owned(), "bar".to_owned()],
vec!["e".to_owned(), "baz".to_owned()],
vec![
"p".to_owned(),
"aaaa".to_owned(),
"ws://example.com".to_owned(),
],
],
content: "this is a test".to_owned(),
sig: "abcde".to_owned(),
tagidx: None,
};
let v = e.tag_values_by_name("e");
assert_eq!(v, vec!["foo", "bar", "baz"]);
}
#[test] #[test]
fn event_canonical_with_tags() { fn event_canonical_with_tags() {
let e = Event { let e = Event {