shoc-backend/SeaHaven.DataServices/Interfaces/IForgetPasswordDataService.cs
Alexandre Brandizzi 77a10e38ca fix(auth): cap reset abuse per account, key code hashes, send reset email off the request path
- Forgot Password is limited to 3 codes an hour and 10 a day per email, and
  an account gets 10 failed code checks a day across every code it is sent,
  so new client addresses and new codes no longer buy more guesses. Refused
  requests answer exactly like accepted ones.
- The reset email is queued to a background sender, and unregistered
  addresses store a row no code can match, so both paths do the same work
  and return without waiting on the mail provider. Each request also clears
  expired codes.
- Code hashes are HMAC-SHA256 under a key derived with HKDF from the JWT
  signing secret; rows in the previous unkeyed format stop matching.
- Email and code are read only from the JSON body.
2026-09-25 13:00:03 -03:00

29 lines
1.3 KiB
C#

using Data.SeaHavenIndustries;
namespace SeaHaven.DataServices.Interfaces
{
public interface IForgetPasswordDataService
{
/// <summary>
/// In one transaction, deletes every pending code for the email and every expired
/// code, then stores the new one.
/// </summary>
Task ReplaceCodeAsync(string email, string userId, string codeHash, string codeSalt, DateTime expiresAtUtc, DateTime nowUtc, CancellationToken cancellationToken);
Task PurgeExpiredAsync(DateTime nowUtc, CancellationToken cancellationToken);
/// <summary>Returns the pending code for exactly this email, or null.</summary>
Task<ForgetPasswordCode?> GetByEmailAsync(string email, CancellationToken cancellationToken);
/// <summary>
/// Atomically consumes one attempt when the code is unexpired and has fewer
/// than <paramref name="maxAttempts"/> consumed. Returns false otherwise.
/// </summary>
Task<bool> TryConsumeAttemptAsync(int id, int maxAttempts, DateTime nowUtc, CancellationToken cancellationToken);
/// <summary>Gives back an attempt consumed by a check that matched.</summary>
Task RefundAttemptAsync(int id, CancellationToken cancellationToken);
Task RemoveByEmailAsync(string email, CancellationToken cancellationToken);
}
}