Skip to content

Commit 2599fb1

Browse files
committed
backend: reduce ratelimit for chargers
fix #243
1 parent fba913c commit 2599fb1

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

backend/src/rate_limit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl Default for ChargerRateLimiter {
119119
impl ChargerRateLimiter {
120120
pub fn new() -> Self {
121121
Self(RateLimiter::keyed(
122-
Quota::per_second(NonZeroU32::new(REQUESTS_PER_SECOND).unwrap())
122+
Quota::per_minute(NonZeroU32::new(REQUESTS_PER_SECOND).unwrap())
123123
.allow_burst(NonZeroU32::new(REQUESTS_BURST).unwrap()),
124124
))
125125
}

backend/src/routes/send_chargelog_to_user.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,114 @@ mod tests {
308308
let resp = test::call_service(&app, req).await;
309309
assert_eq!(resp.status(), 401);
310310
}
311+
312+
#[actix_web::test]
313+
async fn test_send_chargelog_rate_limit() {
314+
let (mut user, _mail) = TestUser::random().await;
315+
user.login().await;
316+
let charger = user.add_random_charger().await;
317+
318+
let app = App::new().configure(configure).service(send_chargelog);
319+
let app = test::init_service(app).await;
320+
321+
let user_uuid = crate::routes::user::tests::get_test_uuid(&user.mail)
322+
.unwrap()
323+
.to_string();
324+
325+
let metadata = json!({
326+
"charger_uuid": charger.uuid,
327+
"password": charger.password,
328+
"user_uuid": user_uuid,
329+
"display_name": "Test Device",
330+
"filename": "chargelog.pdf",
331+
"monthly_send": true
332+
});
333+
334+
let boundary = "----testboundary3";
335+
let ip = "123.123.123.100";
336+
337+
// Send requests up to the burst limit (5 in test mode)
338+
for i in 0..5 {
339+
let body = build_multipart_body(boundary, &metadata, &[1, 2, 3, 4, 5]);
340+
let req = test::TestRequest::post()
341+
.uri("/send_chargelog_to_user")
342+
.append_header(("X-Forwarded-For", ip))
343+
.append_header((
344+
"Content-Type",
345+
format!("multipart/form-data; boundary={boundary}"),
346+
))
347+
.set_payload(body)
348+
.to_request();
349+
let resp = test::call_service(&app, req).await;
350+
assert_eq!(
351+
resp.status(),
352+
200,
353+
"Request {} should succeed (within burst limit)",
354+
i + 1
355+
);
356+
}
357+
358+
// The 6th request should be rate limited
359+
let body = build_multipart_body(boundary, &metadata, &[1, 2, 3, 4, 5]);
360+
let req = test::TestRequest::post()
361+
.uri("/send_chargelog_to_user")
362+
.append_header(("X-Forwarded-For", ip))
363+
.append_header((
364+
"Content-Type",
365+
format!("multipart/form-data; boundary={boundary}"),
366+
))
367+
.set_payload(body)
368+
.to_request();
369+
let resp = test::call_service(&app, req).await;
370+
assert_eq!(
371+
resp.status(),
372+
429,
373+
"Request 6 should be rate limited (429 Too Many Requests)"
374+
);
375+
376+
// Verify that a different IP can still make requests
377+
let body = build_multipart_body(boundary, &metadata, &[1, 2, 3, 4, 5]);
378+
let req = test::TestRequest::post()
379+
.uri("/send_chargelog_to_user")
380+
.append_header(("X-Forwarded-For", "123.123.123.101"))
381+
.append_header((
382+
"Content-Type",
383+
format!("multipart/form-data; boundary={boundary}"),
384+
))
385+
.set_payload(body)
386+
.to_request();
387+
let resp = test::call_service(&app, req).await;
388+
assert_eq!(
389+
resp.status(),
390+
200,
391+
"Request from different IP should succeed"
392+
);
393+
394+
// Verify that a different charger from the same IP can make requests
395+
let charger2 = user.add_random_charger().await;
396+
let metadata2 = json!({
397+
"charger_uuid": charger2.uuid,
398+
"password": charger2.password,
399+
"user_uuid": user_uuid,
400+
"display_name": "Test Device 2",
401+
"filename": "chargelog2.pdf",
402+
"monthly_send": false
403+
});
404+
let body = build_multipart_body(boundary, &metadata2, &[1, 2, 3, 4, 5]);
405+
let req = test::TestRequest::post()
406+
.uri("/send_chargelog_to_user")
407+
.append_header(("X-Forwarded-For", ip))
408+
.append_header((
409+
"Content-Type",
410+
format!("multipart/form-data; boundary={boundary}"),
411+
))
412+
.set_payload(body)
413+
.to_request();
414+
let resp = test::call_service(&app, req).await;
415+
assert_eq!(
416+
resp.status(),
417+
200,
418+
"Request from different charger (same IP) should succeed"
419+
);
420+
}
311421
}

0 commit comments

Comments
 (0)