using System.Security.Claims; using lxc_songlist.Components; using lxc_songlist.Data; using lxc_songlist.Services; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.EntityFrameworkCore; using MudBlazor.Services; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); builder.Services.AddCascadingAuthenticationState(); builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/admin/login"; options.AccessDeniedPath = "/admin/login"; options.Cookie.Name = "lxc-songlist-admin"; options.SlidingExpiration = true; }); builder.Services.AddAuthorization(); builder.Services.AddMudServices(); builder.Services.Configure(builder.Configuration.GetSection("Admin")); builder.Services.Configure(builder.Configuration.GetSection("Site")); builder.Services.AddDbContextFactory(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); // 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.UseAuthentication(); app.UseAuthorization(); app.UseAntiforgery(); app.MapStaticAssets(); app.MapPost("/admin/sign-in", async ( HttpContext httpContext, AdminPasswordService passwordService) => { var form = await httpContext.Request.ReadFormAsync(); var password = form["password"].ToString(); var returnUrl = form["returnUrl"].ToString(); if (!passwordService.Verify(password)) { return Results.Redirect("/admin/login?error=1"); } var claims = new[] { new Claim(ClaimTypes.Name, "admin"), new Claim(ClaimTypes.Role, "Admin") }; var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var principal = new ClaimsPrincipal(identity); await httpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.AddDays(14) }); return Results.Redirect(IsLocalUrl(returnUrl) ? returnUrl : "/admin"); }) .DisableAntiforgery(); app.MapGet("/admin/logout", async (HttpContext httpContext) => { await httpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return Results.Redirect("/"); }) .RequireAuthorization(); app.MapRazorComponents() .AddInteractiveServerRenderMode(); app.Run(); static bool IsLocalUrl(string? url) { return !string.IsNullOrWhiteSpace(url) && Uri.TryCreate(url, UriKind.Relative, out _) && url[0] == '/' && (url.Length == 1 || (url[1] != '/' && url[1] != '\\')); }