From ea1370847fb442583e42e2609f992b7976da78ce Mon Sep 17 00:00:00 2001 From: Alexandre Brandizzi Date: Fri, 25 Sep 2026 13:46:37 -0300 Subject: [PATCH] test(auth): move the password-policy reset case onto hashed, attempt-counted codes --- .../PasswordPolicyTests.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs b/Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs index b33d466..8183cf3 100644 --- a/Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs +++ b/Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs @@ -9,6 +9,7 @@ using Moq; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.Configuration; using SeaHaven.Services.DTOs; +using SeaHaven.Services.Helpers; using SeaHaven.Services.Implementation; using SeaHaven.Services.Interfaces; using Xunit; @@ -132,7 +133,8 @@ public sealed class PasswordPolicyTests : IAsyncDisposable Microsoft.Extensions.Options.Options.Create(new JwtOptions { Secret = new string('x', 64) }), Mock.Of(), Mock.Of(), - Mock.Of()); + Mock.Of(), + TimeProvider.System); var result = await service.ChangePasswordAsync(user.Id, CurrentPassword, "Next2@x", CancellationToken.None); @@ -169,10 +171,19 @@ public sealed class PasswordPolicyTests : IAsyncDisposable { var user = await CreateUserAsync(); var forget = new Mock(); - forget.Setup(f => f.ExistsByEmailAndCodeAsync(user.Email!, "123456", It.IsAny())) - .ReturnsAsync(true); + var salt = PasswordResetCodeSecrets.NewSalt(); forget.Setup(f => f.GetByEmailAsync(user.Email!, It.IsAny())) - .ReturnsAsync(new ForgetPasswordCode { Email = user.Email!, UserId = user.Id, Code = "123456" }); + .ReturnsAsync(new ForgetPasswordCode + { + Id = 7, + Email = user.Email!, + UserId = user.Id, + CodeSalt = salt, + CodeHash = PasswordResetCodeSecrets.Hash(salt, "123456"), + ExpiresAtUtc = DateTime.UtcNow.AddMinutes(10) + }); + forget.Setup(f => f.TryConsumeAttemptAsync(7, It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(true); var service = NewAuthenticationService(forget); var reset = await service.ResetPasswordAsync(user.Email!, "123456", "abcdef", CancellationToken.None); @@ -180,6 +191,7 @@ public sealed class PasswordPolicyTests : IAsyncDisposable reset.Should().BeFalse(); (await UserManager.CheckPasswordAsync(user, CurrentPassword)).Should().BeTrue(); forget.Verify(f => f.RemoveByEmailAsync(It.IsAny(), It.IsAny()), Times.Never); + forget.Verify(f => f.RefundAttemptAsync(7, It.IsAny()), Times.Once); } private async Task> ValidateAsync(ApplicationUser user, string password) @@ -208,7 +220,8 @@ public sealed class PasswordPolicyTests : IAsyncDisposable Microsoft.Extensions.Options.Options.Create(new JwtOptions { Secret = new string('x', 64) }), Mock.Of(), (forget ?? new Mock()).Object, - Mock.Of()); + Mock.Of(), + TimeProvider.System); public async ValueTask DisposeAsync() {