From 50a522bbd798741c15f929ac755ff6e23842f023 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 16 Aug 2017 10:59:13 -0400 Subject: [PATCH] markdown mail service when self hosted --- src/Core/Core.csproj | 64 +++--- .../MailTemplates/Markdown/ChangeEmail.md | 1 + .../Markdown/ChangeEmailAlreadyExists.md | 3 + .../Markdown/MasterPasswordHint.md | 7 + .../Markdown/NoMasterPasswordHint.md | 3 + .../Markdown/OrganizationUserAccepted.md | 5 + .../Markdown/OrganizationUserConfirmed.md | 3 + .../Markdown/OrganizationUserInvited.md | 6 + .../MailTemplates/Markdown/TwoFactorEmail.md | 3 + .../MailTemplates/Markdown/VerifyDelete.md | 3 + .../MailTemplates/Markdown/VerifyEmail.md | 3 + src/Core/MailTemplates/Markdown/Welcome.md | 37 +++ .../{ => Razor}/ChangeEmail.cshtml | 0 .../{ => Razor}/ChangeEmail.text.cshtml | 0 .../ChangeEmailAlreadyExists.cshtml | 0 .../ChangeEmailAlreadyExists.text.cshtml | 0 .../{ => Razor}/MasterPasswordHint.cshtml | 0 .../MasterPasswordHint.text.cshtml | 0 .../{ => Razor}/NoMasterPasswordHint.cshtml | 0 .../NoMasterPasswordHint.text.cshtml | 0 .../OrganizationUserAccepted.cshtml | 0 .../OrganizationUserAccepted.text.cshtml | 0 .../OrganizationUserConfirmed.cshtml | 0 .../OrganizationUserConfirmed.text.cshtml | 0 .../OrganizationUserInvited.cshtml | 0 .../OrganizationUserInvited.text.cshtml | 0 .../{ => Razor}/TwoFactorEmail.cshtml | 0 .../{ => Razor}/TwoFactorEmail.text.cshtml | 0 .../{ => Razor}/VerifyDelete.cshtml | 0 .../{ => Razor}/VerifyDelete.text.cshtml | 0 .../{ => Razor}/VerifyEmail.cshtml | 3 +- .../{ => Razor}/VerifyEmail.text.cshtml | 4 +- .../MailTemplates/{ => Razor}/Welcome.cshtml | 0 .../{ => Razor}/Welcome.text.cshtml | 0 .../{ => Razor}/_BasicMailLayout.cshtml | 0 .../{ => Razor}/_BasicMailLayout.text.cshtml | 0 .../{ => Razor}/_MailLayout.cshtml | 0 .../{ => Razor}/_MailLayout.text.cshtml | 0 .../Implementations/MarkdownMailService.cs | 210 ++++++++++++++++++ ...ViewMailService.cs => RazorMailService.cs} | 10 +- .../SendGridTemplateMailService.cs | 2 +- .../Utilities/ServiceCollectionExtensions.cs | 10 +- 42 files changed, 342 insertions(+), 35 deletions(-) create mode 100644 src/Core/MailTemplates/Markdown/ChangeEmail.md create mode 100644 src/Core/MailTemplates/Markdown/ChangeEmailAlreadyExists.md create mode 100644 src/Core/MailTemplates/Markdown/MasterPasswordHint.md create mode 100644 src/Core/MailTemplates/Markdown/NoMasterPasswordHint.md create mode 100644 src/Core/MailTemplates/Markdown/OrganizationUserAccepted.md create mode 100644 src/Core/MailTemplates/Markdown/OrganizationUserConfirmed.md create mode 100644 src/Core/MailTemplates/Markdown/OrganizationUserInvited.md create mode 100644 src/Core/MailTemplates/Markdown/TwoFactorEmail.md create mode 100644 src/Core/MailTemplates/Markdown/VerifyDelete.md create mode 100644 src/Core/MailTemplates/Markdown/VerifyEmail.md create mode 100644 src/Core/MailTemplates/Markdown/Welcome.md rename src/Core/MailTemplates/{ => Razor}/ChangeEmail.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/ChangeEmail.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/ChangeEmailAlreadyExists.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/ChangeEmailAlreadyExists.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/MasterPasswordHint.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/MasterPasswordHint.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/NoMasterPasswordHint.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/NoMasterPasswordHint.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/OrganizationUserAccepted.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/OrganizationUserAccepted.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/OrganizationUserConfirmed.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/OrganizationUserConfirmed.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/OrganizationUserInvited.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/OrganizationUserInvited.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/TwoFactorEmail.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/TwoFactorEmail.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/VerifyDelete.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/VerifyDelete.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/VerifyEmail.cshtml (66%) rename src/Core/MailTemplates/{ => Razor}/VerifyEmail.text.cshtml (53%) rename src/Core/MailTemplates/{ => Razor}/Welcome.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/Welcome.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/_BasicMailLayout.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/_BasicMailLayout.text.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/_MailLayout.cshtml (100%) rename src/Core/MailTemplates/{ => Razor}/_MailLayout.text.cshtml (100%) create mode 100644 src/Core/Services/Implementations/MarkdownMailService.cs rename src/Core/Services/Implementations/{RazorViewMailService.cs => RazorMailService.cs} (98%) diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index d466deaff..1b8966b93 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -8,36 +8,48 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Core/MailTemplates/Markdown/ChangeEmail.md b/src/Core/MailTemplates/Markdown/ChangeEmail.md new file mode 100644 index 000000000..a9aaaa2b2 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/ChangeEmail.md @@ -0,0 +1 @@ +To finalize changing your email address enter the following code in the pop-up window: {{token}} diff --git a/src/Core/MailTemplates/Markdown/ChangeEmailAlreadyExists.md b/src/Core/MailTemplates/Markdown/ChangeEmailAlreadyExists.md new file mode 100644 index 000000000..e46ab95e4 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/ChangeEmailAlreadyExists.md @@ -0,0 +1,3 @@ +A user ({{fromEmail}}) recently tried to change their account to use this email address ({{toEmail}}). An account already exists with this email ({{toEmail}}). + +If you did not try to change an email address, you can safely ignore this email. diff --git a/src/Core/MailTemplates/Markdown/MasterPasswordHint.md b/src/Core/MailTemplates/Markdown/MasterPasswordHint.md new file mode 100644 index 000000000..271e1d1c3 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/MasterPasswordHint.md @@ -0,0 +1,7 @@ +You (or someone) recently requested your master password hint. + +Your hint is: "{{hint}}" + +Login: <{{vaultUrl}}> + +If you did not request your master password hint you can safely ignore this email. diff --git a/src/Core/MailTemplates/Markdown/NoMasterPasswordHint.md b/src/Core/MailTemplates/Markdown/NoMasterPasswordHint.md new file mode 100644 index 000000000..9ae929546 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/NoMasterPasswordHint.md @@ -0,0 +1,3 @@ +You (or someone) recently requested your master password hint. Unfortunately, your account does not have a master password hint. + +If you did not request your master password hint you can safely ignore this email. diff --git a/src/Core/MailTemplates/Markdown/OrganizationUserAccepted.md b/src/Core/MailTemplates/Markdown/OrganizationUserAccepted.md new file mode 100644 index 000000000..8c6dd1bde --- /dev/null +++ b/src/Core/MailTemplates/Markdown/OrganizationUserAccepted.md @@ -0,0 +1,5 @@ +This email is to notify you that {{userEmail}} has accepted your invitation to join {{organizationName}}. + +To confirm this user, log into the bitwarden web vault, manage your organization "People" and confirm the user. + +If you do not wish to confirm this user, you can also remove them from the organization on the same page. diff --git a/src/Core/MailTemplates/Markdown/OrganizationUserConfirmed.md b/src/Core/MailTemplates/Markdown/OrganizationUserConfirmed.md new file mode 100644 index 000000000..4ef73877a --- /dev/null +++ b/src/Core/MailTemplates/Markdown/OrganizationUserConfirmed.md @@ -0,0 +1,3 @@ +This email is to notify you that you have been confirmed as a user of {{organizationName}}. + +Any collections and logins being shared with you by this organization will now appear in your bitwarden vault. diff --git a/src/Core/MailTemplates/Markdown/OrganizationUserInvited.md b/src/Core/MailTemplates/Markdown/OrganizationUserInvited.md new file mode 100644 index 000000000..55400c4e3 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/OrganizationUserInvited.md @@ -0,0 +1,6 @@ +You have been invited to join the {{organizationName}} organization. To accept this invite, click the +following link: + +<{{url}}> + +If you do not wish to join this organization, you can safely ignore this email. diff --git a/src/Core/MailTemplates/Markdown/TwoFactorEmail.md b/src/Core/MailTemplates/Markdown/TwoFactorEmail.md new file mode 100644 index 000000000..5bd8d81e8 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/TwoFactorEmail.md @@ -0,0 +1,3 @@ +Your two-step verification code is: {{token}} + +Use this code to complete logging in with bitwarden. diff --git a/src/Core/MailTemplates/Markdown/VerifyDelete.md b/src/Core/MailTemplates/Markdown/VerifyDelete.md new file mode 100644 index 000000000..b77c8a314 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/VerifyDelete.md @@ -0,0 +1,3 @@ +Click the link below to delete your bitwarden account ({{email}}). If you did not request this email to delete your bitwarden account, you can safely ignore it. + +<{{url}}> diff --git a/src/Core/MailTemplates/Markdown/VerifyEmail.md b/src/Core/MailTemplates/Markdown/VerifyEmail.md new file mode 100644 index 000000000..1355cd5e4 --- /dev/null +++ b/src/Core/MailTemplates/Markdown/VerifyEmail.md @@ -0,0 +1,3 @@ +Verify this email address for your bitwarden account by clicking the following link. If you did not request this email to verify a bitwarden account, you can safely ignore it. + +<{{Url}}> diff --git a/src/Core/MailTemplates/Markdown/Welcome.md b/src/Core/MailTemplates/Markdown/Welcome.md new file mode 100644 index 000000000..5d221a4aa --- /dev/null +++ b/src/Core/MailTemplates/Markdown/Welcome.md @@ -0,0 +1,37 @@ +Thank you for creating an account with bitwarden. You may now log in with your new account. + +Did you know that bitwarden is free to sync with all of your devices? Download bitwarden today on: + +Mobile +============ + +## iOS + + +## Android + + +Desktop +============ + +## Chrome Extension + + +## Firefox Extension + + +## Opera Extension + + +Web +============ + +You can also access your vault from any web-enabled device using our web vault at: <{{vaultUrl}}> + +------------ + +If you have any questions or problems you can email us from our website at: + + +Thank you! +The bitwarden Team diff --git a/src/Core/MailTemplates/ChangeEmail.cshtml b/src/Core/MailTemplates/Razor/ChangeEmail.cshtml similarity index 100% rename from src/Core/MailTemplates/ChangeEmail.cshtml rename to src/Core/MailTemplates/Razor/ChangeEmail.cshtml diff --git a/src/Core/MailTemplates/ChangeEmail.text.cshtml b/src/Core/MailTemplates/Razor/ChangeEmail.text.cshtml similarity index 100% rename from src/Core/MailTemplates/ChangeEmail.text.cshtml rename to src/Core/MailTemplates/Razor/ChangeEmail.text.cshtml diff --git a/src/Core/MailTemplates/ChangeEmailAlreadyExists.cshtml b/src/Core/MailTemplates/Razor/ChangeEmailAlreadyExists.cshtml similarity index 100% rename from src/Core/MailTemplates/ChangeEmailAlreadyExists.cshtml rename to src/Core/MailTemplates/Razor/ChangeEmailAlreadyExists.cshtml diff --git a/src/Core/MailTemplates/ChangeEmailAlreadyExists.text.cshtml b/src/Core/MailTemplates/Razor/ChangeEmailAlreadyExists.text.cshtml similarity index 100% rename from src/Core/MailTemplates/ChangeEmailAlreadyExists.text.cshtml rename to src/Core/MailTemplates/Razor/ChangeEmailAlreadyExists.text.cshtml diff --git a/src/Core/MailTemplates/MasterPasswordHint.cshtml b/src/Core/MailTemplates/Razor/MasterPasswordHint.cshtml similarity index 100% rename from src/Core/MailTemplates/MasterPasswordHint.cshtml rename to src/Core/MailTemplates/Razor/MasterPasswordHint.cshtml diff --git a/src/Core/MailTemplates/MasterPasswordHint.text.cshtml b/src/Core/MailTemplates/Razor/MasterPasswordHint.text.cshtml similarity index 100% rename from src/Core/MailTemplates/MasterPasswordHint.text.cshtml rename to src/Core/MailTemplates/Razor/MasterPasswordHint.text.cshtml diff --git a/src/Core/MailTemplates/NoMasterPasswordHint.cshtml b/src/Core/MailTemplates/Razor/NoMasterPasswordHint.cshtml similarity index 100% rename from src/Core/MailTemplates/NoMasterPasswordHint.cshtml rename to src/Core/MailTemplates/Razor/NoMasterPasswordHint.cshtml diff --git a/src/Core/MailTemplates/NoMasterPasswordHint.text.cshtml b/src/Core/MailTemplates/Razor/NoMasterPasswordHint.text.cshtml similarity index 100% rename from src/Core/MailTemplates/NoMasterPasswordHint.text.cshtml rename to src/Core/MailTemplates/Razor/NoMasterPasswordHint.text.cshtml diff --git a/src/Core/MailTemplates/OrganizationUserAccepted.cshtml b/src/Core/MailTemplates/Razor/OrganizationUserAccepted.cshtml similarity index 100% rename from src/Core/MailTemplates/OrganizationUserAccepted.cshtml rename to src/Core/MailTemplates/Razor/OrganizationUserAccepted.cshtml diff --git a/src/Core/MailTemplates/OrganizationUserAccepted.text.cshtml b/src/Core/MailTemplates/Razor/OrganizationUserAccepted.text.cshtml similarity index 100% rename from src/Core/MailTemplates/OrganizationUserAccepted.text.cshtml rename to src/Core/MailTemplates/Razor/OrganizationUserAccepted.text.cshtml diff --git a/src/Core/MailTemplates/OrganizationUserConfirmed.cshtml b/src/Core/MailTemplates/Razor/OrganizationUserConfirmed.cshtml similarity index 100% rename from src/Core/MailTemplates/OrganizationUserConfirmed.cshtml rename to src/Core/MailTemplates/Razor/OrganizationUserConfirmed.cshtml diff --git a/src/Core/MailTemplates/OrganizationUserConfirmed.text.cshtml b/src/Core/MailTemplates/Razor/OrganizationUserConfirmed.text.cshtml similarity index 100% rename from src/Core/MailTemplates/OrganizationUserConfirmed.text.cshtml rename to src/Core/MailTemplates/Razor/OrganizationUserConfirmed.text.cshtml diff --git a/src/Core/MailTemplates/OrganizationUserInvited.cshtml b/src/Core/MailTemplates/Razor/OrganizationUserInvited.cshtml similarity index 100% rename from src/Core/MailTemplates/OrganizationUserInvited.cshtml rename to src/Core/MailTemplates/Razor/OrganizationUserInvited.cshtml diff --git a/src/Core/MailTemplates/OrganizationUserInvited.text.cshtml b/src/Core/MailTemplates/Razor/OrganizationUserInvited.text.cshtml similarity index 100% rename from src/Core/MailTemplates/OrganizationUserInvited.text.cshtml rename to src/Core/MailTemplates/Razor/OrganizationUserInvited.text.cshtml diff --git a/src/Core/MailTemplates/TwoFactorEmail.cshtml b/src/Core/MailTemplates/Razor/TwoFactorEmail.cshtml similarity index 100% rename from src/Core/MailTemplates/TwoFactorEmail.cshtml rename to src/Core/MailTemplates/Razor/TwoFactorEmail.cshtml diff --git a/src/Core/MailTemplates/TwoFactorEmail.text.cshtml b/src/Core/MailTemplates/Razor/TwoFactorEmail.text.cshtml similarity index 100% rename from src/Core/MailTemplates/TwoFactorEmail.text.cshtml rename to src/Core/MailTemplates/Razor/TwoFactorEmail.text.cshtml diff --git a/src/Core/MailTemplates/VerifyDelete.cshtml b/src/Core/MailTemplates/Razor/VerifyDelete.cshtml similarity index 100% rename from src/Core/MailTemplates/VerifyDelete.cshtml rename to src/Core/MailTemplates/Razor/VerifyDelete.cshtml diff --git a/src/Core/MailTemplates/VerifyDelete.text.cshtml b/src/Core/MailTemplates/Razor/VerifyDelete.text.cshtml similarity index 100% rename from src/Core/MailTemplates/VerifyDelete.text.cshtml rename to src/Core/MailTemplates/Razor/VerifyDelete.text.cshtml diff --git a/src/Core/MailTemplates/VerifyEmail.cshtml b/src/Core/MailTemplates/Razor/VerifyEmail.cshtml similarity index 66% rename from src/Core/MailTemplates/VerifyEmail.cshtml rename to src/Core/MailTemplates/Razor/VerifyEmail.cshtml index 49edc5f12..691ea8c01 100644 --- a/src/Core/MailTemplates/VerifyEmail.cshtml +++ b/src/Core/MailTemplates/Razor/VerifyEmail.cshtml @@ -3,6 +3,7 @@ Layout = "_BasicMailLayout"; }

