mirror of
https://github.com/scsibug/nostr-rs-relay.git
synced 2024-11-09 21:29:06 -05:00
feat(NIP-20): improve invalid event error messages
Instead of returning a NOTICE for invalid events, return a `OK false` command result with a reason as to why the event is invalid.
This commit is contained in:
parent
5a91419d34
commit
6d1244434b
12
src/error.rs
12
src/error.rs
|
@ -17,10 +17,16 @@ pub enum Error {
|
||||||
ConnWriteError,
|
ConnWriteError,
|
||||||
#[error("EVENT parse failed")]
|
#[error("EVENT parse failed")]
|
||||||
EventParseFailed,
|
EventParseFailed,
|
||||||
#[error("ClOSE message parse failed")]
|
#[error("CLOSE message parse failed")]
|
||||||
CloseParseFailed,
|
CloseParseFailed,
|
||||||
#[error("Event validation failed")]
|
#[error("Event invalid signature")]
|
||||||
EventInvalid,
|
EventInvalidSignature,
|
||||||
|
#[error("Event invalid id")]
|
||||||
|
EventInvalidId,
|
||||||
|
#[error("Event malformed pubkey")]
|
||||||
|
EventMalformedPubkey,
|
||||||
|
#[error("Event could not canonicalize")]
|
||||||
|
EventCouldNotCanonicalize,
|
||||||
#[error("Event too large")]
|
#[error("Event too large")]
|
||||||
EventMaxLengthError(usize),
|
EventMaxLengthError(usize),
|
||||||
#[error("Subscription identifier max length exceeded")]
|
#[error("Subscription identifier max length exceeded")]
|
||||||
|
|
34
src/event.rs
34
src/event.rs
|
@ -27,6 +27,12 @@ pub struct EventCmd {
|
||||||
event: Event,
|
event: Event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EventCmd {
|
||||||
|
pub fn event_id(&self) -> &str {
|
||||||
|
return &self.event.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parsed nostr event.
|
/// Parsed nostr event.
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
|
@ -83,13 +89,13 @@ impl From<EventCmd> for Result<Event> {
|
||||||
// ensure command is correct
|
// ensure command is correct
|
||||||
if ec.cmd != "EVENT" {
|
if ec.cmd != "EVENT" {
|
||||||
Err(CommandUnknownError)
|
Err(CommandUnknownError)
|
||||||
} else if ec.event.is_valid() {
|
|
||||||
let mut e = ec.event;
|
|
||||||
e.build_index();
|
|
||||||
e.update_delegation();
|
|
||||||
Ok(e)
|
|
||||||
} else {
|
} else {
|
||||||
Err(EventInvalid)
|
ec.event.validate().map(|_| {
|
||||||
|
let mut e = ec.event;
|
||||||
|
e.build_index();
|
||||||
|
e.update_delegation();
|
||||||
|
e
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +226,7 @@ impl Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if this event has a valid signature.
|
/// Check if this event has a valid signature.
|
||||||
fn is_valid(&self) -> bool {
|
fn validate(&self) -> Result<()> {
|
||||||
// TODO: return a Result with a reason for invalid events
|
// TODO: return a Result with a reason for invalid events
|
||||||
// validation is performed by:
|
// validation is performed by:
|
||||||
// * parsing JSON string into event fields
|
// * parsing JSON string into event fields
|
||||||
|
@ -229,8 +235,8 @@ impl Event {
|
||||||
// * serialize with no spaces/newlines
|
// * serialize with no spaces/newlines
|
||||||
let c_opt = self.to_canonical();
|
let c_opt = self.to_canonical();
|
||||||
if c_opt.is_none() {
|
if c_opt.is_none() {
|
||||||
debug!("event could not be canonicalized");
|
debug!("could not canonicalize");
|
||||||
return false;
|
return Err(EventCouldNotCanonicalize);
|
||||||
}
|
}
|
||||||
let c = c_opt.unwrap();
|
let c = c_opt.unwrap();
|
||||||
// * compute the sha256sum.
|
// * compute the sha256sum.
|
||||||
|
@ -239,21 +245,21 @@ impl Event {
|
||||||
// * ensure the id matches the computed sha256sum.
|
// * ensure the id matches the computed sha256sum.
|
||||||
if self.id != hex_digest {
|
if self.id != hex_digest {
|
||||||
debug!("event id does not match digest");
|
debug!("event id does not match digest");
|
||||||
return false;
|
return Err(EventInvalidId);
|
||||||
}
|
}
|
||||||
// * validate the message digest (sig) using the pubkey & computed sha256 message hash.
|
// * validate the message digest (sig) using the pubkey & computed sha256 message hash.
|
||||||
let sig = schnorr::Signature::from_str(&self.sig).unwrap();
|
let sig = schnorr::Signature::from_str(&self.sig).unwrap();
|
||||||
if let Ok(msg) = secp256k1::Message::from_slice(digest.as_ref()) {
|
if let Ok(msg) = secp256k1::Message::from_slice(digest.as_ref()) {
|
||||||
if let Ok(pubkey) = XOnlyPublicKey::from_str(&self.pubkey) {
|
if let Ok(pubkey) = XOnlyPublicKey::from_str(&self.pubkey) {
|
||||||
let verify = SECP.verify_schnorr(&sig, &msg, &pubkey);
|
SECP.verify_schnorr(&sig, &msg, &pubkey)
|
||||||
matches!(verify, Ok(()))
|
.map_err(|_| EventInvalidSignature)
|
||||||
} else {
|
} else {
|
||||||
debug!("client sent malformed pubkey");
|
debug!("client sent malformed pubkey");
|
||||||
false
|
Err(EventMalformedPubkey)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("error converting digest to secp256k1 message");
|
info!("error converting digest to secp256k1 message");
|
||||||
false
|
Err(EventInvalidSignature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -572,6 +572,7 @@ async fn nostr_server(
|
||||||
Ok(NostrMessage::EventMsg(ec)) => {
|
Ok(NostrMessage::EventMsg(ec)) => {
|
||||||
// An EventCmd needs to be validated to be converted into an Event
|
// An EventCmd needs to be validated to be converted into an Event
|
||||||
// handle each type of message
|
// handle each type of message
|
||||||
|
let evid = ec.event_id().to_owned();
|
||||||
let parsed : Result<Event> = Result::<Event>::from(ec);
|
let parsed : Result<Event> = Result::<Event>::from(ec);
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok(e) => {
|
Ok(e) => {
|
||||||
|
@ -592,9 +593,9 @@ async fn nostr_server(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
info!("client: {} sent an invalid event", cid);
|
info!("client: {} sent an invalid event", cid);
|
||||||
ws_stream.send(make_notice_message(Notice::message("event was invalid".into()))).await.ok();
|
ws_stream.send(make_notice_message(Notice::invalid(evid, &format!("{}", e)))).await.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user