Вынести условия-предикаты в extension-методы
HasUser из 13 endpoint-файлов сведён в AuthHelpers.HasUser; 15 приватных предикатов заменены extension-методами с удалением дублирующих приватных методов: IsCommunicationFailure, IsTransportFailure, IsPrivateEndpoint, IsConfigured, IsTrue, IsExpired, IsFailedLogin/IsSuccessfulLogin, HasChanges, HasBudget, HasAnyTerm, IsCurrencyLetter, IsEmojiCodePoint, ContainsFooterHint, IsTypeLabel.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Deal.Infrastructure.Integrations;
|
||||
|
||||
/// <summary>
|
||||
/// Расширения <see cref="Uri"/> для SSRF-гейта интеграций (проверка приватности адреса).
|
||||
/// </summary>
|
||||
internal static class UriExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Проверяет, указывает ли URL на приватный/loopback/link-local адрес (SSRF-гейт).
|
||||
/// Распознаются IP-литералы (IPv4/IPv6) и имя localhost; DNS-имена считаются публичными
|
||||
/// (полный egress-контроль с резолвом выполняется на сетевом периметре).
|
||||
/// </summary>
|
||||
/// <param name="uri">Абсолютный http(s)-адрес.</param>
|
||||
/// <returns>True — адрес приватный/локальный (HTTP к нему запрещён).</returns>
|
||||
public static bool IsPrivateEndpoint(this Uri uri)
|
||||
{
|
||||
string host = uri.Host;
|
||||
if (string.Equals(host, "localhost", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IPAddress.TryParse(host, out IPAddress? address))
|
||||
{
|
||||
return false; // DNS-имя — резолв вне этого слоя
|
||||
}
|
||||
|
||||
if (address.IsIPv4MappedToIPv6)
|
||||
{
|
||||
address = address.MapToIPv4();
|
||||
}
|
||||
|
||||
if (IPAddress.IsLoopback(address))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (address.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
byte[] bytes = address.GetAddressBytes();
|
||||
return bytes[0] == 10
|
||||
|| (bytes[0] == 172 && bytes[1] is >= 16 and <= 31)
|
||||
|| (bytes[0] == 192 && bytes[1] == 168)
|
||||
|| bytes[0] == 169 && bytes[1] == 254 // link-local (включая 169.254.169.254 metadata)
|
||||
|| bytes[0] == 0;
|
||||
}
|
||||
|
||||
// IPv6: уникальные локальные (fc00::/7) и link-local (fe80::/10).
|
||||
byte[] v6 = address.GetAddressBytes();
|
||||
return (v6[0] & 0xFE) == 0xFC || (v6[0] == 0xFE && (v6[1] & 0xC0) == 0x80);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user