basic admin panel stuff

This commit is contained in:
Lapis
2026-06-17 13:39:28 -04:00
parent c20d215ee0
commit 004f1921a6
44 changed files with 3432 additions and 315 deletions
+90 -4
View File
@@ -1,22 +1,108 @@
using System.Security.Claims;
using CannedNet.Admin.Components;
using CannedNet.Admin.Services;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddAuthentication("AdminCookie")
.AddCookie("AdminCookie", options =>
{
options.Cookie.Name = "CannedNetAdmin";
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
options.Cookie.SameSite = SameSiteMode.Strict;
options.LoginPath = "/login";
options.LogoutPath = "/admin/logout";
options.AccessDeniedPath = "/login";
options.ExpireTimeSpan = TimeSpan.FromHours(8);
options.SlidingExpiration = true;
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("OwnerOnly", policy => policy.RequireClaim("role", "Owner"));
});
builder.Services.AddSingleton<AdminAuthService>();
var imagesBaseUrl = builder.Configuration.GetValue<string>("ImagesBaseUrl") ?? "http://localhost:5000/img";
builder.Services.AddSingleton(new ImageUrlService(imagesBaseUrl));
builder.Services.AddHttpContextAccessor();
var serverUrl = builder.Configuration.GetValue<string>("ServerBaseUrl") ?? "http://localhost:5000";
builder.Services.AddTransient<AdminApiKeyHandler>();
builder.Services.AddScoped(sp =>
{
var handler = sp.GetRequiredService<AdminApiKeyHandler>();
handler.InnerHandler = new SocketsHttpHandler();
return new HttpClient(handler) { BaseAddress = new Uri(serverUrl) };
});
var app = builder.Build();
// Configure the HTTP request pipeline.
// --- Admin Auth Endpoints ---
app.MapPost("/admin/login", async (HttpContext context, AdminAuthService authService) =>
{
var form = await context.Request.ReadFormAsync();
var username = form["username"].FirstOrDefault() ?? "";
var password = form["password"].FirstOrDefault() ?? "";
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
{
context.Response.Redirect("/login?error=missing");
return;
}
var user = authService.GetByUsername(username);
if (user == null || !authService.VerifyPassword(password, user.PasswordHash))
{
context.Response.Redirect("/login?error=invalid");
return;
}
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
new Claim("role", user.IsOwner ? "Owner" : "Admin")
};
var identity = new ClaimsIdentity(claims, "AdminCookie");
var principal = new ClaimsPrincipal(identity);
await context.SignInAsync("AdminCookie", principal, new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddHours(8)
});
context.Response.Redirect("/");
});
app.MapGet("/admin/logout", async (HttpContext context) =>
{
await context.SignOutAsync("AdminCookie");
context.Response.Redirect("/login");
});
// --- Standard middleware ---
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.UseHttpsRedirection();
}
app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true);
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();