-
-
Notifications
You must be signed in to change notification settings - Fork 76
CU-868f7n1u3 Adding in Countly for analytics. PW validation fix. #244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| using System; | ||
| using System.ComponentModel.DataAnnotations; | ||
| using System.Linq; | ||
|
|
||
| namespace Resgrid.Framework | ||
| { | ||
| /// <summary> | ||
| /// Validation attribute for password complexity requirements | ||
| /// </summary> | ||
| [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] | ||
| public sealed class PasswordComplexityAttribute : ValidationAttribute | ||
| { | ||
| public int MinLength { get; set; } = 8; | ||
| public bool RequireUppercase { get; set; } = true; | ||
| public bool RequireLowercase { get; set; } = true; | ||
| public bool RequireDigit { get; set; } = true; | ||
| public bool RequireSpecialChar { get; set; } = false; | ||
|
|
||
| public PasswordComplexityAttribute() | ||
| { | ||
| ErrorMessage = "Password does not meet complexity requirements"; | ||
| } | ||
|
|
||
| public override bool IsValid(object value) | ||
| { | ||
| if (value is not string password) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| var result = StringHelpers.VerifyPasswordComplexity( | ||
| password, | ||
| MinLength, | ||
| RequireUppercase, | ||
| RequireLowercase, | ||
| RequireDigit, | ||
| RequireSpecialChar); | ||
|
|
||
| return result.IsValid; | ||
| } | ||
|
|
||
| protected override ValidationResult IsValid(object value, ValidationContext validationContext) | ||
| { | ||
| if (value is not string password) | ||
| { | ||
| return new ValidationResult("Invalid password format"); | ||
| } | ||
|
|
||
| var result = StringHelpers.VerifyPasswordComplexity( | ||
| password, | ||
| MinLength, | ||
| RequireUppercase, | ||
| RequireLowercase, | ||
| RequireDigit, | ||
| RequireSpecialChar); | ||
|
|
||
| if (result.IsValid) | ||
| { | ||
| return ValidationResult.Success; | ||
| } | ||
|
|
||
| var errorMessage = string.Join(", ", result.Errors); | ||
| return new ValidationResult(errorMessage, new[] { validationContext.MemberName }); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| using System; | ||
| using System.Linq; | ||
| using Resgrid.Framework; | ||
|
|
||
| namespace Resgrid.Tests.Framework | ||
| { | ||
| /// <summary> | ||
| /// Example usage and tests for password complexity verification | ||
| /// </summary> | ||
| public static class PasswordComplexityExamples | ||
| { | ||
| /// <summary> | ||
| /// Demonstrates how to use the password complexity verification | ||
| /// </summary> | ||
| public static void RunExamples() | ||
| { | ||
| // Test cases | ||
| var testPasswords = new[] | ||
| { | ||
| "abc123", // Too short, no uppercase | ||
| "ABC123", // No lowercase | ||
| "abcDEF", // No digits | ||
| "Abc123", // Valid according to default requirements | ||
| "Password123", // Valid | ||
| "MyPassword1", // Valid | ||
| "", // Empty | ||
| "Abc123!@#" // Valid with special chars | ||
| }; | ||
|
|
||
| Console.WriteLine("Password Complexity Verification Examples:"); | ||
| Console.WriteLine("========================================="); | ||
|
|
||
| foreach (var password in testPasswords) | ||
| { | ||
| var result = StringHelpers.VerifyPasswordComplexity(password); | ||
| Console.WriteLine($"Password: '{password}'"); | ||
| Console.WriteLine($"Valid: {result.IsValid}"); | ||
| if (!result.IsValid) | ||
| { | ||
| Console.WriteLine($"Errors: {string.Join(", ", result.Errors)}"); | ||
| } | ||
| Console.WriteLine(); | ||
| } | ||
|
|
||
| // Test with custom requirements matching current RegisterViewModel | ||
| Console.WriteLine("Resgrid Default Requirements:"); | ||
| Console.WriteLine("============================"); | ||
|
|
||
| var resgridDefaults = new[] | ||
| { | ||
| "abc123", // Should fail | ||
| "Password1", // Should pass | ||
| "MySecurePass123" // Should pass | ||
| }; | ||
|
|
||
| foreach (var password in resgridDefaults) | ||
| { | ||
| var result = StringHelpers.VerifyPasswordComplexity( | ||
| password, | ||
| minLength: 8, | ||
| requireUppercase: true, | ||
| requireLowercase: true, | ||
| requireDigit: true, | ||
| requireSpecialChar: false); | ||
|
|
||
| Console.WriteLine($"Password: '{password}'"); | ||
| Console.WriteLine($"Valid: {result.IsValid}"); | ||
| if (!result.IsValid) | ||
| { | ||
| Console.WriteLine($"Errors: {string.Join(", ", result.Errors)}"); | ||
| } | ||
| Console.WriteLine(); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Simple validation method for quick checks using Resgrid defaults | ||
| /// </summary> | ||
| public static bool ValidatePasswordForResgrid(string password) | ||
| { | ||
| return StringHelpers.VerifyPasswordComplexity( | ||
| password, | ||
| minLength: 8, | ||
| requireUppercase: true, | ||
| requireLowercase: true, | ||
| requireDigit: true, | ||
| requireSpecialChar: false).IsValid; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,10 +5,12 @@ namespace Resgrid.Web.Models.AccountViewModels | |||||||||||
| public class LoginViewModel | ||||||||||||
| { | ||||||||||||
| [Required] | ||||||||||||
| public string Username { get; set; } | ||||||||||||
| [StringLength(250, ErrorMessage = "The username must be at least 2 characters long and contain only alphanumeric characters.", MinimumLength = 2)] | ||||||||||||
| public string Username { get; set; } | ||||||||||||
|
|
||||||||||||
| [Required] | ||||||||||||
| [DataType(DataType.Password)] | ||||||||||||
| [StringLength(100, ErrorMessage = "The password must be at least 8 characters long, include a number (digit) and an uppercase letter", MinimumLength = 4)] | ||||||||||||
| [DataType(DataType.Password)] | ||||||||||||
| public string Password { get; set; } | ||||||||||||
|
Comment on lines
+12
to
14
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Login password length constraint may block valid users Enforcing min length here can prevent sign-in for legacy accounts whose passwords predate current policy. Recommend removing StringLength (validation occurs on change/reset), or align MinimumLength with current policy (8) if you’re certain no existing accounts fall below. - [StringLength(100, ErrorMessage = "The password must be at least 8 characters long, include a number (digit) and an uppercase letter", MinimumLength = 4)]
- [DataType(DataType.Password)]
+ [DataType(DataType.Password)]📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
|
|
||||||||||||
| [Display(Name = "Remember me?")] | ||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Username error message contradicts actual allowed characters
Identity allows spaces and -._@ (see Startup configuration). Either adjust the message or add a regex to enforce the identity-allowed set. Suggested: simplify the message.
📝 Committable suggestion
🤖 Prompt for AI Agents