diff --git a/DigitalData.Core.API/CSPMiddleware.cs b/DigitalData.Core.API/CSPMiddleware.cs new file mode 100644 index 0000000..63ab642 --- /dev/null +++ b/DigitalData.Core.API/CSPMiddleware.cs @@ -0,0 +1,47 @@ +namespace DigitalData.Core.API +{ + /// + /// Middleware to add Content Security Policy (CSP) headers to the HTTP response. + /// + public class CSPMiddleware + { + private readonly RequestDelegate _next; + private readonly string _policy; + + /// + /// Initializes a new instance of the class. + /// + /// The next middleware in the request pipeline. + /// The CSP policy string with placeholders for nonces. + public CSPMiddleware(RequestDelegate next, string policy) + { + _next = next; + _policy = policy; + } + + /// + /// Invokes the middleware to add the CSP header to the response. + /// + /// The HTTP context. + /// A task that represents the completion of request processing. + public async Task Invoke(HttpContext context) + { + // Generate a nonce (number used once) for inline scripts and styles + var nonce = Convert.ToBase64String(Guid.NewGuid().ToByteArray()); + + // Store the nonce in the context items for later use + context.Items["csp-nonce"] = nonce; + + // Add the CSP header to the response + context.Response.OnStarting(() => + { + context.Response.Headers.Add("Content-Security-Policy", + string.Format(_policy, nonce)); + return Task.CompletedTask; + }); + + // Call the next middleware in the pipeline + await _next(context); + } + } +} \ No newline at end of file diff --git a/DigitalData.Core.API/DIExtensions.cs b/DigitalData.Core.API/DIExtensions.cs new file mode 100644 index 0000000..02b4c25 --- /dev/null +++ b/DigitalData.Core.API/DIExtensions.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Builder; + +namespace DigitalData.Core.API +{ + /// + /// Provides extension methods for adding middleware to the application's request pipeline. + /// + public static class DIExtensions + { + /// + /// Adds the to the application's request pipeline to include + /// Content Security Policy (CSP) headers in the HTTP response. + /// + /// The application builder. + /// + /// The CSP policy string with placeholders. The first format parameter {0} will be replaced + /// by the nonce value. + /// + /// The application builder with the CSP middleware added. + public static IApplicationBuilder UseCSPMiddleware(this IApplicationBuilder app, string policy) + => app.UseMiddleware(policy); + } +} \ No newline at end of file diff --git a/DigitalData.Core.DTO/DTOExtensions.cs b/DigitalData.Core.DTO/DTOExtensions.cs index daad4ce..4db2175 100644 --- a/DigitalData.Core.DTO/DTOExtensions.cs +++ b/DigitalData.Core.DTO/DTOExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Logging; -using System.Diagnostics; using System.Text; namespace DigitalData.Core.DTO @@ -63,6 +62,10 @@ namespace DigitalData.Core.DTO return result; } + public static bool HasFlag(this IEnumerable notices, Enum flag) => notices.Any(n => n.Flag?.ToString() == flag.ToString()); + + public static bool HasAnyFlag(this IEnumerable notices, params Enum[] flags) => flags.Any(f => notices.HasFlag(f)); + public static I Then(this Result result, Func Success, Func, List, I> Fail) { return result.IsSuccess ? Success() : Fail(result.Messages, result.Notices);