tangle


git clone https://radroots.dev/git/tangle.git
Log | Files | Refs | README | LICENSE

rate_limits.rs (22343B)


      1 #![forbid(unsafe_code)]
      2 
      3 use crate::errors::BaseRelayError;
      4 use std::{
      5     collections::BTreeMap,
      6     net::IpAddr,
      7     sync::{Arc, Mutex},
      8 };
      9 use tangle_groups::GroupId;
     10 use tangle_protocol::{Kind, PublicKeyHex, UnixTimestamp};
     11 
     12 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
     13 pub enum TangleRateLimitScope {
     14     Auth,
     15     Event,
     16     GroupWrite,
     17     Req,
     18     Count,
     19 }
     20 
     21 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     22 pub enum TangleRateLimitKey {
     23     Ip {
     24         scope: TangleRateLimitScope,
     25         ip: IpAddr,
     26     },
     27     Pubkey {
     28         scope: TangleRateLimitScope,
     29         pubkey: PublicKeyHex,
     30     },
     31     Group {
     32         scope: TangleRateLimitScope,
     33         group_id: GroupId,
     34     },
     35     Kind {
     36         scope: TangleRateLimitScope,
     37         kind: Kind,
     38     },
     39     AuthFailure {
     40         ip: Option<IpAddr>,
     41         pubkey: Option<PublicKeyHex>,
     42     },
     43     JoinFlowIp {
     44         group_id: GroupId,
     45         ip: IpAddr,
     46     },
     47     JoinFlow {
     48         group_id: GroupId,
     49         pubkey: PublicKeyHex,
     50     },
     51     Connection {
     52         scope: TangleRateLimitScope,
     53         connection_id: u64,
     54     },
     55     QueryClass {
     56         scope: TangleRateLimitScope,
     57         class: TangleRateLimitQueryClass,
     58     },
     59 }
     60 
     61 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
     62 pub enum TangleRateLimitQueryClass {
     63     Broad,
     64 }
     65 
     66 impl TangleRateLimitKey {
     67     pub fn ip(scope: TangleRateLimitScope, ip: IpAddr) -> Self {
     68         Self::Ip { scope, ip }
     69     }
     70 
     71     pub fn pubkey(scope: TangleRateLimitScope, pubkey: PublicKeyHex) -> Self {
     72         Self::Pubkey { scope, pubkey }
     73     }
     74 
     75     pub fn group(scope: TangleRateLimitScope, group_id: GroupId) -> Self {
     76         Self::Group { scope, group_id }
     77     }
     78 
     79     pub fn kind(scope: TangleRateLimitScope, kind: Kind) -> Self {
     80         Self::Kind { scope, kind }
     81     }
     82 
     83     pub fn auth_failure(ip: Option<IpAddr>, pubkey: Option<PublicKeyHex>) -> Self {
     84         Self::AuthFailure { ip, pubkey }
     85     }
     86 
     87     pub fn join_flow(group_id: GroupId, pubkey: PublicKeyHex) -> Self {
     88         Self::JoinFlow { group_id, pubkey }
     89     }
     90 
     91     pub fn join_flow_ip(group_id: GroupId, ip: IpAddr) -> Self {
     92         Self::JoinFlowIp { group_id, ip }
     93     }
     94 
     95     pub fn connection(scope: TangleRateLimitScope, connection_id: u64) -> Self {
     96         Self::Connection {
     97             scope,
     98             connection_id,
     99         }
    100     }
    101 
    102     pub fn query_class(scope: TangleRateLimitScope, class: TangleRateLimitQueryClass) -> Self {
    103         Self::QueryClass { scope, class }
    104     }
    105 }
    106 
    107 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    108 pub struct TangleRateLimitConfig {
    109     auth: TangleAuthRateLimitConfig,
    110     event: TangleEventRateLimitConfig,
    111     group: TangleGroupRateLimitConfig,
    112     req: TangleQueryRateLimitConfig,
    113     count: TangleQueryRateLimitConfig,
    114 }
    115 
    116 impl TangleRateLimitConfig {
    117     pub fn new(
    118         auth: TangleAuthRateLimitConfig,
    119         event: TangleEventRateLimitConfig,
    120         group: TangleGroupRateLimitConfig,
    121         req: TangleQueryRateLimitConfig,
    122         count: TangleQueryRateLimitConfig,
    123     ) -> Self {
    124         Self {
    125             auth,
    126             event,
    127             group,
    128             req,
    129             count,
    130         }
    131     }
    132 
    133     pub fn auth(self) -> TangleAuthRateLimitConfig {
    134         self.auth
    135     }
    136 
    137     pub fn event(self) -> TangleEventRateLimitConfig {
    138         self.event
    139     }
    140 
    141     pub fn group(self) -> TangleGroupRateLimitConfig {
    142         self.group
    143     }
    144 
    145     pub fn req(self) -> TangleQueryRateLimitConfig {
    146         self.req
    147     }
    148 
    149     pub fn count(self) -> TangleQueryRateLimitConfig {
    150         self.count
    151     }
    152 }
    153 
    154 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    155 pub struct TangleAuthRateLimitConfig {
    156     per_ip: TangleRateLimitRule,
    157     per_pubkey: TangleRateLimitRule,
    158     failures: TangleRateLimitRule,
    159     failures_per_ip: TangleRateLimitRule,
    160 }
    161 
    162 impl TangleAuthRateLimitConfig {
    163     pub fn new(
    164         per_ip: TangleRateLimitRule,
    165         per_pubkey: TangleRateLimitRule,
    166         failures: TangleRateLimitRule,
    167         failures_per_ip: TangleRateLimitRule,
    168     ) -> Self {
    169         Self {
    170             per_ip,
    171             per_pubkey,
    172             failures,
    173             failures_per_ip,
    174         }
    175     }
    176 
    177     pub fn per_ip(self) -> TangleRateLimitRule {
    178         self.per_ip
    179     }
    180 
    181     pub fn per_pubkey(self) -> TangleRateLimitRule {
    182         self.per_pubkey
    183     }
    184 
    185     pub fn failures(self) -> TangleRateLimitRule {
    186         self.failures
    187     }
    188 
    189     pub fn failures_per_ip(self) -> TangleRateLimitRule {
    190         self.failures_per_ip
    191     }
    192 }
    193 
    194 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    195 pub struct TangleEventRateLimitConfig {
    196     per_ip: TangleRateLimitRule,
    197     per_pubkey: TangleRateLimitRule,
    198     per_kind: TangleRateLimitRule,
    199 }
    200 
    201 impl TangleEventRateLimitConfig {
    202     pub fn new(
    203         per_ip: TangleRateLimitRule,
    204         per_pubkey: TangleRateLimitRule,
    205         per_kind: TangleRateLimitRule,
    206     ) -> Self {
    207         Self {
    208             per_ip,
    209             per_pubkey,
    210             per_kind,
    211         }
    212     }
    213 
    214     pub fn per_ip(self) -> TangleRateLimitRule {
    215         self.per_ip
    216     }
    217 
    218     pub fn per_pubkey(self) -> TangleRateLimitRule {
    219         self.per_pubkey
    220     }
    221 
    222     pub fn per_kind(self) -> TangleRateLimitRule {
    223         self.per_kind
    224     }
    225 }
    226 
    227 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    228 pub struct TangleGroupRateLimitConfig {
    229     write_per_ip: TangleRateLimitRule,
    230     write_per_pubkey: TangleRateLimitRule,
    231     write_per_group: TangleRateLimitRule,
    232     write_per_kind: TangleRateLimitRule,
    233     join_flow: TangleRateLimitRule,
    234     join_flow_per_ip: TangleRateLimitRule,
    235 }
    236 
    237 impl TangleGroupRateLimitConfig {
    238     pub fn new(
    239         write_per_ip: TangleRateLimitRule,
    240         write_per_pubkey: TangleRateLimitRule,
    241         write_per_group: TangleRateLimitRule,
    242         write_per_kind: TangleRateLimitRule,
    243         join_flow: TangleRateLimitRule,
    244         join_flow_per_ip: TangleRateLimitRule,
    245     ) -> Self {
    246         Self {
    247             write_per_ip,
    248             write_per_pubkey,
    249             write_per_group,
    250             write_per_kind,
    251             join_flow,
    252             join_flow_per_ip,
    253         }
    254     }
    255 
    256     pub fn write_per_ip(self) -> TangleRateLimitRule {
    257         self.write_per_ip
    258     }
    259 
    260     pub fn write_per_pubkey(self) -> TangleRateLimitRule {
    261         self.write_per_pubkey
    262     }
    263 
    264     pub fn write_per_group(self) -> TangleRateLimitRule {
    265         self.write_per_group
    266     }
    267 
    268     pub fn write_per_kind(self) -> TangleRateLimitRule {
    269         self.write_per_kind
    270     }
    271 
    272     pub fn join_flow(self) -> TangleRateLimitRule {
    273         self.join_flow
    274     }
    275 
    276     pub fn join_flow_per_ip(self) -> TangleRateLimitRule {
    277         self.join_flow_per_ip
    278     }
    279 }
    280 
    281 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    282 pub struct TangleQueryRateLimitConfig {
    283     per_ip: TangleRateLimitRule,
    284     per_connection: TangleRateLimitRule,
    285     per_pubkey: TangleRateLimitRule,
    286     per_group: TangleRateLimitRule,
    287     per_kind: TangleRateLimitRule,
    288     broad: TangleRateLimitRule,
    289 }
    290 
    291 impl TangleQueryRateLimitConfig {
    292     pub fn new(
    293         per_ip: TangleRateLimitRule,
    294         per_connection: TangleRateLimitRule,
    295         per_pubkey: TangleRateLimitRule,
    296         per_group: TangleRateLimitRule,
    297         per_kind: TangleRateLimitRule,
    298         broad: TangleRateLimitRule,
    299     ) -> Self {
    300         Self {
    301             per_ip,
    302             per_connection,
    303             per_pubkey,
    304             per_group,
    305             per_kind,
    306             broad,
    307         }
    308     }
    309 
    310     pub fn per_ip(self) -> TangleRateLimitRule {
    311         self.per_ip
    312     }
    313 
    314     pub fn per_connection(self) -> TangleRateLimitRule {
    315         self.per_connection
    316     }
    317 
    318     pub fn per_pubkey(self) -> TangleRateLimitRule {
    319         self.per_pubkey
    320     }
    321 
    322     pub fn per_group(self) -> TangleRateLimitRule {
    323         self.per_group
    324     }
    325 
    326     pub fn per_kind(self) -> TangleRateLimitRule {
    327         self.per_kind
    328     }
    329 
    330     pub fn broad(self) -> TangleRateLimitRule {
    331         self.broad
    332     }
    333 }
    334 
    335 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    336 pub struct TangleRateLimitRule {
    337     window_seconds: u64,
    338     max_hits: u64,
    339 }
    340 
    341 impl TangleRateLimitRule {
    342     pub fn new(window_seconds: u64, max_hits: u64) -> Result<Self, BaseRelayError> {
    343         if window_seconds == 0 {
    344             return Err(BaseRelayError::invalid(
    345                 "rate limit window seconds must be greater than zero",
    346             ));
    347         }
    348         if max_hits == 0 {
    349             return Err(BaseRelayError::invalid(
    350                 "rate limit max hits must be greater than zero",
    351             ));
    352         }
    353         Ok(Self {
    354             window_seconds,
    355             max_hits,
    356         })
    357     }
    358 
    359     pub fn window_seconds(self) -> u64 {
    360         self.window_seconds
    361     }
    362 
    363     pub fn max_hits(self) -> u64 {
    364         self.max_hits
    365     }
    366 }
    367 
    368 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    369 pub enum TangleRateLimitDecision {
    370     Allowed {
    371         remaining: u64,
    372         reset_at: UnixTimestamp,
    373     },
    374     Rejected {
    375         reset_at: UnixTimestamp,
    376     },
    377 }
    378 
    379 impl TangleRateLimitDecision {
    380     pub fn is_allowed(self) -> bool {
    381         matches!(self, Self::Allowed { .. })
    382     }
    383 
    384     pub fn reset_at(self) -> UnixTimestamp {
    385         match self {
    386             Self::Allowed { reset_at, .. } | Self::Rejected { reset_at } => reset_at,
    387         }
    388     }
    389 
    390     pub fn remaining(self) -> u64 {
    391         match self {
    392             Self::Allowed { remaining, .. } => remaining,
    393             Self::Rejected { .. } => 0,
    394         }
    395     }
    396 }
    397 
    398 #[derive(Debug, Clone, Default)]
    399 pub struct TangleRateLimiter {
    400     entries: Arc<Mutex<BTreeMap<TangleRateLimitKey, TangleRateLimitEntry>>>,
    401 }
    402 
    403 impl TangleRateLimiter {
    404     pub fn new() -> Self {
    405         Self::default()
    406     }
    407 
    408     pub fn record(
    409         &self,
    410         key: TangleRateLimitKey,
    411         rule: TangleRateLimitRule,
    412         now: UnixTimestamp,
    413     ) -> TangleRateLimitDecision {
    414         let mut entries = self
    415             .entries
    416             .lock()
    417             .unwrap_or_else(|error| error.into_inner());
    418         let entry = entries
    419             .entry(key)
    420             .and_modify(|entry| entry.reset_if_expired(rule, now))
    421             .or_insert_with(|| TangleRateLimitEntry::new(rule, now));
    422         if entry.hits >= rule.max_hits() {
    423             return TangleRateLimitDecision::Rejected {
    424                 reset_at: entry.reset_at,
    425             };
    426         }
    427         entry.hits = entry.hits.saturating_add(1);
    428         TangleRateLimitDecision::Allowed {
    429             remaining: rule.max_hits().saturating_sub(entry.hits),
    430             reset_at: entry.reset_at,
    431         }
    432     }
    433 
    434     pub fn hits(&self, key: &TangleRateLimitKey) -> u64 {
    435         self.entries
    436             .lock()
    437             .unwrap_or_else(|error| error.into_inner())
    438             .get(key)
    439             .map(|entry| entry.hits)
    440             .unwrap_or(0)
    441     }
    442 
    443     pub fn retain_active(&self, now: UnixTimestamp) {
    444         self.entries
    445             .lock()
    446             .unwrap_or_else(|error| error.into_inner())
    447             .retain(|_, entry| now.as_u64() < entry.reset_at.as_u64());
    448     }
    449 
    450     pub fn tracked_key_count(&self) -> usize {
    451         self.entries
    452             .lock()
    453             .unwrap_or_else(|error| error.into_inner())
    454             .len()
    455     }
    456 }
    457 
    458 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    459 struct TangleRateLimitEntry {
    460     reset_at: UnixTimestamp,
    461     hits: u64,
    462 }
    463 
    464 impl TangleRateLimitEntry {
    465     fn new(rule: TangleRateLimitRule, now: UnixTimestamp) -> Self {
    466         Self {
    467             reset_at: reset_at(rule, now),
    468             hits: 0,
    469         }
    470     }
    471 
    472     fn reset_if_expired(&mut self, rule: TangleRateLimitRule, now: UnixTimestamp) {
    473         if now.as_u64() >= self.reset_at.as_u64() {
    474             *self = Self::new(rule, now);
    475         }
    476     }
    477 }
    478 
    479 fn reset_at(rule: TangleRateLimitRule, now: UnixTimestamp) -> UnixTimestamp {
    480     UnixTimestamp::from(now.as_u64().saturating_add(rule.window_seconds()))
    481 }
    482 
    483 #[cfg(test)]
    484 mod tests {
    485     use super::{
    486         TangleAuthRateLimitConfig, TangleEventRateLimitConfig, TangleGroupRateLimitConfig,
    487         TangleQueryRateLimitConfig, TangleRateLimitConfig, TangleRateLimitDecision,
    488         TangleRateLimitKey, TangleRateLimitQueryClass, TangleRateLimitRule, TangleRateLimitScope,
    489         TangleRateLimiter,
    490     };
    491     use std::net::{IpAddr, Ipv4Addr};
    492     use tangle_groups::GroupId;
    493     use tangle_protocol::{Kind, PublicKeyHex, UnixTimestamp};
    494 
    495     #[test]
    496     fn rate_limit_rules_reject_zero_values() {
    497         assert_eq!(
    498             TangleRateLimitRule::new(0, 1)
    499                 .expect_err("window")
    500                 .prefixed_message(),
    501             "invalid: rate limit window seconds must be greater than zero"
    502         );
    503         assert_eq!(
    504             TangleRateLimitRule::new(1, 0)
    505                 .expect_err("max hits")
    506                 .prefixed_message(),
    507             "invalid: rate limit max hits must be greater than zero"
    508         );
    509     }
    510 
    511     #[test]
    512     fn rate_limiter_tracks_required_key_dimensions() {
    513         let limiter = TangleRateLimiter::new();
    514         let rule = TangleRateLimitRule::new(60, 1).expect("rule");
    515         let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
    516         let pubkey = PublicKeyHex::new(&"1".repeat(64)).expect("pubkey");
    517         let group_id = GroupId::new("farm").expect("group");
    518         let kind = Kind::new(1).expect("kind");
    519         let keys = [
    520             TangleRateLimitKey::ip(TangleRateLimitScope::Event, ip),
    521             TangleRateLimitKey::pubkey(TangleRateLimitScope::Event, pubkey.clone()),
    522             TangleRateLimitKey::group(TangleRateLimitScope::GroupWrite, group_id.clone()),
    523             TangleRateLimitKey::kind(TangleRateLimitScope::Event, kind),
    524             TangleRateLimitKey::auth_failure(Some(ip), Some(pubkey.clone())),
    525             TangleRateLimitKey::join_flow_ip(group_id.clone(), ip),
    526             TangleRateLimitKey::join_flow(group_id, pubkey),
    527             TangleRateLimitKey::connection(TangleRateLimitScope::Req, 42),
    528             TangleRateLimitKey::query_class(
    529                 TangleRateLimitScope::Count,
    530                 TangleRateLimitQueryClass::Broad,
    531             ),
    532         ];
    533 
    534         for key in keys {
    535             assert!(
    536                 limiter
    537                     .record(key.clone(), rule, UnixTimestamp::from(1))
    538                     .is_allowed()
    539             );
    540             assert_eq!(
    541                 limiter.record(key.clone(), rule, UnixTimestamp::from(2)),
    542                 TangleRateLimitDecision::Rejected {
    543                     reset_at: UnixTimestamp::from(61)
    544                 }
    545             );
    546             assert_eq!(limiter.hits(&key), 1);
    547         }
    548         assert_eq!(limiter.tracked_key_count(), 9);
    549     }
    550 
    551     #[test]
    552     fn rate_limiter_counts_per_key_and_resets_after_window() {
    553         let limiter = TangleRateLimiter::new();
    554         let rule = TangleRateLimitRule::new(10, 2).expect("rule");
    555         let key = TangleRateLimitKey::ip(
    556             TangleRateLimitScope::Event,
    557             IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
    558         );
    559 
    560         let first = limiter.record(key.clone(), rule, UnixTimestamp::from(100));
    561         let second = limiter.record(key.clone(), rule, UnixTimestamp::from(101));
    562         let third = limiter.record(key.clone(), rule, UnixTimestamp::from(102));
    563         let after_window = limiter.record(key, rule, UnixTimestamp::from(110));
    564 
    565         assert_eq!(
    566             first,
    567             TangleRateLimitDecision::Allowed {
    568                 remaining: 1,
    569                 reset_at: UnixTimestamp::from(110)
    570             }
    571         );
    572         assert_eq!(
    573             second,
    574             TangleRateLimitDecision::Allowed {
    575                 remaining: 0,
    576                 reset_at: UnixTimestamp::from(110)
    577             }
    578         );
    579         assert_eq!(
    580             third,
    581             TangleRateLimitDecision::Rejected {
    582                 reset_at: UnixTimestamp::from(110)
    583             }
    584         );
    585         assert_eq!(
    586             after_window,
    587             TangleRateLimitDecision::Allowed {
    588                 remaining: 1,
    589                 reset_at: UnixTimestamp::from(120)
    590             }
    591         );
    592     }
    593 
    594     #[test]
    595     fn rate_limiter_drops_expired_key_state() {
    596         let limiter = TangleRateLimiter::new();
    597         let rule = TangleRateLimitRule::new(5, 1).expect("rule");
    598         limiter.record(
    599             TangleRateLimitKey::ip(
    600                 TangleRateLimitScope::Event,
    601                 IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
    602             ),
    603             rule,
    604             UnixTimestamp::from(1),
    605         );
    606         limiter.record(
    607             TangleRateLimitKey::ip(
    608                 TangleRateLimitScope::Event,
    609                 IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)),
    610             ),
    611             rule,
    612             UnixTimestamp::from(5),
    613         );
    614 
    615         limiter.retain_active(UnixTimestamp::from(6));
    616 
    617         assert_eq!(limiter.tracked_key_count(), 1);
    618     }
    619 
    620     #[test]
    621     fn scoped_pubkey_keys_do_not_share_buckets() {
    622         let limiter = TangleRateLimiter::new();
    623         let rule = TangleRateLimitRule::new(60, 1).expect("rule");
    624         let pubkey = PublicKeyHex::new(&"1".repeat(64)).expect("pubkey");
    625         let auth_key = TangleRateLimitKey::pubkey(TangleRateLimitScope::Auth, pubkey.clone());
    626         let event_key = TangleRateLimitKey::pubkey(TangleRateLimitScope::Event, pubkey);
    627 
    628         assert!(
    629             limiter
    630                 .record(auth_key.clone(), rule, UnixTimestamp::from(1))
    631                 .is_allowed()
    632         );
    633         assert!(
    634             limiter
    635                 .record(event_key.clone(), rule, UnixTimestamp::from(1))
    636                 .is_allowed()
    637         );
    638         assert!(
    639             !limiter
    640                 .record(auth_key, rule, UnixTimestamp::from(2))
    641                 .is_allowed()
    642         );
    643         assert!(
    644             !limiter
    645                 .record(event_key, rule, UnixTimestamp::from(2))
    646                 .is_allowed()
    647         );
    648     }
    649 
    650     #[test]
    651     fn rate_limit_config_exposes_auth_and_event_rules() {
    652         let auth_pubkey = TangleRateLimitRule::new(60, 2).expect("auth pubkey");
    653         let auth_failures = TangleRateLimitRule::new(300, 3).expect("auth failures");
    654         let auth_ip = TangleRateLimitRule::new(60, 4).expect("auth ip");
    655         let auth_failures_ip = TangleRateLimitRule::new(300, 5).expect("auth failures ip");
    656         let event_ip = TangleRateLimitRule::new(60, 6).expect("event ip");
    657         let event_pubkey = TangleRateLimitRule::new(60, 7).expect("event pubkey");
    658         let event_kind = TangleRateLimitRule::new(60, 8).expect("event kind");
    659         let group_ip = TangleRateLimitRule::new(60, 9).expect("group ip");
    660         let group_pubkey = TangleRateLimitRule::new(60, 10).expect("group pubkey");
    661         let group_write = TangleRateLimitRule::new(60, 11).expect("group write");
    662         let group_kind = TangleRateLimitRule::new(60, 12).expect("group kind");
    663         let group_join = TangleRateLimitRule::new(300, 13).expect("group join");
    664         let group_join_ip = TangleRateLimitRule::new(300, 14).expect("group join ip");
    665         let req_ip = TangleRateLimitRule::new(60, 15).expect("req ip");
    666         let req_connection = TangleRateLimitRule::new(60, 16).expect("req connection");
    667         let req_pubkey = TangleRateLimitRule::new(60, 17).expect("req pubkey");
    668         let req_group = TangleRateLimitRule::new(60, 18).expect("req group");
    669         let req_kind = TangleRateLimitRule::new(60, 19).expect("req kind");
    670         let req_broad = TangleRateLimitRule::new(60, 20).expect("req broad");
    671         let count_ip = TangleRateLimitRule::new(60, 21).expect("count ip");
    672         let count_connection = TangleRateLimitRule::new(60, 22).expect("count connection");
    673         let count_pubkey = TangleRateLimitRule::new(60, 23).expect("count pubkey");
    674         let count_group = TangleRateLimitRule::new(60, 24).expect("count group");
    675         let count_kind = TangleRateLimitRule::new(60, 25).expect("count kind");
    676         let count_broad = TangleRateLimitRule::new(60, 26).expect("count broad");
    677         let config = TangleRateLimitConfig::new(
    678             TangleAuthRateLimitConfig::new(auth_ip, auth_pubkey, auth_failures, auth_failures_ip),
    679             TangleEventRateLimitConfig::new(event_ip, event_pubkey, event_kind),
    680             TangleGroupRateLimitConfig::new(
    681                 group_ip,
    682                 group_pubkey,
    683                 group_write,
    684                 group_kind,
    685                 group_join,
    686                 group_join_ip,
    687             ),
    688             TangleQueryRateLimitConfig::new(
    689                 req_ip,
    690                 req_connection,
    691                 req_pubkey,
    692                 req_group,
    693                 req_kind,
    694                 req_broad,
    695             ),
    696             TangleQueryRateLimitConfig::new(
    697                 count_ip,
    698                 count_connection,
    699                 count_pubkey,
    700                 count_group,
    701                 count_kind,
    702                 count_broad,
    703             ),
    704         );
    705 
    706         assert_eq!(config.auth().per_ip(), auth_ip);
    707         assert_eq!(config.auth().per_pubkey(), auth_pubkey);
    708         assert_eq!(config.auth().failures(), auth_failures);
    709         assert_eq!(config.auth().failures_per_ip(), auth_failures_ip);
    710         assert_eq!(config.event().per_ip(), event_ip);
    711         assert_eq!(config.event().per_pubkey(), event_pubkey);
    712         assert_eq!(config.event().per_kind(), event_kind);
    713         assert_eq!(config.group().write_per_ip(), group_ip);
    714         assert_eq!(config.group().write_per_pubkey(), group_pubkey);
    715         assert_eq!(config.group().write_per_group(), group_write);
    716         assert_eq!(config.group().write_per_kind(), group_kind);
    717         assert_eq!(config.group().join_flow(), group_join);
    718         assert_eq!(config.group().join_flow_per_ip(), group_join_ip);
    719         assert_eq!(config.req().per_ip(), req_ip);
    720         assert_eq!(config.req().per_connection(), req_connection);
    721         assert_eq!(config.req().per_pubkey(), req_pubkey);
    722         assert_eq!(config.req().per_group(), req_group);
    723         assert_eq!(config.req().per_kind(), req_kind);
    724         assert_eq!(config.req().broad(), req_broad);
    725         assert_eq!(config.count().per_ip(), count_ip);
    726         assert_eq!(config.count().per_connection(), count_connection);
    727         assert_eq!(config.count().per_pubkey(), count_pubkey);
    728         assert_eq!(config.count().per_group(), count_group);
    729         assert_eq!(config.count().per_kind(), count_kind);
    730         assert_eq!(config.count().broad(), count_broad);
    731     }
    732 }