125 lines
4.2 KiB
C#
125 lines
4.2 KiB
C#
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|