Require admin password for destructive admin actions

This commit is contained in:
2026-02-08 15:05:10 +01:00
parent 96a47020d8
commit e666e7c603
13 changed files with 197 additions and 43 deletions

View File

@@ -9,6 +9,8 @@ namespace GameList.Tests;
public class AdminTests
{
private const string AdminPassword = "Pass123!";
[Fact]
public async Task Admin_vote_status_marks_ready_when_all_finalized()
{
@@ -134,7 +136,10 @@ public class AdminTests
Score = 8
});
var resp = await admin.DeleteAsync($"/api/admin/players/{await player.GetProfileIdAsync()}");
var resp = await admin.SendAsync(new HttpRequestMessage(HttpMethod.Delete, $"/api/admin/players/{await player.GetProfileIdAsync()}")
{
Content = JsonContent.Create(new { password = AdminPassword })
});
resp.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(db =>
@@ -246,7 +251,7 @@ public class AdminTests
await player.RegisterAsync("player");
await player.CreateSuggestionAsync("Keep");
var reset = await admin.PostAsJsonAsync("/api/admin/reset", new { });
var reset = await admin.PostAsJsonAsync("/api/admin/reset", new { password = AdminPassword });
reset.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(db =>
@@ -266,7 +271,7 @@ public class AdminTests
}
});
var factoryReset = await admin.PostAsJsonAsync("/api/admin/factory-reset", new { });
var factoryReset = await admin.PostAsJsonAsync("/api/admin/factory-reset", new { password = AdminPassword });
factoryReset.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(db =>
@@ -514,7 +519,7 @@ public class AdminTests
await db.SaveChangesAsync();
});
var reset = await admin.PostAsJsonAsync("/api/admin/reset", new { });
var reset = await admin.PostAsJsonAsync("/api/admin/reset", new { password = AdminPassword });
reset.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(async db =>
@@ -526,7 +531,7 @@ public class AdminTests
Assert.False(state.ResultsOpen);
});
var factoryReset = await admin.PostAsJsonAsync("/api/admin/factory-reset", new { });
var factoryReset = await admin.PostAsJsonAsync("/api/admin/factory-reset", new { password = AdminPassword });
factoryReset.EnsureSuccessStatusCode();
await factory.WithDbContextAsync(async db =>
{
@@ -534,4 +539,25 @@ public class AdminTests
Assert.False(state.ResultsOpen);
});
}
[Fact]
public async Task Destructive_admin_actions_require_valid_admin_password()
{
await using var factory = new TestWebApplicationFactory();
var admin = factory.CreateClientWithCookies();
await admin.RegisterAsync("admin", admin: true);
var player = factory.CreateClientWithCookies();
await player.RegisterAsync("target");
var resetWrongPassword = await admin.PostAsJsonAsync("/api/admin/reset", new { password = "wrong" });
Assert.Equal(HttpStatusCode.BadRequest, resetWrongPassword.StatusCode);
var playerId = await factory.WithDbContextAsync(async db => await db.Players.Where(p => p.Username == "target").Select(p => p.Id).SingleAsync());
var deleteWrongPassword = await admin.SendAsync(new HttpRequestMessage(HttpMethod.Delete, $"/api/admin/players/{playerId}")
{
Content = JsonContent.Create(new { password = "wrong" })
});
Assert.Equal(HttpStatusCode.BadRequest, deleteWrongPassword.StatusCode);
}
}