diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 82afb5eca..efa2f89b0 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -65,7 +65,7 @@
-
+
diff --git a/src/Core/Services/Implementations/RazorMailService.cs b/src/Core/Services/Implementations/RazorMailService.cs
index d4edad65f..116dd820c 100644
--- a/src/Core/Services/Implementations/RazorMailService.cs
+++ b/src/Core/Services/Implementations/RazorMailService.cs
@@ -4,10 +4,12 @@ using System.Threading.Tasks;
using Bit.Core.Models.Table;
using RazorLight;
using Bit.Core.Models.Mail;
-using RazorLight.Templating;
using System.IO;
using System.Net;
using Bit.Core.Utilities;
+using RazorLight.Razor;
+using System.Linq;
+using System.Reflection;
namespace Bit.Core.Services
{
@@ -24,11 +26,9 @@ namespace Bit.Core.Services
_globalSettings = globalSettings;
_mailDeliveryService = mailDeliveryService;
- 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);
- _engine = new RazorLightEngine(core, lookup);
+
+ var factory = new EngineFactory();
+ _engine = factory.Create(new CustomEmbeddedRazorProject());
}
public async Task SendVerifyEmailEmailAsync(string email, Guid userId, string token)
@@ -41,8 +41,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("VerifyEmail", model);
- message.TextContent = _engine.Parse("VerifyEmail.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("VerifyEmail", model);
+ message.TextContent = await _engine.CompileRenderAsync("VerifyEmail.text", model);
message.MetaData.Add("SendGridBypassListManagement", true);
await _mailDeliveryService.SendEmailAsync(message);
@@ -60,8 +60,8 @@ namespace Bit.Core.Services
Email = email,
EmailEncoded = WebUtility.UrlEncode(email)
};
- message.HtmlContent = _engine.Parse("VerifyDelete", model);
- message.TextContent = _engine.Parse("VerifyDelete.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("VerifyDelete", model);
+ message.TextContent = await _engine.CompileRenderAsync("VerifyDelete.text", model);
message.MetaData.Add("SendGridBypassListManagement", true);
await _mailDeliveryService.SendEmailAsync(message);
@@ -77,8 +77,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("ChangeEmailAlreadyExists", model);
- message.TextContent = _engine.Parse("ChangeEmailAlreadyExists.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("ChangeEmailAlreadyExists", model);
+ message.TextContent = await _engine.CompileRenderAsync("ChangeEmailAlreadyExists.text", model);
await _mailDeliveryService.SendEmailAsync(message);
}
@@ -91,8 +91,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("ChangeEmail", model);
- message.TextContent = _engine.Parse("ChangeEmail.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("ChangeEmail", model);
+ message.TextContent = await _engine.CompileRenderAsync("ChangeEmail.text", model);
message.MetaData.Add("SendGridBypassListManagement", true);
await _mailDeliveryService.SendEmailAsync(message);
@@ -107,8 +107,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("TwoFactorEmail", model);
- message.TextContent = _engine.Parse("TwoFactorEmail.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("TwoFactorEmail", model);
+ message.TextContent = await _engine.CompileRenderAsync("TwoFactorEmail.text", model);
message.MetaData.Add("SendGridBypassListManagement", true);
await _mailDeliveryService.SendEmailAsync(message);
@@ -123,8 +123,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("MasterPasswordHint", model);
- message.TextContent = _engine.Parse("MasterPasswordHint.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("MasterPasswordHint", model);
+ message.TextContent = await _engine.CompileRenderAsync("MasterPasswordHint.text", model);
await _mailDeliveryService.SendEmailAsync(message);
}
@@ -136,8 +136,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("NoMasterPasswordHint", model);
- message.TextContent = _engine.Parse("NoMasterPasswordHint.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("NoMasterPasswordHint", model);
+ message.TextContent = await _engine.CompileRenderAsync("NoMasterPasswordHint.text", model);
await _mailDeliveryService.SendEmailAsync(message);
}
@@ -152,8 +152,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("OrganizationUserAccepted", model);
- message.TextContent = _engine.Parse("OrganizationUserAccepted.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("OrganizationUserAccepted", model);
+ message.TextContent = await _engine.CompileRenderAsync("OrganizationUserAccepted.text", model);
await _mailDeliveryService.SendEmailAsync(message);
}
@@ -166,8 +166,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("OrganizationUserConfirmed", model);
- message.TextContent = _engine.Parse("OrganizationUserConfirmed.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("OrganizationUserConfirmed", model);
+ message.TextContent = await _engine.CompileRenderAsync("OrganizationUserConfirmed.text", model);
await _mailDeliveryService.SendEmailAsync(message);
}
@@ -185,8 +185,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("OrganizationUserInvited", model);
- message.TextContent = _engine.Parse("OrganizationUserInvited.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("OrganizationUserInvited", model);
+ message.TextContent = await _engine.CompileRenderAsync("OrganizationUserInvited.text", model);
await _mailDeliveryService.SendEmailAsync(message);
}
@@ -198,8 +198,8 @@ namespace Bit.Core.Services
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName
};
- message.HtmlContent = _engine.Parse("Welcome", model);
- message.TextContent = _engine.Parse("Welcome.text", model);
+ message.HtmlContent = await _engine.CompileRenderAsync("Welcome", model);
+ message.TextContent = await _engine.CompileRenderAsync("Welcome.text", model);
await _mailDeliveryService.SendEmailAsync(message);
}
@@ -218,29 +218,55 @@ namespace Bit.Core.Services
};
}
- public class CustomEmbeddedResourceTemplateManager : ITemplateManager
+ public class CustomEmbeddedRazorProject : RazorLightProject
{
- public CustomEmbeddedResourceTemplateManager(string rootNamespace)
+ public override Task GetItemAsync(string templateKey)
{
- Namespace = rootNamespace ?? throw new ArgumentNullException(nameof(rootNamespace));
+ if(string.IsNullOrEmpty(templateKey))
+ {
+ throw new ArgumentNullException(nameof(templateKey));
+ }
+
+ var item = new CustomEmbeddedRazorProjectItem(templateKey);
+ return Task.FromResult(item as RazorLightProjectItem);
}
- public string Namespace { get; }
-
- public ITemplateSource Resolve(string key)
+ public override Task> GetImportsAsync(string templateKey)
{
- var assembly = GetType().Assembly;
- using(var stream = assembly.GetManifestResourceStream(Namespace + "." + key + ".cshtml"))
+ return Task.FromResult(Enumerable.Empty());
+ }
+ }
+
+ public class CustomEmbeddedRazorProjectItem : RazorLightProjectItem
+ {
+ private readonly string _fullTemplateKey;
+ private readonly Assembly _assembly;
+
+ public CustomEmbeddedRazorProjectItem(string key)
+ {
+ if(string.IsNullOrEmpty(key))
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ Key = key;
+ _assembly = GetType().Assembly;
+ _fullTemplateKey = $"Bit.Core.MailTemplates.Razor.{key}.cshtml";
+ }
+
+ public override string Key { get; set; }
+ public override bool Exists => true;
+
+ public override Stream Read()
+ {
+ using(var stream = _assembly.GetManifestResourceStream(_fullTemplateKey))
{
if(stream == null)
{
- throw new RazorLightException(string.Format("Couldn't load resource '{0}.{1}.cshtml'.", Namespace, key));
+ throw new RazorLightException($"Couldn't load resource '{_fullTemplateKey}'.");
}
- using(var reader = new StreamReader(stream))
- {
- return new LoadedTemplateSource(reader.ReadToEnd());
- }
+ return stream;
}
}
}