forked from connect-boiz/soroban-security-scanner
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_rate_limiting_syntax.rs
More file actions
211 lines (181 loc) · 6.23 KB
/
Copy pathtest_rate_limiting_syntax.rs
File metadata and controls
211 lines (181 loc) · 6.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Syntax verification test for rate limiting implementation
// This file checks that all our modules can be imported and basic types work
use std::net::IpAddr;
use std::time::Duration;
use chrono::Utc;
use uuid::Uuid;
// Test that all our rate limiting types can be imported
mod rate_limiting {
pub mod types {
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::IpAddr;
use std::time::Duration;
use chrono::{DateTime, Utc};
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum RateLimitTier {
Unauthenticated,
Basic,
Premium,
Enterprise,
Admin,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RateLimitWindow {
Second, Minute, Hour, Day, Week, Month,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimitPolicy {
pub max_requests: u64,
pub window: RateLimitWindow,
pub burst_capacity: Option<u64>,
pub penalty_duration: Option<Duration>,
}
#[derive(Debug, Clone)]
pub struct RateLimitContext {
pub user_id: Option<Uuid>,
pub tier: RateLimitTier,
pub ip_address: IpAddr,
pub resource: String,
pub method: String,
pub user_agent: Option<String>,
pub country: Option<String>,
pub api_key: Option<String>,
pub timestamp: DateTime<Utc>,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RateLimitResult {
Allowed {
remaining: u64,
reset_time: DateTime<Utc>,
current_usage: u64,
},
Blocked {
reason: String,
retry_after: Duration,
current_usage: u64,
max_requests: u64,
},
}
}
pub mod config {
use super::types::*;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct RateLimitConfig {
pub enabled: bool,
pub default_policies: HashMap<RateLimitTier, Vec<RateLimitPolicy>>,
}
impl Default for RateLimitConfig {
fn default() -> Self {
Self {
enabled: true,
default_policies: HashMap::new(),
}
}
}
}
pub mod storage {
use async_trait::async_trait;
use super::types::*;
use std::time::Duration;
#[async_trait]
pub trait RateLimitStorage: Send + Sync {
type Error: std::error::Error + Send + Sync + 'static;
async fn record_request(
&self,
key: &str,
window: Duration,
timestamp: DateTime<Utc>,
) -> Result<u64, Self::Error>;
async fn get_request_count(
&self,
key: &str,
window: Duration,
) -> Result<u64, Self::Error>;
}
pub struct MemoryStorage;
impl MemoryStorage {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl RateLimitStorage for MemoryStorage {
type Error = String;
async fn record_request(&self, _key: &str, _window: Duration, _timestamp: DateTime<Utc>) -> Result<u64, Self::Error> {
Ok(1)
}
async fn get_request_count(&self, _key: &str, _window: Duration) -> Result<u64, Self::Error> {
Ok(0)
}
}
}
pub mod limiter {
use super::types::*;
use super::config::RateLimitConfig;
use super::storage::RateLimitStorage;
pub struct RateLimiter {
config: RateLimitConfig,
storage: Box<dyn RateLimitStorage<Error = Box<dyn std::error::Error + Send + Sync>>>,
}
impl RateLimiter {
pub async fn new(
config: RateLimitConfig,
storage: Box<dyn RateLimitStorage<Error = Box<dyn std::error::Error + Send + Sync>>>,
) -> Result<Self, Box<dyn std::error::Error>> {
Ok(Self { config, storage })
}
pub async fn check_rate_limit(&self, context: &RateLimitContext) -> RateLimitResult {
// Simple implementation for syntax check
RateLimitResult::Allowed {
remaining: 100,
reset_time: Utc::now() + Duration::from_secs(60),
current_usage: 1,
}
}
}
}
}
// Test that we can create and use the types
fn test_syntax() {
use rate_limiting::*;
// Test creating a rate limit context
let context = types::RateLimitContext {
user_id: Some(Uuid::new_v4()),
tier: types::RateLimitTier::Basic,
ip_address: "127.0.0.1".parse().unwrap(),
resource: "/api/test".to_string(),
method: "GET".to_string(),
user_agent: Some("test-agent".to_string()),
country: Some("US".to_string()),
api_key: None,
timestamp: Utc::now(),
metadata: std::collections::HashMap::new(),
};
// Test creating a rate limit policy
let policy = types::RateLimitPolicy {
max_requests: 100,
window: types::RateLimitWindow::Minute,
burst_capacity: Some(150),
penalty_duration: Some(Duration::from_secs(300)),
};
// Test creating configuration
let mut config = config::RateLimitConfig::default();
config.default_policies.insert(
types::RateLimitTier::Basic,
vec![policy],
);
// Test creating storage
let storage = Box::new(storage::MemoryStorage::new());
// Test creating rate limiter (would need async in real usage)
println!("All rate limiting types can be created successfully!");
println!("Context: {:?}", context.resource);
println!("Config enabled: {}", config.enabled);
}
fn main() {
test_syntax();
println!("✅ Rate limiting syntax verification passed!");
}