From 4cbe05da3c439f01cd27a4752cd60e375d933b3e Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Tue, 1 Mar 2022 19:09:51 -0500 Subject: [PATCH] SendGrid Mail Delivery Provider (#1892) * add sendgrid mail delivery service * < * remove duplicate code * fix test by using ISendGridClient interface --- .../src/CommCore/packages.lock.json | 15 +++ bitwarden_license/src/Sso/packages.lock.json | 25 +++- .../test/CmmCore.Test/packages.lock.json | 43 ++++--- src/Admin/packages.lock.json | 29 +++-- src/Api/packages.lock.json | 27 +++- src/Billing/packages.lock.json | 25 +++- src/Core/Core.csproj | 1 + .../MultiServiceMailDeliveryService.cs | 19 ++- .../PostalMailDeliveryService.cs | 116 ----------------- .../SendGridMailDeliveryService.cs | 118 ++++++++++++++++++ src/Core/Settings/GlobalSettings.cs | 5 +- src/Core/packages.lock.json | 15 +++ src/Events/packages.lock.json | 25 +++- src/EventsProcessor/packages.lock.json | 25 +++- src/Icons/packages.lock.json | 25 +++- src/Identity/packages.lock.json | 25 +++- src/Infrastructure.Dapper/packages.lock.json | 15 +++ .../packages.lock.json | 15 +++ src/Notifications/packages.lock.json | 25 +++- .../Utilities/ServiceCollectionExtensions.cs | 3 +- src/SharedWeb/packages.lock.json | 19 ++- test/Api.Test/packages.lock.json | 37 ++++-- test/Billing.Test/packages.lock.json | 41 ++++-- test/Common/packages.lock.json | 33 +++-- .../SendGridMailDeliveryServiceTests.cs | 89 +++++++++++++ test/Core.Test/packages.lock.json | 37 ++++-- test/Icons.Test/packages.lock.json | 29 +++-- test/Identity.Test/packages.lock.json | 41 ++++-- util/Migrator/packages.lock.json | 15 +++ util/MySqlMigrations/packages.lock.json | 33 +++-- util/PostgresMigrations/packages.lock.json | 33 +++-- util/Setup/packages.lock.json | 17 ++- 32 files changed, 741 insertions(+), 279 deletions(-) delete mode 100644 src/Core/Services/Implementations/PostalMailDeliveryService.cs create mode 100644 src/Core/Services/Implementations/SendGridMailDeliveryService.cs create mode 100644 test/Core.Test/Services/SendGridMailDeliveryServiceTests.cs diff --git a/bitwarden_license/src/CommCore/packages.lock.json b/bitwarden_license/src/CommCore/packages.lock.json index c8fa7753f..978598359 100644 --- a/bitwarden_license/src/CommCore/packages.lock.json +++ b/bitwarden_license/src/CommCore/packages.lock.json @@ -1447,6 +1447,15 @@ "resolved": "4.3.2", "contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1662,6 +1671,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3188,6 +3202,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", diff --git a/bitwarden_license/src/Sso/packages.lock.json b/bitwarden_license/src/Sso/packages.lock.json index 38339b020..6c0672801 100644 --- a/bitwarden_license/src/Sso/packages.lock.json +++ b/bitwarden_license/src/Sso/packages.lock.json @@ -1643,6 +1643,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1858,6 +1867,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3369,6 +3383,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3383,7 +3398,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3392,7 +3407,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3402,9 +3417,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/bitwarden_license/test/CmmCore.Test/packages.lock.json b/bitwarden_license/test/CmmCore.Test/packages.lock.json index 7fcbfb321..324fa5145 100644 --- a/bitwarden_license/test/CmmCore.Test/packages.lock.json +++ b/bitwarden_license/test/CmmCore.Test/packages.lock.json @@ -1744,6 +1744,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1959,6 +1968,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3518,27 +3532,27 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "common": { "type": "Project", "dependencies": { - "Api": "1.46.0", + "Api": "1.46.2", "AutoFixture.AutoNSubstitute": "4.14.0", "AutoFixture.Xunit2": "4.14.0", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.NET.Test.Sdk": "16.6.1", "NSubstitute": "4.2.2", "xunit": "2.4.1" @@ -3571,6 +3585,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3585,11 +3600,11 @@ "core.test": { "type": "Project", "dependencies": { - "Api": "1.46.0", + "Api": "1.46.2", "AutoFixture.AutoNSubstitute": "4.14.0", "AutoFixture.Xunit2": "4.14.0", - "Common": "1.46.0", - "Core": "1.46.0", + "Common": "1.46.2", + "Core": "1.46.2", "Microsoft.NET.Test.Sdk": "16.6.1", "Moq": "4.16.1", "NSubstitute": "4.2.2", @@ -3599,7 +3614,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3608,7 +3623,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3618,9 +3633,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/Admin/packages.lock.json b/src/Admin/packages.lock.json index e83ccf951..397f3f32f 100644 --- a/src/Admin/packages.lock.json +++ b/src/Admin/packages.lock.json @@ -1692,6 +1692,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1907,6 +1916,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3408,7 +3422,7 @@ "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "core": { @@ -3438,6 +3452,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3452,7 +3467,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3461,7 +3476,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3471,7 +3486,7 @@ "migrator": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.Extensions.Logging": "5.0.0", "dbup-sqlserver": "4.4.0" } @@ -3479,9 +3494,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/Api/packages.lock.json b/src/Api/packages.lock.json index 9f994d7da..0e1a6afab 100644 --- a/src/Api/packages.lock.json +++ b/src/Api/packages.lock.json @@ -1629,6 +1629,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1844,6 +1853,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3347,7 +3361,7 @@ "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "core": { @@ -3377,6 +3391,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3391,7 +3406,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3400,7 +3415,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3410,9 +3425,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/Billing/packages.lock.json b/src/Billing/packages.lock.json index 8d152c5da..a047e9aab 100644 --- a/src/Billing/packages.lock.json +++ b/src/Billing/packages.lock.json @@ -1661,6 +1661,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1876,6 +1885,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3401,6 +3415,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3415,7 +3430,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3424,7 +3439,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3434,9 +3449,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 5bbd78847..bafa7703e 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -37,6 +37,7 @@ + diff --git a/src/Core/Services/Implementations/MultiServiceMailDeliveryService.cs b/src/Core/Services/Implementations/MultiServiceMailDeliveryService.cs index ee419cb46..f714b42f8 100644 --- a/src/Core/Services/Implementations/MultiServiceMailDeliveryService.cs +++ b/src/Core/Services/Implementations/MultiServiceMailDeliveryService.cs @@ -1,5 +1,4 @@ using System; -using System.Net.Http; using System.Threading.Tasks; using Bit.Core.Models.Mail; using Bit.Core.Settings; @@ -11,32 +10,30 @@ namespace Bit.Core.Services public class MultiServiceMailDeliveryService : IMailDeliveryService { private readonly IMailDeliveryService _sesService; - private readonly IMailDeliveryService _postalService; - private readonly int _postalPercentage; + private readonly IMailDeliveryService _sendGridService; + private readonly int _sendGridPercentage; private static Random _random = new Random(); public MultiServiceMailDeliveryService( GlobalSettings globalSettings, IWebHostEnvironment hostingEnvironment, - IHttpClientFactory httpClientFactory, ILogger sesLogger, - ILogger postalLogger) + ILogger sendGridLogger) { _sesService = new AmazonSesMailDeliveryService(globalSettings, hostingEnvironment, sesLogger); - _postalService = new PostalMailDeliveryService(globalSettings, postalLogger, hostingEnvironment, - httpClientFactory); + _sendGridService = new SendGridMailDeliveryService(globalSettings, hostingEnvironment, sendGridLogger); - // 2% by default - _postalPercentage = (globalSettings.Mail?.PostalPercentage).GetValueOrDefault(2); + // disabled by default (-1) + _sendGridPercentage = (globalSettings.Mail?.SendGridPercentage).GetValueOrDefault(-1); } public async Task SendEmailAsync(MailMessage message) { var roll = _random.Next(0, 99); - if (roll < _postalPercentage) + if (roll < _sendGridPercentage) { - await _postalService.SendEmailAsync(message); + await _sendGridService.SendEmailAsync(message); } else { diff --git a/src/Core/Services/Implementations/PostalMailDeliveryService.cs b/src/Core/Services/Implementations/PostalMailDeliveryService.cs deleted file mode 100644 index 7f4b80998..000000000 --- a/src/Core/Services/Implementations/PostalMailDeliveryService.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Net.Http.Json; -using System.Threading.Tasks; -using Bit.Core.Settings; -using Bit.Core.Utilities; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Logging; - -namespace Bit.Core.Services -{ - public class PostalMailDeliveryService : IMailDeliveryService - { - private readonly GlobalSettings _globalSettings; - private readonly ILogger _logger; - private readonly IHttpClientFactory _clientFactory; - private readonly string _baseTag; - private readonly string _from; - private readonly string _reply; - - public PostalMailDeliveryService( - GlobalSettings globalSettings, - ILogger logger, - IWebHostEnvironment hostingEnvironment, - IHttpClientFactory clientFactory) - { - var postalDomain = CoreHelpers.PunyEncode(globalSettings.Mail.PostalDomain); - var replyToEmail = CoreHelpers.PunyEncode(globalSettings.Mail.ReplyToEmail); - - _globalSettings = globalSettings; - _logger = logger; - _clientFactory = clientFactory; - _baseTag = $"Env_{hostingEnvironment.EnvironmentName}-" + - $"Server_{globalSettings.ProjectName?.Replace(' ', '_')}"; - _from = $"\"{globalSettings.SiteName}\" "; - _reply = $"\"{globalSettings.SiteName}\" <{replyToEmail}>"; - } - - public async Task SendEmailAsync(Models.Mail.MailMessage message) - { - var httpClient = _clientFactory.CreateClient("PostalMailDeliveryService"); - httpClient.DefaultRequestHeaders.Add("X-Server-API-Key", _globalSettings.Mail.PostalApiKey); - - var request = new PostalRequest - { - subject = message.Subject, - from = _from, - reply_to = _reply, - html_body = message.HtmlContent, - to = new List(), - tag = _baseTag - }; - foreach (var address in message.ToEmails) - { - request.to.Add(CoreHelpers.PunyEncode(address)); - } - - if (message.BccEmails != null) - { - request.bcc = new List(); - foreach (var address in message.BccEmails) - { - request.bcc.Add(CoreHelpers.PunyEncode(address)); - } - } - - if (!string.IsNullOrWhiteSpace(message.TextContent)) - { - request.plain_body = message.TextContent; - } - - if (!string.IsNullOrWhiteSpace(message.Category)) - { - request.tag = string.Concat(request.tag, "-Cat_", message.Category); - } - - var responseMessage = await httpClient.PostAsJsonAsync( - $"https://{_globalSettings.Mail.PostalDomain}/api/v1/send/message", - request); - - if (responseMessage.IsSuccessStatusCode) - { - var response = await responseMessage.Content.ReadFromJsonAsync(); - if (response.status != "success") - { - _logger.LogError("Postal send status was not successful: {0}, {1}", - response.status, response.message); - } - } - else - { - _logger.LogError("Postal send failed: {0}", responseMessage.StatusCode); - } - } - - public class PostalRequest - { - public List to { get; set; } - public List cc { get; set; } - public List bcc { get; set; } - public string tag { get; set; } - public string from { get; set; } - public string reply_to { get; set; } - public string plain_body { get; set; } - public string html_body { get; set; } - public string subject { get; set; } - } - - public class PostalResponse - { - public string status { get; set; } - public string message { get; set; } - } - } -} diff --git a/src/Core/Services/Implementations/SendGridMailDeliveryService.cs b/src/Core/Services/Implementations/SendGridMailDeliveryService.cs new file mode 100644 index 000000000..3214f7dcd --- /dev/null +++ b/src/Core/Services/Implementations/SendGridMailDeliveryService.cs @@ -0,0 +1,118 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Bit.Core.Models.Mail; +using Bit.Core.Settings; +using Bit.Core.Utilities; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; +using SendGrid; +using SendGrid.Helpers.Mail; + +namespace Bit.Core.Services +{ + public class SendGridMailDeliveryService : IMailDeliveryService, IDisposable + { + private readonly GlobalSettings _globalSettings; + private readonly IWebHostEnvironment _hostingEnvironment; + private readonly ILogger _logger; + private readonly ISendGridClient _client; + private readonly string _senderTag; + private readonly string _replyToEmail; + + public SendGridMailDeliveryService( + GlobalSettings globalSettings, + IWebHostEnvironment hostingEnvironment, + ILogger logger) + : this(new SendGridClient(globalSettings.Mail.SendGridApiKey), + globalSettings, hostingEnvironment, logger) + { + } + + public void Dispose() + { + // TODO: nothing to dispose + } + + public SendGridMailDeliveryService( + ISendGridClient client, + GlobalSettings globalSettings, + IWebHostEnvironment hostingEnvironment, + ILogger logger) + { + if (string.IsNullOrWhiteSpace(globalSettings.Mail?.SendGridApiKey)) + { + throw new ArgumentNullException(nameof(globalSettings.Mail.SendGridApiKey)); + } + + _globalSettings = globalSettings; + _hostingEnvironment = hostingEnvironment; + _logger = logger; + _client = client; + _senderTag = $"Server_{globalSettings.ProjectName?.Replace(' ', '_')}"; + _replyToEmail = CoreHelpers.PunyEncode(globalSettings.Mail.ReplyToEmail); + } + + public async Task SendEmailAsync(MailMessage message) + { + var msg = new SendGridMessage(); + msg.SetFrom(new EmailAddress(_replyToEmail, _globalSettings.SiteName)); + msg.AddTos(message.ToEmails.Select(e => new EmailAddress(CoreHelpers.PunyEncode(e))).ToList()); + if (message.BccEmails?.Any() ?? false) + { + msg.AddBccs(message.BccEmails.Select(e => new EmailAddress(CoreHelpers.PunyEncode(e))).ToList()); + } + + msg.SetSubject(message.Subject); + msg.AddContent(MimeType.Text, message.TextContent); + msg.AddContent(MimeType.Html, message.HtmlContent); + + msg.AddCategory($"type:{message.Category}"); + msg.AddCategory($"env:{_hostingEnvironment.EnvironmentName}"); + msg.AddCategory($"sender:{_senderTag}"); + + msg.SetClickTracking(false, false); + msg.SetOpenTracking(false); + + if (message.MetaData != null && + message.MetaData.ContainsKey("SendGridBypassListManagement") && + Convert.ToBoolean(message.MetaData["SendGridBypassListManagement"])) + { + msg.SetBypassListManagement(true); + } + + try + { + var success = await SendAsync(msg, false); + if (!success) + { + _logger.LogWarning("Failed to send email. Retrying..."); + await SendAsync(msg, true); + } + } + catch (Exception e) + { + _logger.LogWarning(e, "Failed to send email (with exception). Retrying..."); + await SendAsync(msg, true); + throw; + } + } + + private async Task SendAsync(SendGridMessage message, bool retry) + { + if (retry) + { + // wait and try again + await Task.Delay(2000); + } + + var response = await _client.SendEmailAsync(message); + if (!response.IsSuccessStatusCode) + { + var responseBody = await response.Body.ReadAsStringAsync(); + _logger.LogError("SendGrid email sending failed with {0}: {1}", response.StatusCode, responseBody); + } + return response.IsSuccessStatusCode; + } + } +} diff --git a/src/Core/Settings/GlobalSettings.cs b/src/Core/Settings/GlobalSettings.cs index b41e5e790..407545f8a 100644 --- a/src/Core/Settings/GlobalSettings.cs +++ b/src/Core/Settings/GlobalSettings.cs @@ -280,9 +280,8 @@ namespace Bit.Core.Settings public string ReplyToEmail { get; set; } public string AmazonConfigSetName { get; set; } public SmtpSettings Smtp { get; set; } = new SmtpSettings(); - public string PostalDomain { get; set; } - public string PostalApiKey { get; set; } - public int? PostalPercentage { get; set; } + public string SendGridApiKey { get; set; } + public int? SendGridPercentage { get; set; } public class SmtpSettings { diff --git a/src/Core/packages.lock.json b/src/Core/packages.lock.json index 145213cd3..8fe8b7555 100644 --- a/src/Core/packages.lock.json +++ b/src/Core/packages.lock.json @@ -247,6 +247,16 @@ "System.Diagnostics.DiagnosticSource": "4.7.1" } }, + "SendGrid": { + "type": "Direct", + "requested": "[9.25.3, )", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry.Serilog": { "type": "Direct", "requested": "[2.1.5, )", @@ -1718,6 +1728,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "System.AppContext": { "type": "Transitive", "resolved": "4.3.0", diff --git a/src/Events/packages.lock.json b/src/Events/packages.lock.json index ab38a4009..73bcbcd5c 100644 --- a/src/Events/packages.lock.json +++ b/src/Events/packages.lock.json @@ -1589,6 +1589,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1804,6 +1813,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3310,6 +3324,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3324,7 +3339,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3333,7 +3348,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3343,9 +3358,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/EventsProcessor/packages.lock.json b/src/EventsProcessor/packages.lock.json index 0c528756d..82e94a042 100644 --- a/src/EventsProcessor/packages.lock.json +++ b/src/EventsProcessor/packages.lock.json @@ -1583,6 +1583,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1798,6 +1807,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3304,6 +3318,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3318,7 +3333,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3327,7 +3342,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3337,9 +3352,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/Icons/packages.lock.json b/src/Icons/packages.lock.json index 3e88c679b..3f66097af 100644 --- a/src/Icons/packages.lock.json +++ b/src/Icons/packages.lock.json @@ -1592,6 +1592,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1807,6 +1816,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3313,6 +3327,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3327,7 +3342,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3336,7 +3351,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3346,9 +3361,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/Identity/packages.lock.json b/src/Identity/packages.lock.json index ab38a4009..73bcbcd5c 100644 --- a/src/Identity/packages.lock.json +++ b/src/Identity/packages.lock.json @@ -1589,6 +1589,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1804,6 +1813,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3310,6 +3324,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3324,7 +3339,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3333,7 +3348,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3343,9 +3358,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/Infrastructure.Dapper/packages.lock.json b/src/Infrastructure.Dapper/packages.lock.json index 57ce78519..f593d9c3c 100644 --- a/src/Infrastructure.Dapper/packages.lock.json +++ b/src/Infrastructure.Dapper/packages.lock.json @@ -1489,6 +1489,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1704,6 +1713,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3230,6 +3244,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", diff --git a/src/Infrastructure.EntityFramework/packages.lock.json b/src/Infrastructure.EntityFramework/packages.lock.json index 764397df6..99e209d06 100644 --- a/src/Infrastructure.EntityFramework/packages.lock.json +++ b/src/Infrastructure.EntityFramework/packages.lock.json @@ -1558,6 +1558,15 @@ "resolved": "4.3.2", "contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1773,6 +1782,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3269,6 +3283,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", diff --git a/src/Notifications/packages.lock.json b/src/Notifications/packages.lock.json index 0364dfeb8..c11a2f3e7 100644 --- a/src/Notifications/packages.lock.json +++ b/src/Notifications/packages.lock.json @@ -1657,6 +1657,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1883,6 +1892,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3404,6 +3418,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3418,7 +3433,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3427,7 +3442,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3437,9 +3452,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs index 244bf608e..a6a2bb3be 100644 --- a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs +++ b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs @@ -156,8 +156,7 @@ namespace Bit.SharedWeb.Utilities } var awsConfigured = CoreHelpers.SettingHasValue(globalSettings.Amazon?.AccessKeySecret); - if (!globalSettings.SelfHosted && awsConfigured && - CoreHelpers.SettingHasValue(globalSettings.Mail?.PostalApiKey)) + if (awsConfigured && CoreHelpers.SettingHasValue(globalSettings.Mail?.SendGridApiKey)) { services.AddSingleton(); } diff --git a/src/SharedWeb/packages.lock.json b/src/SharedWeb/packages.lock.json index 33f743702..9e8bbbe54 100644 --- a/src/SharedWeb/packages.lock.json +++ b/src/SharedWeb/packages.lock.json @@ -1583,6 +1583,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1798,6 +1807,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3304,6 +3318,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3318,7 +3333,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3327,7 +3342,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", diff --git a/test/Api.Test/packages.lock.json b/test/Api.Test/packages.lock.json index e16306a2f..3093bb639 100644 --- a/test/Api.Test/packages.lock.json +++ b/test/Api.Test/packages.lock.json @@ -1737,6 +1737,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1952,6 +1961,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3511,27 +3525,27 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "common": { "type": "Project", "dependencies": { - "Api": "1.46.0", + "Api": "1.46.2", "AutoFixture.AutoNSubstitute": "4.14.0", "AutoFixture.Xunit2": "4.14.0", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.NET.Test.Sdk": "16.6.1", "NSubstitute": "4.2.2", "xunit": "2.4.1" @@ -3564,6 +3578,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3578,7 +3593,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3587,7 +3602,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3597,9 +3612,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/test/Billing.Test/packages.lock.json b/test/Billing.Test/packages.lock.json index b9cfd8f96..cd6d93ac6 100644 --- a/test/Billing.Test/packages.lock.json +++ b/test/Billing.Test/packages.lock.json @@ -1809,6 +1809,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -2024,6 +2033,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3602,36 +3616,36 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "billing": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.VisualStudio.Web.CodeGeneration.Design": "5.0.2", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0" + "SharedWeb": "1.46.2" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "common": { "type": "Project", "dependencies": { - "Api": "1.46.0", + "Api": "1.46.2", "AutoFixture.AutoNSubstitute": "4.14.0", "AutoFixture.Xunit2": "4.14.0", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.NET.Test.Sdk": "16.6.1", "NSubstitute": "4.2.2", "xunit": "2.4.1" @@ -3664,6 +3678,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3678,7 +3693,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3687,7 +3702,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3697,9 +3712,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/test/Common/packages.lock.json b/test/Common/packages.lock.json index f2098832f..3f633151b 100644 --- a/test/Common/packages.lock.json +++ b/test/Common/packages.lock.json @@ -1732,6 +1732,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1947,6 +1956,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3506,18 +3520,18 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "core": { @@ -3547,6 +3561,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3561,7 +3576,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3570,7 +3585,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3580,9 +3595,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/test/Core.Test/Services/SendGridMailDeliveryServiceTests.cs b/test/Core.Test/Services/SendGridMailDeliveryServiceTests.cs new file mode 100644 index 000000000..db2358868 --- /dev/null +++ b/test/Core.Test/Services/SendGridMailDeliveryServiceTests.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Bit.Core.Models.Mail; +using Bit.Core.Services; +using Bit.Core.Settings; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; +using NSubstitute; +using SendGrid; +using SendGrid.Helpers.Mail; +using Xunit; + +namespace Bit.Core.Test.Services +{ + public class SendGridMailDeliveryServiceTests : IDisposable + { + private readonly SendGridMailDeliveryService _sut; + + private readonly GlobalSettings _globalSettings; + private readonly IWebHostEnvironment _hostingEnvironment; + private readonly ILogger _logger; + private readonly ISendGridClient _sendGridClient; + + public SendGridMailDeliveryServiceTests() + { + _globalSettings = new GlobalSettings + { + Mail = + { + SendGridApiKey = "SendGridApiKey" + } + }; + + _hostingEnvironment = Substitute.For(); + _logger = Substitute.For>(); + _sendGridClient = Substitute.For(); + + _sut = new SendGridMailDeliveryService( + _sendGridClient, + _globalSettings, + _hostingEnvironment, + _logger + ); + } + + public void Dispose() + { + _sut?.Dispose(); + } + + [Fact] + public async Task SendEmailAsync_CallsSendEmailAsync_WhenMessageIsValid() + { + var mailMessage = new MailMessage + { + ToEmails = new List { "ToEmails" }, + BccEmails = new List { "BccEmails" }, + Subject = "Subject", + HtmlContent = "HtmlContent", + TextContent = "TextContent", + Category = "Category" + }; + + _sendGridClient.SendEmailAsync(Arg.Any()).Returns( + new Response(System.Net.HttpStatusCode.OK, null, null)); + await _sut.SendEmailAsync(mailMessage); + + await _sendGridClient.Received(1).SendEmailAsync( + Arg.Do(msg => + { + msg.Received(1).AddTos(new List { new EmailAddress(mailMessage.ToEmails.First()) }); + msg.Received(1).AddBccs(new List { new EmailAddress(mailMessage.ToEmails.First()) }); + + Assert.Equal(mailMessage.Subject, msg.Subject); + Assert.Equal(mailMessage.HtmlContent, msg.HtmlContent); + Assert.Equal(mailMessage.TextContent, msg.PlainTextContent); + + Assert.Contains("type:Cateogry", msg.Categories); + Assert.Contains(msg.Categories, x => x.StartsWith("env:")); + Assert.Contains(msg.Categories, x => x.StartsWith("sender:")); + + msg.Received(1).SetClickTracking(false, false); + msg.Received(1).SetOpenTracking(false); + })); + } + } +} diff --git a/test/Core.Test/packages.lock.json b/test/Core.Test/packages.lock.json index cc333d5fc..b4216d13c 100644 --- a/test/Core.Test/packages.lock.json +++ b/test/Core.Test/packages.lock.json @@ -1748,6 +1748,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1963,6 +1972,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3522,27 +3536,27 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "common": { "type": "Project", "dependencies": { - "Api": "1.46.0", + "Api": "1.46.2", "AutoFixture.AutoNSubstitute": "4.14.0", "AutoFixture.Xunit2": "4.14.0", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.NET.Test.Sdk": "16.6.1", "NSubstitute": "4.2.2", "xunit": "2.4.1" @@ -3575,6 +3589,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3589,7 +3604,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3598,7 +3613,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3608,9 +3623,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/test/Icons.Test/packages.lock.json b/test/Icons.Test/packages.lock.json index 5bdffd8e0..114db67ed 100644 --- a/test/Icons.Test/packages.lock.json +++ b/test/Icons.Test/packages.lock.json @@ -1678,6 +1678,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1893,6 +1902,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3443,6 +3457,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3458,14 +3473,14 @@ "type": "Project", "dependencies": { "AngleSharp": "0.14.0", - "Core": "1.46.0", - "SharedWeb": "1.46.0" + "Core": "1.46.2", + "SharedWeb": "1.46.2" } }, "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3474,7 +3489,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3484,9 +3499,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/test/Identity.Test/packages.lock.json b/test/Identity.Test/packages.lock.json index 475f548d9..28d6ccdd6 100644 --- a/test/Identity.Test/packages.lock.json +++ b/test/Identity.Test/packages.lock.json @@ -1737,6 +1737,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1952,6 +1961,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3511,27 +3525,27 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "common": { "type": "Project", "dependencies": { - "Api": "1.46.0", + "Api": "1.46.2", "AutoFixture.AutoNSubstitute": "4.14.0", "AutoFixture.Xunit2": "4.14.0", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.NET.Test.Sdk": "16.6.1", "NSubstitute": "4.2.2", "xunit": "2.4.1" @@ -3564,6 +3578,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3578,15 +3593,15 @@ "identity": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0" + "SharedWeb": "1.46.2" } }, "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3595,7 +3610,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3605,9 +3620,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/util/Migrator/packages.lock.json b/util/Migrator/packages.lock.json index 9ff638504..b33281578 100644 --- a/util/Migrator/packages.lock.json +++ b/util/Migrator/packages.lock.json @@ -1495,6 +1495,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1710,6 +1719,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3247,6 +3261,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", diff --git a/util/MySqlMigrations/packages.lock.json b/util/MySqlMigrations/packages.lock.json index 2da27d60e..a0c2df9eb 100644 --- a/util/MySqlMigrations/packages.lock.json +++ b/util/MySqlMigrations/packages.lock.json @@ -1630,6 +1630,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1845,6 +1854,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3360,18 +3374,18 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "core": { @@ -3401,6 +3415,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3415,7 +3430,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3424,7 +3439,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3434,9 +3449,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/util/PostgresMigrations/packages.lock.json b/util/PostgresMigrations/packages.lock.json index 2da27d60e..a0c2df9eb 100644 --- a/util/PostgresMigrations/packages.lock.json +++ b/util/PostgresMigrations/packages.lock.json @@ -1630,6 +1630,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1845,6 +1854,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3360,18 +3374,18 @@ "type": "Project", "dependencies": { "Azure.Messaging.EventGrid": "4.7.0", - "CommCore": "1.46.0", - "Core": "1.46.0", + "CommCore": "1.46.2", + "Core": "1.46.2", "Microsoft.AspNetCore.Mvc.NewtonsoftJson": "5.0.9", "NewRelic.Agent": "8.41.0", - "SharedWeb": "1.46.0", + "SharedWeb": "1.46.2", "Swashbuckle.AspNetCore": "6.2.3" } }, "commcore": { "type": "Project", "dependencies": { - "Core": "1.46.0" + "Core": "1.46.2" } }, "core": { @@ -3401,6 +3415,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3415,7 +3430,7 @@ "infrastructure.dapper": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Dapper": "2.0.123", "System.Data.SqlClient": "4.8.3" } @@ -3424,7 +3439,7 @@ "type": "Project", "dependencies": { "AutoMapper.Extensions.Microsoft.DependencyInjection": "8.0.1", - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.EntityFrameworkCore.Relational": "5.0.12", "Npgsql.EntityFrameworkCore.PostgreSQL": "5.0.2", "Pomelo.EntityFrameworkCore.MySql": "5.0.3", @@ -3434,9 +3449,9 @@ "sharedweb": { "type": "Project", "dependencies": { - "Core": "1.46.0", - "Infrastructure.Dapper": "1.46.0", - "Infrastructure.EntityFramework": "1.46.0" + "Core": "1.46.2", + "Infrastructure.Dapper": "1.46.2", + "Infrastructure.EntityFramework": "1.46.2" } } } diff --git a/util/Setup/packages.lock.json b/util/Setup/packages.lock.json index 8f44a06ec..1edf71338 100644 --- a/util/Setup/packages.lock.json +++ b/util/Setup/packages.lock.json @@ -1501,6 +1501,15 @@ "resolved": "4.4.0", "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.25.3", + "contentHash": "Dldhsc4+jV28rfa53W+09A549lDfKqGEFFtdOU4uOxHvS/pFhBN8lRkAEzvbMbycwZJJCzfrDdKc/qT1MxWynQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, "Sentry": { "type": "Transitive", "resolved": "2.1.5", @@ -1716,6 +1725,11 @@ "System.Threading.Timer": "4.3.0" } }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, "Stripe.net": { "type": "Transitive", "resolved": "37.26.0", @@ -3253,6 +3267,7 @@ "Newtonsoft.Json": "12.0.3", "Otp.NET": "1.2.2", "Quartz": "3.1.0", + "SendGrid": "9.25.3", "Sentry.Serilog": "2.1.5", "Serilog.AspNetCore": "3.4.0", "Serilog.Extensions.Logging": "3.0.1", @@ -3267,7 +3282,7 @@ "migrator": { "type": "Project", "dependencies": { - "Core": "1.46.0", + "Core": "1.46.2", "Microsoft.Extensions.Logging": "5.0.0", "dbup-sqlserver": "4.4.0" }