nostr-rs-relay

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

delegation.rs (13765B)


      1 //! Event parsing and validation
      2 use crate::error::Error;
      3 use crate::error::Result;
      4 use crate::event::Event;
      5 use bitcoin_hashes::{sha256, Hash};
      6 use lazy_static::lazy_static;
      7 use regex::Regex;
      8 use secp256k1::{schnorr, Secp256k1, VerifyOnly, XOnlyPublicKey};
      9 use serde::{Deserialize, Serialize};
     10 use std::str::FromStr;
     11 use tracing::{debug, info};
     12 
     13 // This handles everything related to delegation, in particular the
     14 // condition/rune parsing and logic.
     15 
     16 // Conditions are poorly specified, so we will implement the minimum
     17 // necessary for now.
     18 
     19 // fields MUST be either "kind" or "created_at".
     20 // operators supported are ">", "<", "=", "!".
     21 // no operations on 'content' are supported.
     22 
     23 // this allows constraints for:
     24 // valid date ranges (valid from X->Y dates).
     25 // specific kinds (publish kind=1,5)
     26 // kind ranges (publish ephemeral events, kind>19999&kind<30001)
     27 
     28 // for more complex scenarios (allow delegatee to publish ephemeral
     29 // AND replacement events), it may be necessary to generate and use
     30 // different condition strings, since we do not support grouping or
     31 // "OR" logic.
     32 
     33 lazy_static! {
     34     /// Secp256k1 verification instance.
     35     pub static ref SECP: Secp256k1<VerifyOnly> = Secp256k1::verification_only();
     36 }
     37 
     38 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
     39 pub enum Field {
     40     Kind,
     41     CreatedAt,
     42 }
     43 
     44 impl FromStr for Field {
     45     type Err = Error;
     46     fn from_str(value: &str) -> Result<Self, Self::Err> {
     47         if value == "kind" {
     48             Ok(Field::Kind)
     49         } else if value == "created_at" {
     50             Ok(Field::CreatedAt)
     51         } else {
     52             Err(Error::DelegationParseError)
     53         }
     54     }
     55 }
     56 
     57 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
     58 pub enum Operator {
     59     LessThan,
     60     GreaterThan,
     61     Equals,
     62     NotEquals,
     63 }
     64 impl FromStr for Operator {
     65     type Err = Error;
     66     fn from_str(value: &str) -> Result<Self, Self::Err> {
     67         if value == "<" {
     68             Ok(Operator::LessThan)
     69         } else if value == ">" {
     70             Ok(Operator::GreaterThan)
     71         } else if value == "=" {
     72             Ok(Operator::Equals)
     73         } else if value == "!" {
     74             Ok(Operator::NotEquals)
     75         } else {
     76             Err(Error::DelegationParseError)
     77         }
     78     }
     79 }
     80 
     81 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
     82 pub struct ConditionQuery {
     83     pub(crate) conditions: Vec<Condition>,
     84 }
     85 
     86 impl ConditionQuery {
     87     pub fn allows_event(&self, event: &Event) -> bool {
     88         // check each condition, to ensure that the event complies
     89         // with the restriction.
     90         for c in &self.conditions {
     91             if !c.allows_event(event) {
     92                 // any failing conditions invalidates the delegation
     93                 // on this event
     94                 return false;
     95             }
     96         }
     97         // delegation was permitted unconditionally, or all conditions
     98         // were true
     99         true
    100     }
    101 }
    102 
    103 // Verify that the delegator approved the delegation; return a ConditionQuery if so.
    104 pub fn validate_delegation(
    105     delegator: &str,
    106     delegatee: &str,
    107     cond_query: &str,
    108     sigstr: &str,
    109 ) -> Option<ConditionQuery> {
    110     // form the token
    111     let tok = format!("nostr:delegation:{}:{}", delegatee, cond_query);
    112     // form SHA256 hash
    113     let digest: sha256::Hash = sha256::Hash::hash(tok.as_bytes());
    114     let sig = schnorr::Signature::from_str(sigstr).unwrap();
    115     if let Ok(msg) = secp256k1::Message::from_slice(digest.as_ref()) {
    116         if let Ok(pubkey) = XOnlyPublicKey::from_str(delegator) {
    117             let verify = SECP.verify_schnorr(&sig, &msg, &pubkey);
    118             if verify.is_ok() {
    119                 // return the parsed condition query
    120                 cond_query.parse::<ConditionQuery>().ok()
    121             } else {
    122                 debug!("client sent an delegation signature that did not validate");
    123                 None
    124             }
    125         } else {
    126             debug!("client sent malformed delegation pubkey");
    127             None
    128         }
    129     } else {
    130         info!("error converting delegation digest to secp256k1 message");
    131         None
    132     }
    133 }
    134 
    135 /// Parsed delegation condition
    136 /// see https://github.com/nostr-protocol/nips/pull/28#pullrequestreview-1084903800
    137 /// An example complex condition would be:  kind=1,2,3&created_at<1665265999
    138 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)]
    139 pub struct Condition {
    140     pub(crate) field: Field,
    141     pub(crate) operator: Operator,
    142     pub(crate) values: Vec<u64>,
    143 }
    144 
    145 impl Condition {
    146     /// Check if this condition allows the given event to be delegated
    147     pub fn allows_event(&self, event: &Event) -> bool {
    148         // determine what the right-hand side of the operator is
    149         let resolved_field = match &self.field {
    150             Field::Kind => event.kind,
    151             Field::CreatedAt => event.created_at,
    152         };
    153         match &self.operator {
    154             Operator::LessThan => {
    155                 // the less-than operator is only valid for single values.
    156                 if self.values.len() == 1 {
    157                     if let Some(v) = self.values.first() {
    158                         return resolved_field < *v;
    159                     }
    160                 }
    161             }
    162             Operator::GreaterThan => {
    163                 // the greater-than operator is only valid for single values.
    164                 if self.values.len() == 1 {
    165                     if let Some(v) = self.values.first() {
    166                         return resolved_field > *v;
    167                     }
    168                 }
    169             }
    170             Operator::Equals => {
    171                 // equals is interpreted as "must be equal to at least one provided value"
    172                 return self.values.iter().any(|&x| resolved_field == x);
    173             }
    174             Operator::NotEquals => {
    175                 // not-equals is interpreted as "must not be equal to any provided value"
    176                 // this is the one case where an empty list of values could be allowed; even though it is a pointless restriction.
    177                 return self.values.iter().all(|&x| resolved_field != x);
    178             }
    179         }
    180         false
    181     }
    182 }
    183 
    184 fn str_to_condition(cs: &str) -> Option<Condition> {
    185     // a condition is a string (alphanum+underscore), an operator (<>=!), and values (num+comma)
    186     lazy_static! {
    187         static ref RE: Regex = Regex::new("([[:word:]]+)([<>=!]+)([,[[:digit:]]]*)").unwrap();
    188     }
    189     // match against the regex
    190     let caps = RE.captures(cs)?;
    191     let field = caps.get(1)?.as_str().parse::<Field>().ok()?;
    192     let operator = caps.get(2)?.as_str().parse::<Operator>().ok()?;
    193     // values are just comma separated numbers, but all must be parsed
    194     let rawvals = caps.get(3)?.as_str();
    195     let values = rawvals
    196         .split_terminator(',')
    197         .map(|n| n.parse::<u64>().ok())
    198         .collect::<Option<Vec<_>>>()?;
    199     // convert field string into Field
    200     Some(Condition {
    201         field,
    202         operator,
    203         values,
    204     })
    205 }
    206 
    207 /// Parse a condition query from a string slice
    208 impl FromStr for ConditionQuery {
    209     type Err = Error;
    210     fn from_str(value: &str) -> Result<Self, Self::Err> {
    211         // split the string with '&'
    212         let mut conditions = vec![];
    213         let condstrs = value.split_terminator('&');
    214         // parse each individual condition
    215         for c in condstrs {
    216             conditions.push(str_to_condition(c).ok_or(Error::DelegationParseError)?);
    217         }
    218         Ok(ConditionQuery { conditions })
    219     }
    220 }
    221 
    222 #[cfg(test)]
    223 mod tests {
    224     use super::*;
    225 
    226     // parse condition strings
    227     #[test]
    228     fn parse_empty() -> Result<()> {
    229         // given an empty condition query, produce an empty vector
    230         let empty_cq = ConditionQuery { conditions: vec![] };
    231         let parsed = "".parse::<ConditionQuery>()?;
    232         assert_eq!(parsed, empty_cq);
    233         Ok(())
    234     }
    235 
    236     // parse field 'kind'
    237     #[test]
    238     fn test_kind_field_parse() -> Result<()> {
    239         let field = "kind".parse::<Field>()?;
    240         assert_eq!(field, Field::Kind);
    241         Ok(())
    242     }
    243     // parse field 'created_at'
    244     #[test]
    245     fn test_created_at_field_parse() -> Result<()> {
    246         let field = "created_at".parse::<Field>()?;
    247         assert_eq!(field, Field::CreatedAt);
    248         Ok(())
    249     }
    250     // parse unknown field
    251     #[test]
    252     fn unknown_field_parse() {
    253         let field = "unk".parse::<Field>();
    254         assert!(field.is_err());
    255     }
    256 
    257     // parse a full conditional query with an empty array
    258     #[test]
    259     fn parse_kind_equals_empty() -> Result<()> {
    260         // given an empty condition query, produce an empty vector
    261         let kind_cq = ConditionQuery {
    262             conditions: vec![Condition {
    263                 field: Field::Kind,
    264                 operator: Operator::Equals,
    265                 values: vec![],
    266             }],
    267         };
    268         let parsed = "kind=".parse::<ConditionQuery>()?;
    269         assert_eq!(parsed, kind_cq);
    270         Ok(())
    271     }
    272     // parse a full conditional query with a single value
    273     #[test]
    274     fn parse_kind_equals_singleval() -> Result<()> {
    275         // given an empty condition query, produce an empty vector
    276         let kind_cq = ConditionQuery {
    277             conditions: vec![Condition {
    278                 field: Field::Kind,
    279                 operator: Operator::Equals,
    280                 values: vec![1],
    281             }],
    282         };
    283         let parsed = "kind=1".parse::<ConditionQuery>()?;
    284         assert_eq!(parsed, kind_cq);
    285         Ok(())
    286     }
    287     // parse a full conditional query with multiple values
    288     #[test]
    289     fn parse_kind_equals_multival() -> Result<()> {
    290         // given an empty condition query, produce an empty vector
    291         let kind_cq = ConditionQuery {
    292             conditions: vec![Condition {
    293                 field: Field::Kind,
    294                 operator: Operator::Equals,
    295                 values: vec![1, 2, 4],
    296             }],
    297         };
    298         let parsed = "kind=1,2,4".parse::<ConditionQuery>()?;
    299         assert_eq!(parsed, kind_cq);
    300         Ok(())
    301     }
    302     // parse multiple conditions
    303     #[test]
    304     fn parse_multi_conditions() -> Result<()> {
    305         // given an empty condition query, produce an empty vector
    306         let cq = ConditionQuery {
    307             conditions: vec![
    308                 Condition {
    309                     field: Field::Kind,
    310                     operator: Operator::GreaterThan,
    311                     values: vec![10000],
    312                 },
    313                 Condition {
    314                     field: Field::Kind,
    315                     operator: Operator::LessThan,
    316                     values: vec![20000],
    317                 },
    318                 Condition {
    319                     field: Field::Kind,
    320                     operator: Operator::NotEquals,
    321                     values: vec![10001],
    322                 },
    323                 Condition {
    324                     field: Field::CreatedAt,
    325                     operator: Operator::LessThan,
    326                     values: vec![1665867123],
    327                 },
    328             ],
    329         };
    330         let parsed =
    331             "kind>10000&kind<20000&kind!10001&created_at<1665867123".parse::<ConditionQuery>()?;
    332         assert_eq!(parsed, cq);
    333         Ok(())
    334     }
    335     fn simple_event() -> Event {
    336         Event {
    337             id: "0".to_owned(),
    338             pubkey: "0".to_owned(),
    339             delegated_by: None,
    340             created_at: 0,
    341             kind: 0,
    342             tags: vec![],
    343             content: "".to_owned(),
    344             sig: "0".to_owned(),
    345             tagidx: None,
    346         }
    347     }
    348     // Check for condition logic on event w/ empty values
    349     #[test]
    350     fn condition_with_empty_values() {
    351         let mut c = Condition {
    352             field: Field::Kind,
    353             operator: Operator::GreaterThan,
    354             values: vec![],
    355         };
    356         let e = simple_event();
    357         assert!(!c.allows_event(&e));
    358         c.operator = Operator::LessThan;
    359         assert!(!c.allows_event(&e));
    360         c.operator = Operator::Equals;
    361         assert!(!c.allows_event(&e));
    362         // Not Equals applied to an empty list *is* allowed
    363         // (pointless, but logically valid).
    364         c.operator = Operator::NotEquals;
    365         assert!(c.allows_event(&e));
    366     }
    367 
    368     // Check for condition logic on event w/ single value
    369     #[test]
    370     fn condition_kind_gt_event_single() {
    371         let c = Condition {
    372             field: Field::Kind,
    373             operator: Operator::GreaterThan,
    374             values: vec![10],
    375         };
    376         let mut e = simple_event();
    377         // kind is not greater than 10, not allowed
    378         e.kind = 1;
    379         assert!(!c.allows_event(&e));
    380         // kind is greater than 10, allowed
    381         e.kind = 100;
    382         assert!(c.allows_event(&e));
    383         // kind is 10, not allowed
    384         e.kind = 10;
    385         assert!(!c.allows_event(&e));
    386     }
    387     // Check for condition logic on event w/ multi values
    388     #[test]
    389     fn condition_with_multi_values() {
    390         let mut c = Condition {
    391             field: Field::Kind,
    392             operator: Operator::Equals,
    393             values: vec![0, 10, 20],
    394         };
    395         let mut e = simple_event();
    396         // Allow if event kind is in list for Equals
    397         e.kind = 10;
    398         assert!(c.allows_event(&e));
    399         // Deny if event kind is not in list for Equals
    400         e.kind = 11;
    401         assert!(!c.allows_event(&e));
    402         // Deny if event kind is in list for NotEquals
    403         e.kind = 10;
    404         c.operator = Operator::NotEquals;
    405         assert!(!c.allows_event(&e));
    406         // Allow if event kind is not in list for NotEquals
    407         e.kind = 99;
    408         c.operator = Operator::NotEquals;
    409         assert!(c.allows_event(&e));
    410         // Always deny if GreaterThan/LessThan for a list
    411         c.operator = Operator::LessThan;
    412         assert!(!c.allows_event(&e));
    413         c.operator = Operator::GreaterThan;
    414         assert!(!c.allows_event(&e));
    415     }
    416 }