mirror of
https://github.com/scsibug/nostr-rs-relay.git
synced 2024-11-09 21:29:06 -05:00
docs: module headers
This commit is contained in:
parent
234a8ba0ac
commit
fa66a0265e
|
@ -1,3 +1,4 @@
|
|||
//! Configuration file and settings management
|
||||
use lazy_static::lazy_static;
|
||||
use log::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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};
|
||||
|
|
315
src/tags.rs
315
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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user