- Verify this email address for your bitwarden account by clicking the following link: + Verify this email address for your bitwarden account by clicking the following link. If you did not request this email to + verify a bitwarden account, you can safely ignore it.

@Model.Url

diff --git a/src/Core/MailTemplates/VerifyEmail.text.cshtml b/src/Core/MailTemplates/Razor/VerifyEmail.text.cshtml similarity index 53% rename from src/Core/MailTemplates/VerifyEmail.text.cshtml rename to src/Core/MailTemplates/Razor/VerifyEmail.text.cshtml index d599edc25..1a949ae20 100644 --- a/src/Core/MailTemplates/VerifyEmail.text.cshtml +++ b/src/Core/MailTemplates/Razor/VerifyEmail.text.cshtml @@ -3,6 +3,8 @@ Layout = "_BasicMailLayout.text"; } Verify this email address for your bitwarden -account by clicking the following link: +account by clicking the following link. If you +did not request this email to verify a bitwarden +account, you can safely ignore it. @Raw(Model.Url) diff --git a/src/Core/MailTemplates/Welcome.cshtml b/src/Core/MailTemplates/Razor/Welcome.cshtml similarity index 100% rename from src/Core/MailTemplates/Welcome.cshtml rename to src/Core/MailTemplates/Razor/Welcome.cshtml diff --git a/src/Core/MailTemplates/Welcome.text.cshtml b/src/Core/MailTemplates/Razor/Welcome.text.cshtml similarity index 100% rename from src/Core/MailTemplates/Welcome.text.cshtml rename to src/Core/MailTemplates/Razor/Welcome.text.cshtml diff --git a/src/Core/MailTemplates/_BasicMailLayout.cshtml b/src/Core/MailTemplates/Razor/_BasicMailLayout.cshtml similarity index 100% rename from src/Core/MailTemplates/_BasicMailLayout.cshtml rename to src/Core/MailTemplates/Razor/_BasicMailLayout.cshtml diff --git a/src/Core/MailTemplates/_BasicMailLayout.text.cshtml b/src/Core/MailTemplates/Razor/_BasicMailLayout.text.cshtml similarity index 100% rename from src/Core/MailTemplates/_BasicMailLayout.text.cshtml rename to src/Core/MailTemplates/Razor/_BasicMailLayout.text.cshtml diff --git a/src/Core/MailTemplates/_MailLayout.cshtml b/src/Core/MailTemplates/Razor/_MailLayout.cshtml similarity index 100% rename from src/Core/MailTemplates/_MailLayout.cshtml rename to src/Core/MailTemplates/Razor/_MailLayout.cshtml diff --git a/src/Core/MailTemplates/_MailLayout.text.cshtml b/src/Core/MailTemplates/Razor/_MailLayout.text.cshtml similarity index 100% rename from src/Core/MailTemplates/_MailLayout.text.cshtml rename to src/Core/MailTemplates/Razor/_MailLayout.text.cshtml diff --git a/src/Core/Services/Implementations/MarkdownMailService.cs b/src/Core/Services/Implementations/MarkdownMailService.cs new file mode 100644 index 000000000..12af1755f --- /dev/null +++ b/src/Core/Services/Implementations/MarkdownMailService.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Bit.Core.Models.Table; +using Bit.Core.Models.Mail; +using System.IO; +using System.Net; +using System.Reflection; + +namespace Bit.Core.Services +{ + public class MarkdownMailService : IMailService + { + private const string Namespace = "Bit.Core.MailTemplates.Markdown"; + + private readonly GlobalSettings _globalSettings; + private readonly IMailDeliveryService _mailDeliveryService; + + public MarkdownMailService( + GlobalSettings globalSettings, + IMailDeliveryService mailDeliveryService) + { + _globalSettings = globalSettings; + _mailDeliveryService = mailDeliveryService; + } + + public async Task SendVerifyEmailEmailAsync(string email, Guid userId, string token) + { + var model = new Dictionary + { + ["url"] = string.Format("{0}/verify-email?userId={1}&token={2}", + _globalSettings.BaseServiceUri.Vault, userId, WebUtility.UrlEncode(token)) + }; + + var message = await CreateMessageAsync("Verify Your Email", email, "VerifyEmail", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendVerifyDeleteEmailAsync(string email, Guid userId, string token) + { + var model = new Dictionary + { + ["url"] = string.Format("{0}/verify-recover-delete?userId={1}&token={2}&email={3}", + _globalSettings.BaseServiceUri.Vault, + userId, + WebUtility.UrlEncode(token), + WebUtility.UrlEncode(email)), + ["email"] = WebUtility.HtmlEncode(email) + }; + + var message = await CreateMessageAsync("Delete Your Account", email, "VerifyDelete", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendChangeEmailAlreadyExistsEmailAsync(string fromEmail, string toEmail) + { + var model = new Dictionary + { + ["fromEmail"] = WebUtility.HtmlEncode(fromEmail), + ["toEmail"] = WebUtility.HtmlEncode(toEmail), + }; + + var message = await CreateMessageAsync("Your Email Change", toEmail, "ChangeEmailAlreadyExists", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendChangeEmailEmailAsync(string newEmailAddress, string token) + { + var model = new Dictionary + { + ["token"] = token + }; + + var message = await CreateMessageAsync("Your Email Change", newEmailAddress, "ChangeEmail", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendTwoFactorEmailAsync(string email, string token) + { + var model = new Dictionary + { + ["token"] = token + }; + + var message = await CreateMessageAsync("Your Two-step Login Verification Code", email, "TwoFactorEmail", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendMasterPasswordHintEmailAsync(string email, string hint) + { + var model = new Dictionary + { + ["hint"] = WebUtility.HtmlEncode(hint), + ["vaultUrl"] = _globalSettings.BaseServiceUri.Vault + }; + + var message = await CreateMessageAsync("Your Master Password Hint", email, "MasterPasswordHint", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendNoMasterPasswordHintEmailAsync(string email) + { + var message = await CreateMessageAsync("Your Master Password Hint", email, "NoMasterPasswordHint", null); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendOrganizationAcceptedEmailAsync(string organizationName, string userEmail, + IEnumerable adminEmails) + { + var model = new Dictionary + { + ["userEmail"] = WebUtility.HtmlEncode(userEmail), + ["organizationName"] = WebUtility.HtmlEncode(organizationName) + }; + + var message = await CreateMessageAsync($"User {userEmail} Has Accepted Invite", adminEmails, + "OrganizationUserAccepted", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendOrganizationConfirmedEmailAsync(string organizationName, string email) + { + var model = new Dictionary + { + ["organizationName"] = WebUtility.HtmlEncode(organizationName) + }; + + var message = await CreateMessageAsync($"You Have Been Confirmed To {organizationName}", email, + "OrganizationUserConfirmed", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendOrganizationInviteEmailAsync(string organizationName, OrganizationUser orgUser, string token) + { + var model = new Dictionary + { + ["organizationName"] = WebUtility.HtmlEncode(organizationName), + ["url"] = string.Format("{0}/accept-organization?organizationId={1}&organizationUserId={2}" + + "&email={3}&organizationName={4}&token={5}", + _globalSettings.BaseServiceUri.Vault, + orgUser.OrganizationId, + orgUser.Id, + WebUtility.UrlEncode(orgUser.Email), + WebUtility.UrlEncode(organizationName), + WebUtility.UrlEncode(token)) + }; + + var message = await CreateMessageAsync($"Join {organizationName}", orgUser.Email, "OrganizationUserInvited", model); + message.MetaData.Add("SendGridBypassListManagement", true); + await _mailDeliveryService.SendEmailAsync(message); + } + + public async Task SendWelcomeEmailAsync(User user) + { + var model = new Dictionary + { + ["vaultUrl"] = _globalSettings.BaseServiceUri.Vault + }; + + var message = await CreateMessageAsync("Welcome", user.Email, "Welcome", model); + await _mailDeliveryService.SendEmailAsync(message); + } + + private async Task CreateMessageAsync(string subject, string toEmail, string fileName, + Dictionary model) + { + return await CreateMessageAsync(subject, new List { toEmail }, fileName, model); + } + + private async Task CreateMessageAsync(string subject, IEnumerable toEmails, string fileName, + Dictionary model) + { + var message = new MailMessage + { + ToEmails = toEmails, + Subject = subject, + MetaData = new Dictionary() + }; + + var assembly = typeof(MarkdownMailService).GetTypeInfo().Assembly; + using(var s = assembly.GetManifestResourceStream($"{Namespace}.{fileName}.md")) + using(var sr = new StreamReader(s)) + { + var markdown = await sr.ReadToEndAsync(); + + if(model != null) + { + foreach(var prop in model) + { + markdown = markdown.Replace($"{{{{{prop.Key}}}}}", prop.Value); + } + } + + message.HtmlContent = CommonMark.CommonMarkConverter.Convert(markdown); + message.TextContent = markdown; + } + + return message; + } + } +} diff --git a/src/Core/Services/Implementations/RazorViewMailService.cs b/src/Core/Services/Implementations/RazorMailService.cs similarity index 98% rename from src/Core/Services/Implementations/RazorViewMailService.cs rename to src/Core/Services/Implementations/RazorMailService.cs index 5b6dc0db7..76136bd0c 100644 --- a/src/Core/Services/Implementations/RazorViewMailService.cs +++ b/src/Core/Services/Implementations/RazorMailService.cs @@ -10,20 +10,20 @@ using System.Net; namespace Bit.Core.Services { - public class RazorViewMailService : IMailService + public class RazorMailService : IMailService { private readonly GlobalSettings _globalSettings; private readonly IRazorLightEngine _engine; private readonly IMailDeliveryService _mailDeliveryService; - public RazorViewMailService( + public RazorMailService( GlobalSettings globalSettings, IMailDeliveryService mailDeliveryService) { _globalSettings = globalSettings; _mailDeliveryService = mailDeliveryService; - var manager = new CustomEmbeddedResourceTemplateManager("Bit.Core.MailTemplates"); + var manager = new CustomEmbeddedResourceTemplateManager("Bit.Core.MailTemplates.Razor"); var core = new EngineCore(manager, EngineConfiguration.Default); var pageFactory = new DefaultPageFactory(core.KeyCompile); var lookup = new DefaultPageLookup(pageFactory); @@ -151,8 +151,8 @@ namespace Bit.Core.Services WebVaultUrl = _globalSettings.BaseServiceUri.Vault, SiteName = _globalSettings.SiteName }; - message.HtmlContent = _engine.Parse("OrganizationUserInvited", model); - message.TextContent = _engine.Parse("OrganizationUserInvited.text", model); + message.HtmlContent = _engine.Parse("OrganizationUserAccepted", model); + message.TextContent = _engine.Parse("OrganizationUserAccepted.text", model); await _mailDeliveryService.SendEmailAsync(message); } diff --git a/src/Core/Services/Implementations/SendGridTemplateMailService.cs b/src/Core/Services/Implementations/SendGridTemplateMailService.cs index 5a83671f7..55e864cbf 100644 --- a/src/Core/Services/Implementations/SendGridTemplateMailService.cs +++ b/src/Core/Services/Implementations/SendGridTemplateMailService.cs @@ -88,7 +88,7 @@ namespace Bit.Core.Services AddSubstitution(message, "{{fromEmail}}", fromEmail); AddSubstitution(message, "{{toEmail}}", toEmail); - AddCategories(message, new List { AdministrativeCategoryName, "Change Email Alrady Exists" }); + AddCategories(message, new List { AdministrativeCategoryName, "Change Email Already Exists" }); await _mailDeliveryService.SendEmailAsync(message); } diff --git a/src/Core/Utilities/ServiceCollectionExtensions.cs b/src/Core/Utilities/ServiceCollectionExtensions.cs index c1b497de5..e0b201058 100644 --- a/src/Core/Utilities/ServiceCollectionExtensions.cs +++ b/src/Core/Utilities/ServiceCollectionExtensions.cs @@ -54,7 +54,15 @@ namespace Bit.Core.Utilities public static void AddDefaultServices(this IServiceCollection services, GlobalSettings globalSettings) { - services.AddSingleton(); + if(globalSettings.SelfHosted) + { + services.AddSingleton(); + } + else + { + services.AddSingleton(); + } + services.AddSingleton(); if(CoreHelpers.SettingHasValue(globalSettings.Mail.SendGridApiKey))