public void OnResultExecuting(ResultExecutingContext context) { switch (context.Result) { case StatusCodeResult result: { var status = (HttpStatusCode)result.StatusCode; context.Result = ResultUtilities.Status(status); break; } case ObjectResult result: { var status = (HttpStatusCode)(result.StatusCode ?? 200); var type = result.Value?.GetType(); // ensure something is returned, instead of an empty response if (type == null) { context.Result = ResultUtilities.Status(status); } // wrap string responses else if (type == typeof(string)) { context.Result = ResultUtilities.Status(status, (string)result.Value); } break; } } }
public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var reason = ModelSanitizer.Sanitize(context.HttpContext.Request.Query["reason"].ToString()); if (reason != null && reason.Length >= MinReasonLength) { return(next()); } context.Result = ResultUtilities.BadRequest("A valid reason must be provided for this action."); return(Task.CompletedTask); }
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var control = context.HttpContext.RequestServices.GetService <IWriteControl>(); var environment = context.HttpContext.RequestServices.GetService <IHostEnvironment>(); try { await using (await control.EnterAsync()) await next(); } catch (WriteControlException e) { context.Result = ResultUtilities.Status(HttpStatusCode.ServiceUnavailable, e.ToStringWithTrace("Could not complete this request at the moment due to maintenance.", environment.IsProduction())); } }
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var validator = context.HttpContext.RequestServices.GetService <IRecaptchaValidator>(); var value = ModelSanitizer.Sanitize(context.HttpContext.Request.Query["recaptcha"].ToString()); if (await validator.TryValidateAsync(value, context.HttpContext.RequestAborted)) { await next(); } else { context.Result = ResultUtilities.BadRequest("Could not verify reCAPTCHA token."); } }
public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { if (context.Result != null) { return; } var cancellationToken = context.HttpContext.RequestAborted; var now = DateTime.UtcNow; // retrieve user var users = context.HttpContext.RequestServices.GetService <IUserService>(); var userId = context.HttpContext.Items.TryGetValue(AuthHandler.PayloadItemKey, out var token) ? ((AuthTokenPayload)token).UserId : default; var result = await users.GetAsync(userId, cancellationToken); if (!(result.Value is DbUser user)) { context.Result = ResultUtilities.Forbidden($"Unknown user {userId}."); return; } // pass user down the pipeline context.HttpContext.Items[UserItemKey] = user; if (!user.HasPermissions(UserPermissions.Administrator)) // bypass checks for admin { // restriction check var restriction = user.Restrictions?.FirstOrDefault(r => r.EndTime == null || now < r.EndTime); if (Unrestricted && restriction != null) { context.Result = ResultUtilities.Forbidden($"Cannot perform this action while you are restricted: {restriction.Reason ?? "<unknown reason>"}"); return; } // permission check if (!user.HasPermissions(Permissions)) { context.Result = ResultUtilities.Forbidden($"Insufficient permissions to perform this action. Required: {string.Join(", ", Permissions.ToFlags())}"); return; } } }
public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { switch (context.HttpContext.Request.Method) { case "POST": case "PUT": var query = ModelSanitizer.Sanitize(context.HttpContext.Request.Query["validate"].ToString()); if (query != null && (!bool.TryParse(query, out var x) || x)) // specified and not "false" { // at this point in an action filter, model is already validated, so we will simply short-circuit. // we always with 422 even if there are no validation problems. var problems = Array.Empty <ValidationProblem>(); context.Result = ResultUtilities.UnprocessableEntity(problems); return(Task.CompletedTask); } break; } return(next()); }
public void ConfigureServices(IServiceCollection services) { // configuration services.AddSingleton(_configuration) // root .AddHostedService <ConfigurationReloader>(); // kestrel services.Configure <ServerOptions>(_configuration.GetSection("Server")) .Configure <KestrelServerOptions>(o => { var server = o.ApplicationServices.GetService <IOptionsMonitor <ServerOptions> >().CurrentValue; if (server.HttpPortDev != null) { o.ListenLocalhost(server.HttpPortDev.Value); } if (server.HttpPort != null) { o.ListenAnyIP(server.HttpPort.Value); } if (server.HttpsPort != null && server.CertificatePath != null) { o.ListenAnyIP(server.HttpsPort.Value, l => l.UseHttps(server.CertificatePath, server.CertificatePassword)); } o.Limits.MaxRequestBufferSize = 1024 * 64; // 16 KiB o.Limits.MaxRequestLineSize = 1024 * 8; // 8 KiB o.Limits.MaxRequestHeadersTotalSize = 1024 * 8; // 8 KiB o.Limits.MaxRequestBodySize = 1024 * 256; // 16 KiB }) .AddResponseCompression(o => { o.Providers.Add <GzipCompressionProvider>(); o.Providers.Add <BrotliCompressionProvider>(); }) .AddResponseCaching(o => { o.UseCaseSensitivePaths = false; // this is for static files o.SizeLimit = long.MaxValue; o.MaximumBodySize = long.MaxValue; }); // mvc services.AddMvcCore(m => { m.Filters.Add <PrimitiveResponseWrapperFilter>(); m.Filters.Add <RequestValidateQueryFilter>(); m.OutputFormatters.RemoveType <StringOutputFormatter>(); // model sanitizing binder var modelBinder = new ModelSanitizerModelBinderProvider(m.ModelBinderProviders); m.ModelBinderProviders.Clear(); m.ModelBinderProviders.Add(modelBinder); }) .AddNewtonsoftJson(o => { o.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = ModelNamingStrategy }; o.SerializerSettings.Converters.Add(new StringEnumConverter { NamingStrategy = ModelNamingStrategy, AllowIntegerValues = true }); }) .AddApiExplorer() .AddAuthorization() .AddFormatterMappings() .AddDataAnnotations() .AddCors() .AddTestControllers() .AddControllersAsServices(); services.Configure <ApiBehaviorOptions>(o => { o.SuppressMapClientErrors = true; o.InvalidModelStateResponseFactory = c => { static string fixFieldCasing(string str) => string.Join('.', str.Split('.').Select(s => ModelNamingStrategy.GetPropertyName(s, false))); var problems = c.ModelState .Where(x => !x.Value.IsContainerNode && x.Value.Errors.Count != 0) .Select(x => { var(field, entry) = x; return(new ValidationProblem { Field = ModelNamingStrategy.GetPropertyName(fixFieldCasing(field), false), Messages = entry.Errors.ToArray(e => e.ErrorMessage ?? e.Exception.ToStringWithTrace(null, _environment.IsProduction())) }); }) .ToArray(); return(ResultUtilities.UnprocessableEntity(problems)); };