diff --git a/src/delegation.rs b/src/delegation.rs index f862a4e..99134ee 100644 --- a/src/delegation.rs +++ b/src/delegation.rs @@ -1,18 +1,13 @@ //! Event parsing and validation use crate::error::Error; use crate::error::Result; -//use crate::utils::unix_time; -//use bitcoin_hashes::{sha256, Hash}; +use bitcoin_hashes::{sha256, Hash}; use lazy_static::lazy_static; use regex::Regex; -//use secp256k1::{schnorr, Secp256k1, VerifyOnly, XOnlyPublicKey}; +use secp256k1::{schnorr, Secp256k1, VerifyOnly, XOnlyPublicKey}; use serde::{Deserialize, Serialize}; -//use serde_json::value::Value; -//use serde_json::Number; -//use std::collections::HashMap; -//use std::collections::HashSet; use std::str::FromStr; -//use tracing::{debug, info}; +use tracing::{debug, info}; // This handles everything related to delegation, in particular the // condition/rune parsing and logic. @@ -38,6 +33,11 @@ use std::str::FromStr; // condition string. We will then map that with a deserializer that // maps to a ConditionQuery. +lazy_static! { + /// Secp256k1 verification instance. + pub static ref SECP: Secp256k1 = Secp256k1::verification_only(); +} + #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub enum Field { Kind, @@ -86,12 +86,34 @@ pub struct ConditionQuery { pub(crate) conditions: Vec, } -/// Parsed delegation statement -#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] -pub struct Delegation { - pub(crate) pubkey: String, - pub(crate) condition_query: ConditionQuery, - pub(crate) signature: String, +// Verify that the delegator approved the delegation; return a ConditionQuery if so. +pub fn validate_delegation( + delegator: &str, + delegatee: &str, + cond_query: &str, + sigstr: &str, +) -> Option { + // form the token + let tok = format!("nostr:delegation:{}:{}", delegatee, cond_query); + // form SHA256 hash + let digest: sha256::Hash = sha256::Hash::hash(tok.as_bytes()); + let sig = schnorr::Signature::from_str(sigstr).unwrap(); + if let Ok(msg) = secp256k1::Message::from_slice(digest.as_ref()) { + if let Ok(pubkey) = XOnlyPublicKey::from_str(delegator) { + let verify = SECP.verify_schnorr(&sig, &msg, &pubkey); + if verify.is_ok() { + Some(ConditionQuery { conditions: vec![] }) + } else { + None + } + } else { + debug!("client sent malformed pubkey"); + None + } + } else { + info!("error converting digest to secp256k1 message"); + None + } } /// Parsed delegation condition diff --git a/src/event.rs b/src/event.rs index 3f2098d..fee4a33 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,4 +1,5 @@ //! Event parsing and validation +use crate::delegation::validate_delegation; use crate::error::Error::*; use crate::error::Result; use crate::nip05; @@ -112,10 +113,19 @@ impl Event { // is this event delegated (properly)? // does the signature match, and are conditions valid? - pub fn is_delegated(&self) -> bool { + // if so, return an alternate author for the event + pub fn delegated_author(&self) -> Option { // is there a delegation tag? - let _delegation_tag = self.tag_values_by_name("delegation"); + let delegation_tag = self.tag_values_by_name("delegation"); // delegation tags should have exactly 3 elements after the name (pubkey, condition, sig) + // the event is signed by the delagatee + let delegatee = &self.pubkey; + // the delegation tag references the claimed delagator + let delegator = delegation_tag.get(0)?; + let querystr = delegation_tag.get(1)?; + let sig = delegation_tag.get(2)?; + // pass into the validate_delegation + validate_delegation(delegator, delegatee, querystr, sig); // try to construct a delegation object ( todo!(); }