using Nuuru.Server.Services; namespace Nuuru.Server.Middleware { public class IpBanCheckMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; private static readonly HashSet MutatingMethods = new(StringComparer.OrdinalIgnoreCase) { "POST", "PUT", "DELETE", "PATCH" }; public IpBanCheckMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context, IIpBanService ipBanService) { // Only block mutating methods — reads always pass through if (!MutatingMethods.Contains(context.Request.Method)) { await _next(context); return; } var ip = context.Connection.RemoteIpAddress?.ToString(); if (string.IsNullOrEmpty(ip)) { await _next(context); return; } var path = context.Request.Path.Value ?? string.Empty; if (path.StartsWith("/api/Moderation/ip-bans/mine", StringComparison.OrdinalIgnoreCase) || path.StartsWith("/api/Moderation/ip-bans/appeals", StringComparison.OrdinalIgnoreCase)) { await _next(context); return; } if (await ipBanService.IsIpBannedAsync(ip)) { var ban = await ipBanService.GetActiveIpBanAsync(ip); _logger.LogWarning("IP-banned address {IpAddress} attempted {Method} {Path}", ip, context.Request.Method, context.Request.Path); context.Response.StatusCode = StatusCodes.Status403Forbidden; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(new { error = "Your IP address is banned", reason = ban?.Reason, until = ban?.EndTime == DateTime.MaxValue ? (DateTime?)null : ban?.EndTime, type = "ip_ban", banId = ban?.Id }); return; } await _next(context); } } }