|
12 | 12 |
|
13 | 13 | namespace Resgrid.Framework |
14 | 14 | { |
| 15 | + /// <summary> |
| 16 | + /// Result of password complexity verification |
| 17 | + /// </summary> |
| 18 | + public sealed record PasswordComplexityResult( |
| 19 | + bool IsValid, |
| 20 | + List<string> Errors); |
| 21 | + |
15 | 22 | public static class StringHelpers |
16 | 23 | { |
17 | 24 | /// <summary> |
@@ -247,5 +254,79 @@ public static string SanitizeCoordinatesString(string source) |
247 | 254 | return resultStrBuilder.ToString(); |
248 | 255 | } |
249 | 256 |
|
| 257 | + /// <summary> |
| 258 | + /// Verifies password complexity against security requirements |
| 259 | + /// </summary> |
| 260 | + /// <param name="password">The password to verify</param> |
| 261 | + /// <param name="minLength">Minimum password length (default: 8)</param> |
| 262 | + /// <param name="requireUppercase">Require at least one uppercase letter (default: true)</param> |
| 263 | + /// <param name="requireLowercase">Require at least one lowercase letter (default: true)</param> |
| 264 | + /// <param name="requireDigit">Require at least one digit (default: true)</param> |
| 265 | + /// <param name="requireSpecialChar">Require at least one special character (default: false)</param> |
| 266 | + /// <returns>PasswordComplexityResult indicating validity and any errors</returns> |
| 267 | + public static PasswordComplexityResult VerifyPasswordComplexity( |
| 268 | + string password, |
| 269 | + int minLength = 8, |
| 270 | + bool requireUppercase = true, |
| 271 | + bool requireLowercase = true, |
| 272 | + bool requireDigit = true, |
| 273 | + bool requireSpecialChar = false) |
| 274 | + { |
| 275 | + var errors = new List<string>(); |
| 276 | + |
| 277 | + if (string.IsNullOrWhiteSpace(password)) |
| 278 | + { |
| 279 | + errors.Add("Password cannot be empty"); |
| 280 | + return new PasswordComplexityResult(false, errors); |
| 281 | + } |
| 282 | + |
| 283 | + // Check minimum length |
| 284 | + if (password.Length < minLength) |
| 285 | + { |
| 286 | + errors.Add($"Password must be at least {minLength} characters long"); |
| 287 | + } |
| 288 | + |
| 289 | + // Check for uppercase letter |
| 290 | + if (requireUppercase && !password.Any(char.IsUpper)) |
| 291 | + { |
| 292 | + errors.Add("Password must include an uppercase letter"); |
| 293 | + } |
| 294 | + |
| 295 | + // Check for lowercase letter |
| 296 | + if (requireLowercase && !password.Any(char.IsLower)) |
| 297 | + { |
| 298 | + errors.Add("Password must include a lowercase letter"); |
| 299 | + } |
| 300 | + |
| 301 | + // Check for digit |
| 302 | + if (requireDigit && !password.Any(char.IsDigit)) |
| 303 | + { |
| 304 | + errors.Add("Password must include a number (digit)"); |
| 305 | + } |
| 306 | + |
| 307 | + // Check for special character |
| 308 | + if (requireSpecialChar) |
| 309 | + { |
| 310 | + var specialChars = "!@#$%^&*()_+-=[]{}|;:,.<>?"; |
| 311 | + if (!password.Any(c => specialChars.Contains(c))) |
| 312 | + { |
| 313 | + errors.Add("Password must include a special character"); |
| 314 | + } |
| 315 | + } |
| 316 | + |
| 317 | + return new PasswordComplexityResult(errors.Count == 0, errors); |
| 318 | + } |
| 319 | + |
| 320 | + /// <summary> |
| 321 | + /// Validates password complexity using default Resgrid requirements |
| 322 | + /// </summary> |
| 323 | + /// <param name="password">The password to validate</param> |
| 324 | + /// <returns>True if password meets complexity requirements</returns> |
| 325 | + public static bool IsValidPassword(string password) |
| 326 | + { |
| 327 | + var result = VerifyPasswordComplexity(password); |
| 328 | + return result.IsValid; |
| 329 | + } |
| 330 | + |
250 | 331 | } |
251 | 332 | } |
0 commit comments