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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
// ─── rate_limit.rs ────────────────────────────────────────────────────────────
// This file implements per-IP rate limiting for all HTTP endpoints.
//
// What is rate limiting?
// Rate limiting prevents a single client from sending too many requests in a
// short time window. Without it, a malicious client could:
// - Flood the server with requests (DoS attack)
// - Brute-force the /login endpoint trying many passwords
// - Exhaust server memory by triggering many expensive queries
//
// How it works:
// Each incoming request is checked against a sliding window counter:
// 1. Extract the client's IP address from the request.
// 2. Look up the list of recent request timestamps for that IP.
// 3. Remove timestamps older than the window (e.g. older than 60 seconds).
// 4. If the remaining count >= max_requests → reject with 429 Too Many Requests.
// 5. Otherwise → record this request's timestamp and allow it through.
//
// Configuration (set via environment variables in main.rs):
// RATE_LIMIT_REQUESTS — max requests per window (default: 100)
// RATE_LIMIT_WINDOW_SECS — window size in seconds (default: 60)
//
// Known limitation:
// The IP is read from X-Forwarded-For, which is spoofable by clients.
// Behind a trusted reverse proxy, use the LAST IP in the header instead.
// See extract_ip() for details.
// ─────────────────────────────────────────────────────────────────────────────
// This file only compiles for native (non-WASM) targets.
// The rate limiter uses std::time and network types that don't exist in WASM.
use ;
// DashMap = a concurrent HashMap safe to share across async tasks without a Mutex.
// Each IP address maps to a Vec of timestamps of recent requests.
use DashMap;
use json;
// IpAddr = an IP address (either IPv4 or IPv6).
use IpAddr;
// Arc = Atomically Reference Counted pointer — lets multiple owners share the
// same data safely across threads. Required because the rate limiter is cloned
// into every request handler.
use Arc;
// Duration = a span of time (e.g. 60 seconds).
// Instant = a point in time, used for measuring elapsed time.
use ;
// ─── RateLimiter ──────────────────────────────────────────────────────────────
/// The rate limiter state, shared across all request handlers.
///
/// `#[derive(Clone)]` lets Axum clone this into each request handler.
/// The `Arc<DashMap<...>>` inside means all clones share the same underlying data —
/// cloning the struct is cheap (just increments a reference count).
// ─── RateLimitError ───────────────────────────────────────────────────────────
/// Error returned when a client exceeds their rate limit.
///
/// Contains enough information to build a helpful 429 response:
/// - `retry_after`: how many seconds until the client can try again.
/// - `limit`: the maximum requests per window (for informational purposes).
// ─── rate_limit_middleware ────────────────────────────────────────────────────
/// Axum middleware that enforces rate limiting on every request.
///
/// Middleware in Axum is a function that wraps a request handler:
/// request → [rate_limit_middleware] → [auth_middleware] → [handler]
///
/// If the rate limit is exceeded, this middleware short-circuits the chain
/// and returns a 429 response immediately — the handler is never called.
///
/// The `RateLimiter` is retrieved from Axum's extension system, where it was
/// inserted in main.rs via `.layer(axum::Extension(rate_limiter))`.
pub async
// ─── extract_ip ───────────────────────────────────────────────────────────────
/// Extract the client's real IP address from the request.
///
/// When MoltenDB runs behind a reverse proxy (nginx, Cloudflare, etc.), the
/// actual client IP is not the TCP connection IP — it's forwarded in headers.
///
/// Header priority:
/// 1. `X-Forwarded-For` — standard proxy header, may contain a comma-separated
/// list of IPs (client, proxy1, proxy2). We take the FIRST one.
/// 2. `X-Real-IP` — simpler single-IP header set by nginx.
/// 3. Fallback to `127.0.0.1` — used when running without a proxy.
///
/// ⚠️ SECURITY NOTE:
/// `X-Forwarded-For` is set by the client and is trivially spoofable.
/// A client can send `X-Forwarded-For: 1.2.3.4` to appear as any IP.
/// In production behind a trusted proxy, use the LAST IP in the list
/// (the one added by your own proxy) rather than the first.