Add owner role and admin management controls

This commit is contained in:
2026-02-08 19:01:58 +01:00
parent 97f1b30b75
commit 1c59d68a50
25 changed files with 540 additions and 9 deletions

View File

@@ -14,6 +14,12 @@ public static class AuthEndpoints
{
var group = app.MapGroup("/api/auth").RequireRateLimiting("auth-sensitive");
group.MapGet("/options", async (AppDbContext db) =>
{
var ownerExists = await db.Players.AsNoTracking().AnyAsync(p => p.IsOwner);
return Results.Ok(new AuthOptionsResponse(ownerExists));
});
group.MapPost("/register", async ([FromBody] RegisterRequest request, HttpContext ctx, AppDbContext db, IConfiguration config, AuthAttemptMonitor authAttemptMonitor) =>
{
if (!AuthValidator.TryValidateRegistration(request, out var validated, out var registrationError))
@@ -37,15 +43,16 @@ public static class AuthEndpoints
return EndpointHelpers.BadRequestError("Invalid admin key.");
}
var adminExists = await db.Players.AnyAsync(p => p.IsAdmin);
if (adminExists)
var ownerExists = await db.Players.AsNoTracking().AnyAsync(p => p.IsOwner);
if (ownerExists)
{
authAttemptMonitor.RecordFailure(ctx, "auth-register-admin", validated.NormalizedUsername, "bootstrap-admin-disabled");
return EndpointHelpers.BadRequestError("Admin registration via admin key is disabled after the first admin account.");
return EndpointHelpers.BadRequestError("Admin registration via admin key is disabled once an owner account exists.");
}
}
var isAdmin = wantsAdmin;
var isOwner = wantsAdmin;
var player = new Player
{
@@ -56,6 +63,7 @@ public static class AuthEndpoints
PasswordSalt = salt,
DisplayName = validated.DisplayName,
IsAdmin = isAdmin,
IsOwner = isOwner,
CreatedAt = DateTimeOffset.UtcNow,
LastLoginAt = DateTimeOffset.UtcNow
};