using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.RateLimiting; namespace Nuuru.Server.Auth; /// /// Automatically applies the "api-mutation" rate limiting policy to all /// POST, PUT, PATCH, and DELETE actions that don't already have an explicit /// or . /// /// If a controller has any rate limiting attribute at the class level, /// none of its actions will receive the automatic "api-mutation" policy, /// even if individual mutation actions lack their own attribute. /// The controller-level policy is assumed to intentionally govern all /// of its endpoints, including mutations. /// public class MutationRateLimitConvention : IApplicationModelConvention { public void Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { // Skip controllers that already have a rate limiting attribute at class level if (HasRateLimitingAttribute(controller.Attributes)) continue; foreach (var action in controller.Actions) { // Skip actions that already have a rate limiting attribute if (HasRateLimitingAttribute(action.Attributes)) continue; if (IsMutationAction(action)) { foreach (var selector in action.Selectors) { selector.EndpointMetadata.Add(new EnableRateLimitingAttribute("api-mutation")); } } } } } private static bool HasRateLimitingAttribute(IReadOnlyList attributes) => attributes.Any(a => a is EnableRateLimitingAttribute or DisableRateLimitingAttribute); private static bool IsMutationAction(ActionModel action) => action.Attributes.Any(a => a is Microsoft.AspNetCore.Mvc.HttpPostAttribute or Microsoft.AspNetCore.Mvc.HttpPutAttribute or Microsoft.AspNetCore.Mvc.HttpDeleteAttribute or Microsoft.AspNetCore.Mvc.HttpPatchAttribute); }