mirror of
https://github.com/bitwarden/server.git
synced 2025-05-03 18:52:22 -05:00

* Initial stubbing out of the phishing service * Add the phishing domain controller * Add changes for the phishing domain get * Add distributed cache to the phishing domain Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * Rename the variable name Signed-off-by: Cy Okeke <cokeke@bitwarden.com> * Removed IPhishingDomainService * Feature/phishing detection cronjob (#5512) * Added caching to EF implementation. Added error handling and logging * Refactored update method to use sqlbulkcopy instead of performing a round trip for each new insert * Initial implementation for quartz job to get list of phishing domains * Updated phishing domain settings to be its own interface * Add phishing domain detection with checksum-based updates * Updated auth for phishing domain endpoints to either require api, or licensing claims to support both web and browser clients, and selfhost api clients * [Innovation Sprint] Updated Phishing domains to rely on blob storage (#5517) * Updated phishing detection data layer to rely on azure blob storage instead of sql server * dotnet format * Took rider refactors * Ensuring phishing.testcategory.com exists to test against * Added redis to dev's docker-compose * Removed redis from cloud profile * Remove the Authorize attribute * error whitespace fix whitespace formatting * error WHITESPACE: Fix whitespace formatting * Wrapped phishing detection feature behind feature flag (#5532) * Increased timeout for fetching source list a bunch * Removed PhishingDomains policy --------- Signed-off-by: Cy Okeke <cokeke@bitwarden.com> Co-authored-by: Cy Okeke <cokeke@bitwarden.com>
101 lines
3.4 KiB
C#
101 lines
3.4 KiB
C#
using Bit.Core.PhishingDomainFeatures.Interfaces;
|
|
using Bit.Core.Settings;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Bit.Core.PhishingDomainFeatures;
|
|
|
|
/// <summary>
|
|
/// Implementation of ICloudPhishingDomainQuery for cloud environments
|
|
/// that directly calls the external phishing domain source
|
|
/// </summary>
|
|
public class CloudPhishingDomainDirectQuery : ICloudPhishingDomainQuery
|
|
{
|
|
private readonly IGlobalSettings _globalSettings;
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
private readonly ILogger<CloudPhishingDomainDirectQuery> _logger;
|
|
|
|
public CloudPhishingDomainDirectQuery(
|
|
IGlobalSettings globalSettings,
|
|
IHttpClientFactory httpClientFactory,
|
|
ILogger<CloudPhishingDomainDirectQuery> logger)
|
|
{
|
|
_globalSettings = globalSettings;
|
|
_httpClientFactory = httpClientFactory;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<List<string>> GetPhishingDomainsAsync()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(_globalSettings.PhishingDomain?.UpdateUrl))
|
|
{
|
|
throw new InvalidOperationException("Phishing domain update URL is not configured.");
|
|
}
|
|
|
|
var httpClient = _httpClientFactory.CreateClient("PhishingDomains");
|
|
var response = await httpClient.GetAsync(_globalSettings.PhishingDomain.UpdateUrl);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var content = await response.Content.ReadAsStringAsync();
|
|
return ParseDomains(content);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the SHA256 checksum of the remote phishing domains list
|
|
/// </summary>
|
|
/// <returns>The SHA256 checksum as a lowercase hex string</returns>
|
|
public async Task<string> GetRemoteChecksumAsync()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(_globalSettings.PhishingDomain?.ChecksumUrl))
|
|
{
|
|
_logger.LogWarning("Phishing domain checksum URL is not configured.");
|
|
return string.Empty;
|
|
}
|
|
|
|
try
|
|
{
|
|
var httpClient = _httpClientFactory.CreateClient("PhishingDomains");
|
|
var response = await httpClient.GetAsync(_globalSettings.PhishingDomain.ChecksumUrl);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var content = await response.Content.ReadAsStringAsync();
|
|
return ParseChecksumResponse(content);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error retrieving phishing domain checksum from {Url}",
|
|
_globalSettings.PhishingDomain.ChecksumUrl);
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses a checksum response in the format "hash *filename"
|
|
/// </summary>
|
|
private static string ParseChecksumResponse(string checksumContent)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(checksumContent))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
// Format is typically "hash *filename"
|
|
var parts = checksumContent.Split(' ', 2);
|
|
|
|
return parts.Length > 0 ? parts[0].Trim() : string.Empty;
|
|
}
|
|
|
|
private static List<string> ParseDomains(string content)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(content))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
return content
|
|
.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries)
|
|
.Select(line => line.Trim())
|
|
.Where(line => !string.IsNullOrWhiteSpace(line) && !line.StartsWith("#"))
|
|
.ToList();
|
|
}
|
|
}
|