galaeth-draft/Galaeth.Services/Services/EmailDomainBlacklistService.cs

125 lines
4.2 KiB
C#
Raw Permalink Normal View History

2024-11-17 10:31:01 +01:00
using System.Net.Mail;
using Galaeth.Core.Entities;
using Galaeth.Core.Extensions;
using Galaeth.Core.RepositoryInterfaces;
using Galaeth.Services.Configuration;
using Galaeth.Services.Interfaces;
using Injectio.Attributes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Galaeth.Services.Services;
/// <inheritdoc/>
[RegisterScoped]
public class EmailDomainBlacklistService : IEmailDomainBlacklistService
{
private readonly EmailDomainBlacklistConfiguration _configuration;
private readonly IEmailDomainBlacklistRepository _repository;
private readonly ILogger<EmailDomainBlacklistService> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="EmailDomainBlacklistService"/> class.
/// </summary>
/// <param name="configuration">Instance of <see cref="IOptions{EmailDomainBlacklistConfiguration}"/>.</param>
/// <param name="repository">Instance of <see cref="IEmailDomainBlacklistRepository"/>.</param>
/// <param name="logger">Instance of <see cref="ILogger"/>.</param>
public EmailDomainBlacklistService(
IOptions<EmailDomainBlacklistConfiguration> configuration,
IEmailDomainBlacklistRepository repository,
ILogger<EmailDomainBlacklistService> logger)
{
_configuration = configuration.Value;
_repository = repository;
_logger = logger;
}
/// <inheritdoc/>
public async Task UpdateBlacklist()
{
if (!_configuration.Enabled)
{
_logger.LogInformation("Email address domain blacklist disabled");
return;
}
_logger.LogInformation("Updating email address domain blacklist");
try
{
var client = new HttpClient();
// Attempt to fetch master list.
var result = await client.GetAsync(_configuration.MasterList);
if (!result.IsSuccessStatusCode)
{
_logger.LogError(
"Failed to retrieve up-to-date blacklisted domains. Http status code: {code}",
result.StatusCode);
return;
}
var content = await result.Content.ReadAsStringAsync();
var entries = content.Split(
["\r\n", "\r", "\n"],
StringSplitOptions.None)
.Where(s => !string.IsNullOrWhiteSpace(s) && s.Trim()[..1] != "#" && s.Trim()[..1] != "[" &&
s.Trim()[..1] != "!");
var existing = await _repository.GetAllAsync();
var newDomains = entries.Except(existing.Select(e => e.Domain)).ToList();
_logger.LogInformation("Adding {count} new domains to the blacklist", newDomains.Count);
// Add new domains to blacklist
var listChunks = newDomains.ChunkBy(1000);
newDomains.Clear();
foreach (var chunk in listChunks)
{
await _repository.AddAsync(chunk.Select(d => new EmailDomainBlacklist()
{
Domain = d,
CreatedAt = DateTime.UtcNow,
}));
}
GC.Collect(2, GCCollectionMode.Aggressive);
GC.WaitForFullGCComplete();
}
catch (Exception exception)
{
_logger.LogError("Failed to retrieve up-to-date blacklisted domains: {exception}", exception);
}
var count = await _repository.CountEntries();
_logger.LogInformation("Total email address domains in blacklist: {count}", count);
}
/// <inheritdoc/>
public async Task<bool> CheckBlacklist(string emailAddress)
{
if (!_configuration.Enabled)
{
return false;
}
try
{
var mailAddress = new MailAddress(emailAddress.ToLowerInvariant());
var domain = mailAddress.Host;
var blacklisted = await _repository.FindByIdAsync(domain);
return blacklisted is not null;
}
catch (Exception exception)
{
_logger.LogWarning(
"Failed to determine if following email address is in the blacklist: {email}. {exception}",
emailAddress.MaskEmailAddress(),
exception);
return false;
}
}
}