using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.Authentication.Cookies; using The_Stitching_Beehive.Data; using The_Stitching_Beehive.Services; using System.IO.Compression; var builder = WebApplication.CreateBuilder(args); var envPath = Path.GetFullPath(".env"); if (File.Exists(envPath)) { foreach (var line in File.ReadAllLines(envPath)) { if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith('#')) continue; var parts = line.Split('=', 2); if (parts.Length != 2) continue; var key = parts[0].Trim(); var value = parts[1].Trim(); var configKey = key switch { "ADMIN_PASSWORD" => "AdminSettings:Password", "EMAIL_USERNAME" => "EmailSettings:Username", "EMAIL_PASSWORD" => "EmailSettings:Password", _ => key.Replace("__", ":") }; builder.Configuration[configKey] = value; } } var dataRoot = Path.GetFullPath(builder.Configuration.GetValue("DataPaths:Root") ?? "App_Data"); var uploadsDir = Path.Combine(dataRoot, "uploads"); Directory.CreateDirectory(dataRoot); Directory.CreateDirectory(uploadsDir); var connectionString = $"Data Source={Path.Combine(dataRoot, "StitchingBeehive.db")}"; builder.Configuration["ConnectionStrings:DefaultConnection"] = connectionString; builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes( builder.Configuration.GetValue("AdminSettings:SessionTimeoutMinutes", 30)); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(o => { o.LoginPath = "/Admin/Login"; o.ExpireTimeSpan = TimeSpan.FromDays(7); o.SlidingExpiration = true; }); builder.Services.AddControllersWithViews(); builder.Services.AddResponseCompression(options => { options.Providers.Add(); options.Providers.Add(); options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(GetAdditionalMimeTypes()); }); static string[] GetAdditionalMimeTypes() { return ["text/html", "text/css", "text/javascript", "application/javascript", "application/json", "image/svg+xml", "font/woff2", "application/xml", "text/xml"]; } builder.Services.Configure(options => { options.Level = CompressionLevel.Optimal; }); builder.Services.Configure(options => { options.Level = CompressionLevel.Optimal; }); var app = builder.Build(); app.Use(async (context, next) => { context.Response.Headers.XContentTypeOptions = "nosniff"; context.Response.Headers.XFrameOptions = "DENY"; context.Response.Headers.XXSSProtection = "1; mode=block"; context.Response.Headers["Referrer-Policy"] = "strict-origin-when-cross-origin"; await next(); }); if (!app.Environment.IsDevelopment()) { _ = app.UseExceptionHandler("/Home/Error"); _ = app.UseHsts(); _ = app.UseResponseCompression(); } app.UseStaticFiles(new StaticFileOptions { OnPrepareResponse = context => { if (!app.Environment.IsDevelopment()) { context.Context.Response.Headers.CacheControl = "public, max-age=31536000"; context.Context.Response.Headers.XContentTypeOptions = "nosniff"; } } }); app.UseStaticFiles(new StaticFileOptions { FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(uploadsDir), RequestPath = "/uploads" }); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); using (var scope = app.Services.CreateScope()) { var services = scope.ServiceProvider; var context = services.GetRequiredService(); context.Database.Migrate(); } app.Run();