feat(server): add rate limiting

This commit is contained in:
Stevan Freeborn
2026-01-04 21:11:09 -06:00
parent 7ba17ea0e3
commit 3e2e0b5690
2 changed files with 52 additions and 0 deletions
@@ -0,0 +1,32 @@
using System.Globalization;
using System.Threading.RateLimiting;
namespace GroundsForSupport.Server.RateLimiting;
internal static class Extensions
{
public static void AddRateLimingPolicies(this IServiceCollection services)
{
services.AddRateLimiter(static o =>
{
o.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
o.OnRejected = static (context, ct) =>
{
var response = context.HttpContext.Response;
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
response.Headers.RetryAfter = ((int)retryAfter.TotalSeconds).ToString(CultureInfo.InvariantCulture);
var resetTime = DateTimeOffset.UtcNow.Add(retryAfter);
var unixTimeMilliseconds = resetTime.ToUnixTimeMilliseconds();
response.Headers.Append("X-RateLimit-Reset", unixTimeMilliseconds.ToString(CultureInfo.InvariantCulture));
}
return ValueTask.CompletedTask;
};
o.AddPolicy(FixedRateLimitPolicy.Name, FixedRateLimitPolicy.Partitioner);
});
}
}
@@ -0,0 +1,20 @@
using System.Threading.RateLimiting;
namespace GroundsForSupport.Server.RateLimiting;
internal static class FixedRateLimitPolicy
{
public const string Name = "fixed";
public static Func<HttpContext, RateLimitPartition<string>> Partitioner =>
static context => RateLimitPartition.GetFixedWindowLimiter(
partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
factory: static partition => new FixedWindowRateLimiterOptions
{
PermitLimit = 10,
Window = TimeSpan.FromHours(1),
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = 0
}
);
}