wip: tests, clippy

This commit is contained in:
Greg Heartsfield 2022-10-16 12:59:36 -05:00
parent 2eee827d39
commit b95a62bd91
2 changed files with 140 additions and 5 deletions

View File

@ -1,6 +1,7 @@
//! Event parsing and validation //! Event parsing and validation
use crate::error::Error; use crate::error::Error;
use crate::error::Result; use crate::error::Result;
use crate::event::Event;
use bitcoin_hashes::{sha256, Hash}; use bitcoin_hashes::{sha256, Hash};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
@ -86,6 +87,14 @@ pub struct ConditionQuery {
pub(crate) conditions: Vec<Condition>, pub(crate) conditions: Vec<Condition>,
} }
impl ConditionQuery {
pub fn allows_event(&self, _event: &Event) -> bool {
// check each condition, to ensure that the event complies with the restriction.
false
}
}
// Verify that the delegator approved the delegation; return a ConditionQuery if so. // Verify that the delegator approved the delegation; return a ConditionQuery if so.
pub fn validate_delegation( pub fn validate_delegation(
delegator: &str, delegator: &str,
@ -125,7 +134,46 @@ pub fn validate_delegation(
pub struct Condition { pub struct Condition {
pub(crate) field: Field, pub(crate) field: Field,
pub(crate) operator: Operator, pub(crate) operator: Operator,
pub(crate) values: Vec<usize>, pub(crate) values: Vec<u64>,
}
impl Condition {
/// Check if this condition allows the given event to be delegated
pub fn allows_event(&self, event: &Event) -> bool {
// determine what the right-hand side of the operator is
let resolved_field = match &self.field {
Field::Kind => event.kind,
Field::CreatedAt => event.created_at,
};
match &self.operator {
Operator::LessThan => {
// the less-than operator is only valid for single values.
if self.values.len() == 1 {
if let Some(v) = self.values.first() {
return resolved_field < *v;
}
}
}
Operator::GreaterThan => {
// the greater-than operator is only valid for single values.
if self.values.len() == 1 {
if let Some(v) = self.values.first() {
return resolved_field > *v;
}
}
}
Operator::Equals => {
// equals is interpreted as "must be equal to at least one provided value"
return self.values.iter().any(|&x| resolved_field == x);
}
Operator::NotEquals => {
// not-equals is interpreted as "must not be equal to any provided value"
// this is the one case where an empty list of values could be allowed; even though it is a pointless restriction.
return self.values.iter().all(|&x| resolved_field != x);
}
}
false
}
} }
fn str_to_condition(cs: &str) -> Option<Condition> { fn str_to_condition(cs: &str) -> Option<Condition> {
@ -141,7 +189,7 @@ fn str_to_condition(cs: &str) -> Option<Condition> {
let rawvals = caps.get(3)?.as_str(); let rawvals = caps.get(3)?.as_str();
let values = rawvals let values = rawvals
.split_terminator(',') .split_terminator(',')
.map(|n| n.parse::<usize>().ok()) .map(|n| n.parse::<u64>().ok())
.collect::<Option<Vec<_>>>()?; .collect::<Option<Vec<_>>>()?;
// convert field string into Field // convert field string into Field
Some(Condition { Some(Condition {
@ -279,4 +327,84 @@ mod tests {
assert_eq!(parsed, cq); assert_eq!(parsed, cq);
Ok(()) Ok(())
} }
fn simple_event() -> Event {
Event {
id: "0".to_owned(),
pubkey: "0".to_owned(),
created_at: 0,
kind: 0,
tags: vec![],
content: "".to_owned(),
sig: "0".to_owned(),
tagidx: None,
}
}
// Check for condition logic on event w/ empty values
#[test]
fn condition_with_empty_values() {
let mut c = Condition {
field: Field::Kind,
operator: Operator::GreaterThan,
values: vec![],
};
let e = simple_event();
assert!(!c.allows_event(&e));
c.operator = Operator::LessThan;
assert!(!c.allows_event(&e));
c.operator = Operator::Equals;
assert!(!c.allows_event(&e));
// Not Equals applied to an empty list *is* allowed
// (pointless, but logically valid).
c.operator = Operator::NotEquals;
assert!(c.allows_event(&e));
}
// Check for condition logic on event w/ single value
#[test]
fn condition_kind_gt_event_single() {
let c = Condition {
field: Field::Kind,
operator: Operator::GreaterThan,
values: vec![10],
};
let mut e = simple_event();
// kind is not greater than 10, not allowed
e.kind = 1;
assert!(!c.allows_event(&e));
// kind is greater than 10, allowed
e.kind = 100;
assert!(c.allows_event(&e));
// kind is 10, not allowed
e.kind = 10;
assert!(!c.allows_event(&e));
}
// Check for condition logic on event w/ multi values
#[test]
fn condition_with_multi_values() {
let mut c = Condition {
field: Field::Kind,
operator: Operator::Equals,
values: vec![0, 10, 20],
};
let mut e = simple_event();
// Allow if event kind is in list for Equals
e.kind = 10;
assert!(c.allows_event(&e));
// Deny if event kind is not in list for Equals
e.kind = 11;
assert!(!c.allows_event(&e));
// Deny if event kind is in list for NotEquals
e.kind = 10;
c.operator = Operator::NotEquals;
assert!(!c.allows_event(&e));
// Allow if event kind is not in list for NotEquals
e.kind = 99;
c.operator = Operator::NotEquals;
assert!(c.allows_event(&e));
// Always deny if GreaterThan/LessThan for a list
c.operator = Operator::LessThan;
assert!(!c.allows_event(&e));
c.operator = Operator::GreaterThan;
assert!(!c.allows_event(&e));
}
} }

View File

@ -125,9 +125,16 @@ impl Event {
let querystr = delegation_tag.get(1)?; let querystr = delegation_tag.get(1)?;
let sig = delegation_tag.get(2)?; let sig = delegation_tag.get(2)?;
// pass into the validate_delegation // pass into the validate_delegation
validate_delegation(delegator, delegatee, querystr, sig); if let Some(cond_query) = validate_delegation(delegator, delegatee, querystr, sig) {
// try to construct a delegation object ( // check if this condition query would allow this event.
todo!(); if cond_query.allows_event(self) {
Some(delegator.into())
} else {
None
}
} else {
None
}
} }
/// Build an event tag index /// Build an event tag index