1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-04 12:40:22 -05:00

[PM-14406] Fix security task email sends (#5571)

* convert `AdminOwnerEmails` to List rather than IEnumerable

* check for JSON array in `formatAdminOwnerEmails`

* remove trailing comma for admin/owners

* Use display block on tables to enforce padding

* update padding around review at-risk passwords
This commit is contained in:
Nick Krantz 2025-03-31 14:00:43 -05:00 committed by GitHub
parent 0579fb0e68
commit 9c16127bd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 33 additions and 12 deletions

View File

@ -14,18 +14,17 @@
</td>
</tr>
</table>
<table width="100%" border="0" cellpadding="0" cellspacing="0"
style="display: table; width:100%; padding-bottom: 24px; text-align: center;" align="center">
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="padding-bottom: 24px; padding-left: 24px; padding-right: 24px; text-align: center;" align="center">
<tr>
<td display="display: table-cell">
<td>
<a href="{{ReviewPasswordsUrl}}" clicktracking=off target="_blank"
style="display: inline-block; font-weight: bold; color: #ffffff; text-decoration: none; text-align: center; cursor: pointer; border-radius: 999px; background-color: #175DDC; border-color: #175DDC; border-style: solid; border-width: 10px 20px; margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
Review at-risk passwords
</a>
</td>
</tr>
<table width="100%" border="0" cellpadding="0" cellspacing="0"
style="display: table; width:100%; padding-bottom: 24px; text-align: center;" align="center">
</table>
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="padding-bottom: 24px; padding-left: 24px; padding-right: 24px; text-align: center;" align="center">
<tr>
<td display="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-style: normal; font-weight: 400; font-size: 12px; line-height: 16px;">
{{formatAdminOwnerEmails AdminOwnerEmails}}

View File

@ -8,7 +8,7 @@ public class SecurityTaskNotificationViewModel : BaseMailModel
public bool TaskCountPlural => TaskCount != 1;
public IEnumerable<string> AdminOwnerEmails { get; set; }
public List<string> AdminOwnerEmails { get; set; }
public string ReviewPasswordsUrl => $"{WebVaultUrl}/browser-extension-prompt";
}

View File

@ -1,5 +1,6 @@
using System.Net;
using System.Reflection;
using System.Text.Json;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Models.Mail;
@ -752,7 +753,21 @@ public class HandlebarsMailService : IMailService
return;
}
var emailList = ((IEnumerable<string>)parameters[0]).ToList();
var emailList = new List<string>();
if (parameters[0] is JsonElement jsonElement && jsonElement.ValueKind == JsonValueKind.Array)
{
emailList = jsonElement.EnumerateArray().Select(e => e.GetString()).ToList();
}
else if (parameters[0] is IEnumerable<string> emails)
{
emailList = emails.ToList();
}
else
{
writer.WriteSafeString(string.Empty);
return;
}
if (emailList.Count == 0)
{
writer.WriteSafeString(string.Empty);
@ -774,7 +789,7 @@ public class HandlebarsMailService : IMailService
{
outputMessage += string.Join(", ", emailList.Take(emailList.Count - 1)
.Select(email => constructAnchorElement(email)));
outputMessage += $", and {constructAnchorElement(emailList.Last())}.";
outputMessage += $" and {constructAnchorElement(emailList.Last())}.";
}
writer.WriteSafeString($"{outputMessage}");
@ -1250,7 +1265,7 @@ public class HandlebarsMailService : IMailService
{
OrgName = CoreHelpers.SanitizeForEmail(sanitizedOrgName, false),
TaskCount = notification.TaskCount,
AdminOwnerEmails = adminOwnerEmails,
AdminOwnerEmails = adminOwnerEmails.ToList(),
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
};
message.Category = "SecurityTasksNotification";

View File

@ -48,9 +48,16 @@ public class CreateManyTaskNotificationsCommand : ICreateManyTaskNotificationsCo
}).ToList();
var organization = await _organizationRepository.GetByIdAsync(orgId);
var orgAdminEmails = await _organizationUserRepository.GetManyDetailsByRoleAsync(orgId, OrganizationUserType.Admin);
var orgOwnerEmails = await _organizationUserRepository.GetManyDetailsByRoleAsync(orgId, OrganizationUserType.Owner);
var orgAdminAndOwnerEmails = orgAdminEmails.Concat(orgOwnerEmails).Select(x => x.Email).Distinct().ToList();
var orgAdminEmails = (await _organizationUserRepository.GetManyDetailsByRoleAsync(orgId, OrganizationUserType.Admin))
.Select(u => u.Email)
.ToList();
var orgOwnerEmails = (await _organizationUserRepository.GetManyDetailsByRoleAsync(orgId, OrganizationUserType.Owner))
.Select(u => u.Email)
.ToList();
// Ensure proper deserialization of emails
var orgAdminAndOwnerEmails = orgAdminEmails.Concat(orgOwnerEmails).Distinct().ToList();
await _mailService.SendBulkSecurityTaskNotificationsAsync(organization, userTaskCount, orgAdminAndOwnerEmails);