using Downpatch.Web.Components; using Downpatch.Web.Endpoints; using Downpatch.Web.Services; using Markdig; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.FileProviders; namespace Downpatch.Web { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorComponents(); builder.Services.AddHttpContextAccessor(); builder.Services.AddRouting(); builder.Services.AddMemoryCache(o => { o.SizeLimit = 512 * 1024 * 1024; }); builder.Services.AddSingleton(sp => { var env = sp.GetRequiredService(); var root = Path.GetFullPath(Path.Combine(env.ContentRootPath, "content")); var index = new ContentIndex(root); index.Build(); return index; }); builder.Services.AddSingleton(sp => { var pipeline = new MarkdownPipelineBuilder() .DisableHtml() .UseAutoIdentifiers(Markdig.Extensions.AutoIdentifiers.AutoIdentifierOptions.GitHub) .Build(); return pipeline; }); builder.Services.AddSingleton(sp => { var env = sp.GetRequiredService(); var root = Path.GetFullPath(Path.Combine(env.ContentRootPath, "content")); var nav = new Downpatch.Web.Services.NavStore(root); nav.Build(); return nav; }); builder.Services.AddSingleton(); var app = builder.Build(); app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost }); var isDev = app.Environment.IsDevelopment(); if (app.Environment.IsDevelopment()) { app.Use(async (ctx, next) => { ctx.Response.Headers["Content-Security-Policy"] = "default-src 'self'; " + "base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; " + "script-src 'self' 'unsafe-inline'; " + "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; " + "img-src 'self' data:; font-src 'self' https://cdn.jsdelivr.net data:; " + "connect-src 'self' ws: wss: http://localhost:* https://localhost:*"; await next(); }); } else { app.Use(async (ctx, next) => { ctx.Response.Headers["Content-Security-Policy"] = "default-src 'self'; " + "base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; " + "script-src 'self'; " + "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; " + "img-src 'self' data:; font-src 'self' https://cdn.jsdelivr.net data:; " + "connect-src 'self'"; await next(); }); } app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "content")), RequestPath = "/content" }); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true); app.UseHttpsRedirection(); app.UseAntiforgery(); app.MapStaticAssets(); app.UseStaticFiles(); app.MapRobots(); app.MapSitemap(); app.MapRazorComponents(); using var scope = app.Services.CreateScope(); var pages = scope.ServiceProvider.GetRequiredService(); pages.WarmAll(); app.Run(); } } }