nostr-rs-relay

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

commit fa66a0265e6ad7b757fce2aae89e2f94ce58cbc9
parent 234a8ba0ac67d72d5024479be91fe0e05dfa8910
Author: Greg Heartsfield <scsibug@imap.cc>
Date:   Sat, 12 Feb 2022 09:29:31 -0600

docs: module headers

Diffstat:
Msrc/config.rs | 1+
Msrc/info.rs | 3++-
Msrc/nip05.rs | 2+-
Dsrc/tags.rs | 315-------------------------------------------------------------------------------
4 files changed, 4 insertions(+), 317 deletions(-)

diff --git a/src/config.rs b/src/config.rs @@ -1,3 +1,4 @@ +//! Configuration file and settings management use lazy_static::lazy_static; use log::*; use serde::{Deserialize, Serialize}; diff --git a/src/info.rs b/src/info.rs @@ -1,5 +1,6 @@ -use crate::config; +//! Relay metadata using NIP-11 /// Relay Info +use crate::config; use serde::{Deserialize, Serialize}; pub const CARGO_PKG_VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION"); diff --git a/src/nip05.rs b/src/nip05.rs @@ -1,4 +1,4 @@ -//! User Verification Through NIP-05 +//! User verification using NIP-05 names use crate::config::SETTINGS; use crate::db; use crate::error::{Error, Result}; diff --git a/src/tags.rs b/src/tags.rs @@ -1,315 +0,0 @@ -//! Tags used in events to link to another event or a pubkey -//! -//! Reference specification NIP01: https://github.com/fiatjaf/nostr/blob/master/nips/01.md#events-and-signatures -//! - -use bitcoin_hashes::hex::ToHex; -use bitcoin_hashes::sha256; -use secp256k1::XOnlyPublicKey; -use std::str::FromStr; - -use serde::de::Unexpected; -use serde::ser::SerializeSeq; -use serde::{Deserialize, Deserializer, Serializer}; -use serde_json::Value; - -use crate::error::Error; - -type EventId = sha256::Hash; - -#[derive(Debug, PartialEq)] -struct EventTag { - event_id: EventId, - recommended_url: Option<String>, -} - -#[derive(Debug, PartialEq)] -struct PubkeyTag { - pubkey: XOnlyPublicKey, - recommended_url: Option<String>, -} - -// Tag structure representing two possible types of tags -#[derive(Debug, PartialEq)] -enum Tag { - Event(EventTag), - Pubkey(PubkeyTag), -} - -// Custom json serialization into protocol network format -// Event tag : ["e", "<32 byte event-id>", "optional<url>"] -// Pubkey tag : ["p", "<32 byte Xonly Pubkey>", "optional<url>"] -impl serde::Serialize for Tag { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - match self { - Self::Event(event_tag) => { - let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element("e")?; - seq.serialize_element(&event_tag.event_id.to_hex())?; - if let Some(url) = &event_tag.recommended_url { - seq.serialize_element(url)?; - } else { - } - seq.end() - } - Self::Pubkey(pubkey_tag) => { - let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element("p")?; - seq.serialize_element(&pubkey_tag.pubkey.to_hex())?; - if let Some(url) = &pubkey_tag.recommended_url { - seq.serialize_element(url)?; - } else { - } - seq.end() - } - } - } -} - -// Custom json deserialization from protocol network format -impl<'de> serde::Deserialize<'de> for Tag { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - // Receive incoming data in a json object - let received: Value = Deserialize::deserialize(deserializer)?; - - // Check received data is a json array - let values = received.as_array().ok_or_else(|| { - serde::de::Error::invalid_type(Unexpected::Other("tag json object"), &"json array") - })?; - - // Check json array contains only string - let values = values - .iter() - .map(|value| { - value.as_str().ok_or_else(|| { - serde::de::Error::invalid_type( - Unexpected::Other("tag json data"), - &"json string", - ) - }) - }) - .collect::<Result<Vec<_>, _>>()?; - - // Check length is not more tha 3 - if values.len() > 3 { - Err(serde::de::Error::invalid_length( - values.len(), - &"tag length is 2 or 3", - )) - } else { - // Parse the json array into appropriate types - match values[0] { - // This denotes an event type tag - "e" => { - let event_id = EventId::from_str(values[1]) - .map_err(|e| serde::de::Error::custom(e.to_string()))?; - let recomended_url = if values.len() == 3 { - Some(values[2].into()) - } else { - None - }; - Ok(Tag::Event(EventTag { - event_id, - recommended_url: recomended_url, - })) - } - // This denotes a pubkey type tag - "p" => { - let pubkey = XOnlyPublicKey::from_str(values[1]) - .map_err(|e| serde::de::Error::custom(e.to_string()))?; - let recomended_url = if values.len() == 3 { - Some(values[2].into()) - } else { - None - }; - - Ok(Tag::Pubkey(PubkeyTag { - pubkey, - recommended_url: recomended_url, - })) - } - // Any other tag type is currently not supported - _ => Err(serde::de::Error::invalid_value( - Unexpected::Other("tag type flag"), - &"'e' or 'p'", - )), - } - } - } -} - -#[allow(dead_code)] -// Some api (not public currently) to use Tags -impl Tag { - fn new_event_tag(event_id: EventId, recomended_url: Option<String>) -> Self { - Self::Event(EventTag { - event_id, - recommended_url: recomended_url, - }) - } - - fn new_pubkey_tag(pubkey: XOnlyPublicKey, recomended_url: Option<String>) -> Self { - Self::Pubkey(PubkeyTag { - pubkey, - recommended_url: recomended_url, - }) - } - - fn get_recomended_url(&self) -> Option<String> { - match self { - Self::Event(EventTag { - event_id: _, - recommended_url, - }) => recommended_url.clone(), - Self::Pubkey(PubkeyTag { - pubkey: _, - recommended_url, - }) => recommended_url.clone(), - } - } - - fn get_event_id(&self) -> Result<EventId, Error> { - match self { - Self::Event(EventTag { - event_id, - recommended_url: _, - }) => Ok(*event_id), - _ => Err(Error::CustomError("Expected event tag".to_string())), - } - } - - fn get_pubkey(&self) -> Result<XOnlyPublicKey, Error> { - match self { - Self::Pubkey(PubkeyTag { - pubkey, - recommended_url: _, - }) => Ok(*pubkey), - _ => Err(Error::CustomError("Expected pubkey tag".to_string())), - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use bitcoin_hashes::Hash; - - #[test] - fn serde_roundtrip() { - let pubkey = XOnlyPublicKey::from_str( - "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166", - ) - .unwrap(); - let url = "wss://rsslay.fiatjaf.com"; - static HASH_BYTES: [u8; 32] = [ - 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, - 0x3d, 0x97, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c, - 0x86, 0x35, 0xfb, 0x6c, - ]; - let event_id = EventId::from_slice(&HASH_BYTES).expect("right number of bytes"); - - let event_tag = Tag::new_event_tag(event_id, Some(url.to_string())); - let pubkey_tag = Tag::new_pubkey_tag(pubkey, Some(url.to_string())); - - let ser_event_tag = serde_json::to_string(&event_tag).unwrap(); - let ser_pubkey_tag = serde_json::to_string(&pubkey_tag).unwrap(); - - let deser_event_tag: Tag = serde_json::from_str(&ser_event_tag).unwrap(); - let deser_pubkey_tag: Tag = serde_json::from_str(&ser_pubkey_tag).unwrap(); - - assert_eq!(deser_event_tag, event_tag); - assert_eq!(deser_pubkey_tag, pubkey_tag); - } - - #[test] - fn invalid_pubkey() { - let test_string = r#"["p","845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166","wss://rsslay.fiatjaf.com"]"#; - let tag: Result<Tag, _> = serde_json::from_str(test_string); - assert_eq!( - tag.err().expect("expect error").to_string(), - "secp: malformed public key".to_string() - ); - } - - #[test] - fn invalid_datatype() { - let test_string = r#"["p", 188457, "wss://rsslay.fiatjaf.com"]"#; - let tag: Result<Tag, _> = serde_json::from_str(test_string); - assert_eq!( - tag.err().expect("expect error").to_string(), - "invalid type: tag json data, expected json string".to_string() - ); - } - - #[test] - fn invalid_tagbyte() { - let test_string = r#"["q", "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166", "wss://rsslay.fiatjaf.com"]"#; - let tag: Result<Tag, _> = serde_json::from_str(test_string); - assert_eq!( - tag.err().expect("expect error").to_string(), - "invalid value: tag type flag, expected 'e' or 'p'".to_string() - ); - } - - #[test] - fn invalid_event_id() { - let test_string = r#"["e","ef537f25c895bfa782526529a9b63d97aa631564d5d78c8635fb6c","wss://rsslay.fiatjaf.com"]"#; - let tag: Result<Tag, _> = serde_json::from_str(test_string); - assert_eq!( - tag.err().expect("expect error").to_string(), - "bad hex string length 54 (expected 64)".to_string() - ); - } - - #[test] - fn invalid_url_type() { - let test_string = r#"["e","ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c", 123456788]"#; - let tag: Result<Tag, _> = serde_json::from_str(test_string); - assert_eq!( - tag.err().expect("expect error").to_string(), - "invalid type: tag json data, expected json string".to_string() - ); - } - - #[test] - fn invalid_length() { - let test_string = r#"["e","ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c","wss://rsslay.fiatjaf.com", "Random extra data"]"#; - let tag: Result<Tag, _> = serde_json::from_str(test_string); - assert_eq!( - tag.err().expect("expect error").to_string(), - "invalid length 4, expected tag length is 2 or 3".to_string() - ); - } - - #[test] - fn invalid_json_type() { - let test_string = r#"{"type": "e","event": "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"}"#; - let tag: Result<Tag, _> = serde_json::from_str(test_string); - assert_eq!( - tag.err().expect("expect error").to_string(), - "invalid type: tag json object, expected json array".to_string() - ); - } - - #[test] - fn evenrt_tag_missing_url() { - let test_string = - r#"["e","ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"]"#; - let tag: Tag = serde_json::from_str(test_string).unwrap(); - assert!(tag.get_recomended_url().is_none()); - } - - #[test] - fn pubkey_tag_missing_url() { - let test_string = - r#"["p","18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"]"#; - let tag: Tag = serde_json::from_str(test_string).unwrap(); - assert!(tag.get_recomended_url().is_none()); - } -}