diff --git a/src/Core/MailTemplates/Handlebars/OrganizationUserRemovedForPolicyTwoStep.html.hbs b/src/Core/MailTemplates/Handlebars/OrganizationUserRemovedForPolicyTwoStep.html.hbs new file mode 100644 index 000000000..c28185566 --- /dev/null +++ b/src/Core/MailTemplates/Handlebars/OrganizationUserRemovedForPolicyTwoStep.html.hbs @@ -0,0 +1,15 @@ +{{#>FullHtmlLayout}} + + + + + + + +
+ Your user account has been removed from the {{OrganizationName}} organization because you do not have two-step login configured. Before you can re-join this organization you need to set up two-step login on your user account. +
+ Learn how to enable two-step login on your user account at + https://help.bitwarden.com/article/setup-two-step-login/ +
+{{/FullHtmlLayout}} diff --git a/src/Core/MailTemplates/Handlebars/OrganizationUserRemovedForPolicyTwoStep.text.hbs b/src/Core/MailTemplates/Handlebars/OrganizationUserRemovedForPolicyTwoStep.text.hbs new file mode 100644 index 000000000..a79afb588 --- /dev/null +++ b/src/Core/MailTemplates/Handlebars/OrganizationUserRemovedForPolicyTwoStep.text.hbs @@ -0,0 +1,7 @@ +{{#>BasicTextLayout}} +Your user account has been removed from the {{OrganizationName}} organization because you do not have two-step login +configured. Before you can re-join this organization you need to set up two-step login on your user account. + +Learn how to enable two-step login on your user account at + +{{/BasicTextLayout}} \ No newline at end of file diff --git a/src/Core/Models/Mail/OrganizationUserRemovedForPolicyTwoStepViewModel.cs b/src/Core/Models/Mail/OrganizationUserRemovedForPolicyTwoStepViewModel.cs new file mode 100644 index 000000000..10beaa5d7 --- /dev/null +++ b/src/Core/Models/Mail/OrganizationUserRemovedForPolicyTwoStepViewModel.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Models.Mail +{ + public class OrganizationUserRemovedForPolicyTwoStepViewModel : BaseMailModel + { + public string OrganizationName { get; set; } + } +} diff --git a/src/Core/Services/IMailService.cs b/src/Core/Services/IMailService.cs index c44d86855..72c4e5b01 100644 --- a/src/Core/Services/IMailService.cs +++ b/src/Core/Services/IMailService.cs @@ -19,6 +19,7 @@ namespace Bit.Core.Services Task SendOrganizationAcceptedEmailAsync(string organizationName, string userEmail, IEnumerable adminEmails); Task SendOrganizationConfirmedEmailAsync(string organizationName, string email); + Task SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(string organizationName, string email); Task SendPasswordlessSignInAsync(string returnUrl, string token, string email); Task SendInvoiceUpcomingAsync(string email, decimal amount, DateTime dueDate, List items, bool mentionInvoices); diff --git a/src/Core/Services/Implementations/HandlebarsMailService.cs b/src/Core/Services/Implementations/HandlebarsMailService.cs index 8c7a223ae..2bd6bcc84 100644 --- a/src/Core/Services/Implementations/HandlebarsMailService.cs +++ b/src/Core/Services/Implementations/HandlebarsMailService.cs @@ -186,6 +186,20 @@ namespace Bit.Core.Services await _mailDeliveryService.SendEmailAsync(message); } + public async Task SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(string organizationName, string email) + { + var message = CreateDefaultMessage($"You have been removed from {organizationName}", email); + var model = new OrganizationUserRemovedForPolicyTwoStepViewModel + { + OrganizationName = CoreHelpers.SanitizeForEmail(organizationName), + WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash, + SiteName = _globalSettings.SiteName + }; + await AddMessageContentAsync(message, "OrganizationUserRemovedForPolicyTwoStep", model); + message.Category = "OrganizationUserRemovedForPolicyTwoStep"; + await _mailDeliveryService.SendEmailAsync(message); + } + public async Task SendWelcomeEmailAsync(User user) { var message = CreateDefaultMessage("Welcome", user.Email); diff --git a/src/Core/Services/Implementations/PolicyService.cs b/src/Core/Services/Implementations/PolicyService.cs index 361966276..fa2c5164b 100644 --- a/src/Core/Services/Implementations/PolicyService.cs +++ b/src/Core/Services/Implementations/PolicyService.cs @@ -13,17 +13,20 @@ namespace Bit.Core.Services private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IPolicyRepository _policyRepository; + private readonly IMailService _mailService; public PolicyService( IEventService eventService, IOrganizationRepository organizationRepository, IOrganizationUserRepository organizationUserRepository, - IPolicyRepository policyRepository) + IPolicyRepository policyRepository, + IMailService mailService) { _eventService = eventService; _organizationRepository = organizationRepository; _organizationUserRepository = organizationUserRepository; _policyRepository = policyRepository; + _mailService = mailService; } public async Task SaveAsync(Policy policy, IUserService userService, IOrganizationService organizationService, @@ -52,6 +55,7 @@ namespace Bit.Core.Services { if(currentPolicy.Type == Enums.PolicyType.TwoFactorAuthentication) { + Organization organization = null; var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync( policy.OrganizationId); foreach(var orgUser in orgUsers.Where(ou => @@ -60,8 +64,14 @@ namespace Bit.Core.Services { if(orgUser.UserId != savingUserId && !await userService.TwoFactorIsEnabledAsync(orgUser)) { + if(organization == null) + { + organization = await _organizationRepository.GetByIdAsync(policy.OrganizationId); + } await organizationService.DeleteUserAsync(policy.OrganizationId, orgUser.Id, savingUserId); + await _mailService.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync( + organization.Name, orgUser.Email); } } } diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index ce221b672..0ccdfffbf 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -669,6 +669,9 @@ namespace Bit.Core.Services if(!ownerOrgs.Contains(policy.OrganizationId)) { await organizationService.DeleteUserAsync(policy.OrganizationId, user.Id); + var organization = await _organizationRepository.GetByIdAsync(policy.OrganizationId); + await _mailService.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync( + organization.Name, user.Email); } } } diff --git a/src/Core/Services/NoopImplementations/NoopMailService.cs b/src/Core/Services/NoopImplementations/NoopMailService.cs index 5fb3f0c11..bdbb742d7 100644 --- a/src/Core/Services/NoopImplementations/NoopMailService.cs +++ b/src/Core/Services/NoopImplementations/NoopMailService.cs @@ -47,6 +47,11 @@ namespace Bit.Core.Services return Task.FromResult(0); } + public Task SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(string organizationName, string email) + { + return Task.FromResult(0); + } + public Task SendTwoFactorEmailAsync(string email, string token) { return Task.FromResult(0);