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; /// [RegisterScoped] public class EmailDomainBlacklistService : IEmailDomainBlacklistService { private readonly EmailDomainBlacklistConfiguration _configuration; private readonly IEmailDomainBlacklistRepository _repository; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Instance of . /// Instance of . /// Instance of . public EmailDomainBlacklistService( IOptions configuration, IEmailDomainBlacklistRepository repository, ILogger logger) { _configuration = configuration.Value; _repository = repository; _logger = logger; } /// 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); } /// public async Task 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; } } }