From 7abb05391406a8ed29645db117afecf1c976946e Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Fri, 16 Jul 2021 08:01:51 +1000 Subject: [PATCH] Refactor email attributes (#1458) * Add StrictEmailAddress attribute * Remove duplicate checks, use attributes instead * Rename EmailAddressListAttribute --- .../Request/MemberCreateRequestModel.cs | 20 +++---------- .../Api/Request/Accounts/EmailRequestModel.cs | 3 +- .../Request/Accounts/RegisterRequestModel.cs | 3 +- .../OrganizationUserRequestModels.cs | 2 +- .../Providers/ProviderUserRequestModels.cs | 2 +- .../Utilities/StrictEmailAddressAttribute.cs | 30 +++++++++++++++++++ ....cs => StrictEmailAddressListAttribute.cs} | 6 ++-- 7 files changed, 43 insertions(+), 23 deletions(-) create mode 100644 src/Core/Utilities/StrictEmailAddressAttribute.cs rename src/Core/Utilities/{EmailAddressListAttribute.cs => StrictEmailAddressListAttribute.cs} (83%) diff --git a/src/Core/Models/Api/Public/Request/MemberCreateRequestModel.cs b/src/Core/Models/Api/Public/Request/MemberCreateRequestModel.cs index a95d87deb9..58b4113bf2 100644 --- a/src/Core/Models/Api/Public/Request/MemberCreateRequestModel.cs +++ b/src/Core/Models/Api/Public/Request/MemberCreateRequestModel.cs @@ -2,36 +2,24 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using Bit.Core.Models.Table; +using Bit.Core.Utilities; namespace Bit.Core.Models.Api.Public { - public class MemberCreateRequestModel : MemberUpdateRequestModel, IValidatableObject + public class MemberCreateRequestModel : MemberUpdateRequestModel { /// /// The member's email address. /// /// jsmith@example.com [Required] - [EmailAddress] + [StringLength(256)] + [StrictEmailAddress] public string Email { get; set; } public override OrganizationUser ToOrganizationUser(OrganizationUser existingUser) { throw new NotImplementedException(); } - - public IEnumerable Validate(ValidationContext validationContext) - { - if (Email.Contains(" ") || Email.Contains("<")) - { - yield return new ValidationResult($"Email is not valid.", - new string[] { nameof(Email) }); - } - else if (Email.Length > 256) - { - yield return new ValidationResult($"Email is longer than 256 characters.", - new string[] { nameof(Email) }); - } - } } } diff --git a/src/Core/Models/Api/Request/Accounts/EmailRequestModel.cs b/src/Core/Models/Api/Request/Accounts/EmailRequestModel.cs index f29324bf92..b62a06b189 100644 --- a/src/Core/Models/Api/Request/Accounts/EmailRequestModel.cs +++ b/src/Core/Models/Api/Request/Accounts/EmailRequestModel.cs @@ -1,12 +1,13 @@ using System; using System.ComponentModel.DataAnnotations; +using Bit.Core.Utilities; namespace Bit.Core.Models.Api { public class EmailRequestModel { [Required] - [EmailAddress] + [StrictEmailAddress] [StringLength(256)] public string NewEmail { get; set; } [Required] diff --git a/src/Core/Models/Api/Request/Accounts/RegisterRequestModel.cs b/src/Core/Models/Api/Request/Accounts/RegisterRequestModel.cs index 58a6db8485..6e7fda791f 100644 --- a/src/Core/Models/Api/Request/Accounts/RegisterRequestModel.cs +++ b/src/Core/Models/Api/Request/Accounts/RegisterRequestModel.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using Bit.Core.Enums; using Bit.Core.Models.Business; using Bit.Core.Models.Table; +using Bit.Core.Utilities; using Newtonsoft.Json; namespace Bit.Core.Models.Api @@ -13,7 +14,7 @@ namespace Bit.Core.Models.Api [StringLength(50)] public string Name { get; set; } [Required] - [EmailAddress] + [StrictEmailAddress] [StringLength(256)] public string Email { get; set; } [Required] diff --git a/src/Core/Models/Api/Request/Organizations/OrganizationUserRequestModels.cs b/src/Core/Models/Api/Request/Organizations/OrganizationUserRequestModels.cs index e8d74da371..1bb368d9b6 100644 --- a/src/Core/Models/Api/Request/Organizations/OrganizationUserRequestModels.cs +++ b/src/Core/Models/Api/Request/Organizations/OrganizationUserRequestModels.cs @@ -12,7 +12,7 @@ namespace Bit.Core.Models.Api public class OrganizationUserInviteRequestModel { [Required] - [EmailAddressList] + [StrictEmailAddressList] public IEnumerable Emails { get; set; } [Required] public Enums.OrganizationUserType? Type { get; set; } diff --git a/src/Core/Models/Api/Request/Providers/ProviderUserRequestModels.cs b/src/Core/Models/Api/Request/Providers/ProviderUserRequestModels.cs index f7afa59f61..7c87929628 100644 --- a/src/Core/Models/Api/Request/Providers/ProviderUserRequestModels.cs +++ b/src/Core/Models/Api/Request/Providers/ProviderUserRequestModels.cs @@ -11,7 +11,7 @@ namespace Bit.Core.Models.Api public class ProviderUserInviteRequestModel { [Required] - [EmailAddressList] + [StrictEmailAddressList] public IEnumerable Emails { get; set; } [Required] public ProviderUserType? Type { get; set; } diff --git a/src/Core/Utilities/StrictEmailAddressAttribute.cs b/src/Core/Utilities/StrictEmailAddressAttribute.cs new file mode 100644 index 0000000000..870c45f305 --- /dev/null +++ b/src/Core/Utilities/StrictEmailAddressAttribute.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Text.RegularExpressions; + +namespace Bit.Core.Utilities +{ + public class StrictEmailAddressAttribute : ValidationAttribute + { + public StrictEmailAddressAttribute() + : base("The {0} field is not a valid e-mail address.") + {} + + public override bool IsValid(object value) + { + var emailAddress = value?.ToString(); + if (emailAddress == null) + { + return false; + } + + var illegalChars = @"[\s<>()]"; + if (Regex.IsMatch(emailAddress, illegalChars)) + { + return false; + } + + return new EmailAddressAttribute().IsValid(emailAddress); + } + } +} diff --git a/src/Core/Utilities/EmailAddressListAttribute.cs b/src/Core/Utilities/StrictEmailAddressListAttribute.cs similarity index 83% rename from src/Core/Utilities/EmailAddressListAttribute.cs rename to src/Core/Utilities/StrictEmailAddressListAttribute.cs index 62f2603020..16611d58e2 100644 --- a/src/Core/Utilities/EmailAddressListAttribute.cs +++ b/src/Core/Utilities/StrictEmailAddressListAttribute.cs @@ -4,11 +4,11 @@ using System.Linq; namespace Bit.Core.Utilities { - public class EmailAddressListAttribute : ValidationAttribute + public class StrictEmailAddressListAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { - var emailAttribute = new EmailAddressAttribute(); + var strictEmailAttribute = new StrictEmailAddressAttribute(); var emails = value as IList; if (!emails?.Any() ?? true) @@ -24,7 +24,7 @@ namespace Bit.Core.Utilities for (var i = 0; i < emails.Count(); i++) { var email = emails.ElementAt(i); - if (!emailAttribute.IsValid(email) || email.Contains(" ") || email.Contains("<")) + if (!strictEmailAttribute.IsValid(email)) { return new ValidationResult($"Email #{i + 1} is not valid."); }