fix(app): harden account and workflow state

This commit is contained in:
cesnimda
2026-08-24 20:21:09 +02:00
parent e7cacad7d6
commit dca5daa1a2
32 changed files with 811 additions and 86 deletions
@@ -57,6 +57,51 @@ public sealed class UsersControllerTests
users.Verify(x => x.RemoveFromRolesAsync(admin, It.IsAny<IEnumerable<string>>()), Times.Once);
}
[Fact]
public async Task SetRoles_revokes_existing_sessions_and_trusted_devices_when_roles_change()
{
await using var connection = new SqliteConnection("Data Source=:memory:");
await connection.OpenAsync();
var currentUser = new Mock<ICurrentUserService>();
currentUser.SetupGet(service => service.UserId).Returns("admin-1");
var options = new DbContextOptionsBuilder<JobTrackerContext>()
.UseSqlite(connection)
.Options;
await using var db = new JobTrackerContext(options, currentUser.Object);
await db.Database.EnsureCreatedAsync();
var member = User("user-1");
db.Users.Add(member);
db.UserSessions.Add(new UserSession
{
Id = "member-session",
UserId = member.Id,
CreatedAtUtc = DateTimeOffset.UtcNow,
LastSeenAtUtc = DateTimeOffset.UtcNow,
ExpiresAtUtc = DateTimeOffset.UtcNow.AddDays(1)
});
db.TrustedDevices.Add(new TrustedDevice
{
UserId = member.Id,
TokenHash = "device-hash",
CreatedAtUtc = DateTimeOffset.UtcNow,
ExpiresAtUtc = DateTimeOffset.UtcNow.AddDays(30)
});
await db.SaveChangesAsync();
var users = TestHostFactory.CreateUserManager(member);
users.Setup(x => x.GetRolesAsync(member)).ReturnsAsync([]);
users.Setup(x => x.AddToRoleAsync(member, "Admin")).ReturnsAsync(IdentityResult.Success);
var controller = CreateController(users, "admin-1", db);
var result = await controller.SetRoles(member.Id, new UsersController.SetRolesRequest(["Admin"]), CancellationToken.None);
Assert.IsType<NoContentResult>(result);
var session = await db.UserSessions.IgnoreQueryFilters().SingleAsync(x => x.Id == "member-session");
Assert.NotNull(session.RevokedAtUtc);
Assert.Empty(await db.TrustedDevices.IgnoreQueryFilters().Where(x => x.UserId == member.Id).ToListAsync());
}
[Fact]
public async Task Delete_rejects_deleting_the_final_administrator()
{
@@ -159,6 +204,7 @@ public sealed class UsersControllerTests
new UpperInvariantLookupNormalizer(),
new IdentityErrorDescriber(),
new NullLogger<RoleManager<IdentityRole>>());
roles.Setup(manager => manager.RoleExistsAsync(It.IsAny<string>())).ReturnsAsync(true);
var controller = new UsersController(
users.Object,