11package dev .zenith .web .api ;
22
33import com .fasterxml .jackson .databind .DeserializationFeature ;
4+ import com .google .common .cache .Cache ;
5+ import com .google .common .cache .CacheBuilder ;
46import com .zenith .Globals ;
57import com .zenith .command .api .CommandContext ;
68import com .zenith .discord .EmbedSerializer ;
911import dev .zenith .web .api .model .CommandRequest ;
1012import dev .zenith .web .api .model .CommandResponse ;
1113import io .javalin .Javalin ;
12- import io .javalin .http .util .NaiveRateLimit ;
1314import io .javalin .json .JavalinJackson ;
1415import org .eclipse .jetty .util .thread .ExecutorThreadPool ;
1516
2122
2223public class WebServer {
2324 private Javalin server ;
25+ private final Cache <String , Integer > rateLimitCache = CacheBuilder .newBuilder ()
26+ .expireAfterWrite (1 , TimeUnit .MINUTES )
27+ .build ();
2428
2529 public synchronized void start () {
2630 if (server != null ) {
@@ -56,6 +60,20 @@ private Javalin createServer() {
5660 config .jsonMapper (new JavalinJackson (objectMapper , false ));
5761 })
5862 .beforeMatched (ctx -> {
63+ if (PLUGIN_CONFIG .rateLimiter ) {
64+ String ip = ctx .ip ();
65+ synchronized (this ) {
66+ int reqCount = rateLimitCache .get (ip , () -> 0 );
67+ rateLimitCache .put (ip , reqCount + 1 );
68+ if (reqCount >= PLUGIN_CONFIG .rateLimitRequestsPerMinute ) {
69+ ctx .status (429 );
70+ ctx .json (new AuthErrorResponse ("Rate limit exceeded" ));
71+ ctx .skipRemainingHandlers ();
72+ LOG .warn ("Rate limit exceeded for IP: {}" , ip );
73+ return ;
74+ }
75+ }
76+ }
5977 var authHeaderValue = ctx .header ("Authorization" );
6078 if (authHeaderValue != null ) {
6179 var expectedHeaderValue = PLUGIN_CONFIG .authToken ;
@@ -73,9 +91,6 @@ private Javalin createServer() {
7391 LOG .warn ("Denied request from {}: {}" , ctx .ip (), reason );
7492 })
7593 .post ("/command" , ctx -> {
76- if (PLUGIN_CONFIG .rateLimiter ) {
77- NaiveRateLimit .requestPerTimeUnit (ctx , PLUGIN_CONFIG .rateLimitRequestsPerMinute , TimeUnit .MINUTES );
78- }
7994 var req = ctx .bodyAsClass (CommandRequest .class );
8095 var command = req .command ();
8196 var context = CommandContext .create (command , WebAPICommandSource .INSTANCE );
0 commit comments