feat: rate limit emails to two per address per hour
This commit is contained in:
parent
5cb3faa92b
commit
ff8d53814d
6 changed files with 189 additions and 49 deletions
|
@ -12,13 +12,25 @@
|
|||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
using Coravel.Mailer.Mail;
|
||||
using Coravel.Mailer.Mail.Interfaces;
|
||||
using Coravel.Queuing.Interfaces;
|
||||
using Foxnouns.Backend.Database;
|
||||
using Foxnouns.Backend.Database.Models;
|
||||
using Foxnouns.Backend.Mailables;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
|
||||
namespace Foxnouns.Backend.Services;
|
||||
|
||||
public class MailService(ILogger logger, IMailer mailer, IQueue queue, Config config)
|
||||
public class MailService(
|
||||
ILogger logger,
|
||||
IMailer mailer,
|
||||
IQueue queue,
|
||||
IClock clock,
|
||||
Config config,
|
||||
IServiceProvider serviceProvider
|
||||
)
|
||||
{
|
||||
private readonly ILogger _logger = logger.ForContext<MailService>();
|
||||
|
||||
|
@ -26,25 +38,18 @@ public class MailService(ILogger logger, IMailer mailer, IQueue queue, Config co
|
|||
{
|
||||
queue.QueueAsyncTask(async () =>
|
||||
{
|
||||
_logger.Debug("Sending account creation email to {ToEmail}", to);
|
||||
try
|
||||
{
|
||||
await mailer.SendAsync(
|
||||
new AccountCreationMailable(
|
||||
config,
|
||||
new AccountCreationMailableView
|
||||
{
|
||||
BaseUrl = config.BaseUrl,
|
||||
To = to,
|
||||
Code = code,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
_logger.Error(exc, "Sending account creation email");
|
||||
}
|
||||
await SendEmailAsync(
|
||||
to,
|
||||
new AccountCreationMailable(
|
||||
config,
|
||||
new AccountCreationMailableView
|
||||
{
|
||||
BaseUrl = config.BaseUrl,
|
||||
To = to,
|
||||
Code = code,
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -53,25 +58,53 @@ public class MailService(ILogger logger, IMailer mailer, IQueue queue, Config co
|
|||
_logger.Debug("Sending add email address email to {ToEmail}", to);
|
||||
queue.QueueAsyncTask(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await mailer.SendAsync(
|
||||
new AddEmailMailable(
|
||||
config,
|
||||
new AddEmailMailableView
|
||||
{
|
||||
BaseUrl = config.BaseUrl,
|
||||
To = to,
|
||||
Code = code,
|
||||
Username = username,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
_logger.Error(exc, "Sending add email address email");
|
||||
}
|
||||
await SendEmailAsync(
|
||||
to,
|
||||
new AddEmailMailable(
|
||||
config,
|
||||
new AddEmailMailableView
|
||||
{
|
||||
BaseUrl = config.BaseUrl,
|
||||
To = to,
|
||||
Code = code,
|
||||
Username = username,
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task SendEmailAsync<T>(string to, Mailable<T> mailable)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ReSharper disable SuggestVarOrType_SimpleTypes
|
||||
await using var scope = serviceProvider.CreateAsyncScope();
|
||||
await using var db = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
|
||||
// ReSharper restore SuggestVarOrType_SimpleTypes
|
||||
|
||||
Instant now = clock.GetCurrentInstant();
|
||||
|
||||
int count = await db.SentEmails.CountAsync(e =>
|
||||
e.Email == to && e.SentAt > (now - Duration.FromHours(1))
|
||||
);
|
||||
if (count >= 2)
|
||||
{
|
||||
_logger.Information(
|
||||
"Have already sent 2 or more emails to {ToAddress} in the past hour, not sending new email",
|
||||
to
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await mailer.SendAsync(mailable);
|
||||
|
||||
db.SentEmails.Add(new SentEmail { Email = to, SentAt = now });
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
_logger.Error(exc, "Sending email");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue