shoc-backend/Data.SeaHavenIndustries/Auth/IdentityPasswordPolicy.cs

47 lines
1.9 KiB
C#

using Microsoft.AspNetCore.Identity;
namespace Data.SeaHavenIndustries
{
/// <summary>
/// The single password rule for every surface that sets a password: at least
/// six characters with one uppercase letter, one number, and one special
/// character. Lowercase letters are deliberately not required so the server
/// accepts exactly what the four-item checklist in the web app marks as met.
/// </summary>
public static class IdentityPasswordPolicy
{
public const int MinimumLength = 6;
public static void Apply(PasswordOptions options)
{
ArgumentNullException.ThrowIfNull(options);
options.RequiredLength = MinimumLength;
options.RequireUppercase = true;
options.RequireDigit = true;
options.RequireNonAlphanumeric = true;
options.RequireLowercase = false;
options.RequiredUniqueChars = 1;
}
private static readonly HashSet<string> PolicyErrorCodes = new(StringComparer.Ordinal)
{
nameof(IdentityErrorDescriber.PasswordTooShort),
nameof(IdentityErrorDescriber.PasswordRequiresUpper),
nameof(IdentityErrorDescriber.PasswordRequiresLower),
nameof(IdentityErrorDescriber.PasswordRequiresDigit),
nameof(IdentityErrorDescriber.PasswordRequiresNonAlphanumeric),
nameof(IdentityErrorDescriber.PasswordRequiresUniqueChars)
};
/// <summary>
/// True when Identity refused the password itself. Other failures, such as a
/// concurrency conflict, must not be reported to the user as a weak password.
/// </summary>
public static bool IsPolicyRejection(IdentityResult result)
{
ArgumentNullException.ThrowIfNull(result);
return result.Errors.Any(error => PolicyErrorCodes.Contains(error.Code));
}
}
}