diff --git a/src/Core/Services/Implementations/HandlebarsMailService.cs b/src/Core/Services/Implementations/HandlebarsMailService.cs index 8aabb3a715..d4e7c581bf 100644 --- a/src/Core/Services/Implementations/HandlebarsMailService.cs +++ b/src/Core/Services/Implementations/HandlebarsMailService.cs @@ -151,7 +151,7 @@ namespace Bit.Core.Services var model = new OrganizationUserAcceptedViewModel { OrganizationId = organization.Id, - OrganizationName = CoreHelpers.SanitizeForEmail(organization.Name), + OrganizationName = CoreHelpers.SanitizeForEmail(organization.Name, false), UserIdentifier = userIdentifier, WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash, SiteName = _globalSettings.SiteName @@ -166,7 +166,7 @@ namespace Bit.Core.Services var message = CreateDefaultMessage($"You Have Been Confirmed To {organizationName}", email); var model = new OrganizationUserConfirmedViewModel { - OrganizationName = CoreHelpers.SanitizeForEmail(organizationName), + OrganizationName = CoreHelpers.SanitizeForEmail(organizationName, false), WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash, SiteName = _globalSettings.SiteName }; @@ -189,7 +189,7 @@ namespace Bit.Core.Services var messageModels = invites.Select(invite => CreateMessage(invite.orgUser.Email, new OrganizationUserInvitedViewModel { - OrganizationName = CoreHelpers.SanitizeForEmail(organizationName), + OrganizationName = CoreHelpers.SanitizeForEmail(organizationName, false), Email = WebUtility.UrlEncode(invite.orgUser.Email), OrganizationId = invite.orgUser.OrganizationId.ToString(), OrganizationUserId = invite.orgUser.Id.ToString(), @@ -209,7 +209,7 @@ namespace Bit.Core.Services var message = CreateDefaultMessage($"You have been removed from {organizationName}", email); var model = new OrganizationUserRemovedForPolicyTwoStepViewModel { - OrganizationName = CoreHelpers.SanitizeForEmail(organizationName), + OrganizationName = CoreHelpers.SanitizeForEmail(organizationName, false), WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash, SiteName = _globalSettings.SiteName }; @@ -302,7 +302,7 @@ namespace Bit.Core.Services var message = CreateDefaultMessage("License Expired", emails); var model = new LicenseExpiredViewModel { - OrganizationName = organizationName, + OrganizationName = CoreHelpers.SanitizeForEmail(organizationName, false), }; await AddMessageContentAsync(message, "LicenseExpired", model); message.Category = "LicenseExpired"; @@ -349,7 +349,7 @@ namespace Bit.Core.Services var message = CreateDefaultMessage($"You have been removed from {organizationName}", email); var model = new OrganizationUserRemovedForPolicySingleOrgViewModel { - OrganizationName = CoreHelpers.SanitizeForEmail(organizationName), + OrganizationName = CoreHelpers.SanitizeForEmail(organizationName, false), WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash, SiteName = _globalSettings.SiteName }; diff --git a/src/Core/Utilities/CoreHelpers.cs b/src/Core/Utilities/CoreHelpers.cs index 58de340a87..2c219db782 100644 --- a/src/Core/Utilities/CoreHelpers.cs +++ b/src/Core/Utilities/CoreHelpers.cs @@ -555,12 +555,20 @@ namespace Bit.Core.Utilities return sb.ToString(); } - public static string SanitizeForEmail(string value) + public static string SanitizeForEmail(string value, bool htmlEncode = true) { - var cleanedValue = value.Replace("@", "[at]") - .Replace("http://", string.Empty) - .Replace("https://", string.Empty); - return HttpUtility.HtmlEncode(cleanedValue); + var cleanedValue = value.Replace("@", "[at]"); + var regexOptions = RegexOptions.CultureInvariant | + RegexOptions.Singleline | + RegexOptions.IgnoreCase; + cleanedValue = Regex.Replace(cleanedValue, @"(\.\w)", + m => string.Concat("[dot]", m.ToString().Last()), regexOptions); + while (Regex.IsMatch(cleanedValue, @"((^|\b)(\w*)://)", regexOptions)) + { + cleanedValue = Regex.Replace(cleanedValue, @"((^|\b)(\w*)://)", + string.Empty, regexOptions); + } + return htmlEncode ? HttpUtility.HtmlEncode(cleanedValue) : cleanedValue; } public static string DateTimeToTableStorageKey(DateTime? date = null)