197 lines
6.4 KiB
C#
197 lines
6.4 KiB
C#
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Globalization;
|
|
using System.Xml.Linq;
|
|
|
|
namespace StellaOps.Feedser.Source.Ru.Bdu.Internal;
|
|
|
|
internal static class RuBduXmlParser
|
|
{
|
|
public static RuBduVulnerabilityDto? TryParse(XElement element)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(element);
|
|
|
|
var identifier = element.Element("identifier")?.Value?.Trim();
|
|
if (string.IsNullOrWhiteSpace(identifier))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var name = Normalize(element.Element("name")?.Value);
|
|
var description = Normalize(element.Element("description")?.Value);
|
|
var solution = Normalize(element.Element("solution")?.Value);
|
|
var severity = Normalize(element.Element("severity")?.Value);
|
|
var exploitStatus = Normalize(element.Element("exploit_status")?.Value);
|
|
var fixStatus = Normalize(element.Element("fix_status")?.Value);
|
|
var vulStatus = Normalize(element.Element("vul_status")?.Value);
|
|
var vulClass = Normalize(element.Element("vul_class")?.Value);
|
|
var vulState = Normalize(element.Element("vul_state")?.Value);
|
|
var other = Normalize(element.Element("other")?.Value);
|
|
var incidentCount = ParseInt(element.Element("vul_incident")?.Value);
|
|
|
|
var identifyDate = ParseDate(element.Element("identify_date")?.Value);
|
|
|
|
var cvssVectorElement = element.Element("cvss")?.Element("vector");
|
|
var cvssVector = Normalize(cvssVectorElement?.Value);
|
|
var cvssScore = ParseDouble(cvssVectorElement?.Attribute("score")?.Value);
|
|
|
|
var cvss3VectorElement = element.Element("cvss3")?.Element("vector");
|
|
var cvss3Vector = Normalize(cvss3VectorElement?.Value);
|
|
var cvss3Score = ParseDouble(cvss3VectorElement?.Attribute("score")?.Value);
|
|
|
|
var software = ParseSoftware(element.Element("vulnerable_software"));
|
|
var environment = ParseEnvironment(element.Element("environment"));
|
|
var cwes = ParseCwes(element.Element("cwes"));
|
|
|
|
return new RuBduVulnerabilityDto(
|
|
identifier.Trim(),
|
|
name,
|
|
description,
|
|
solution,
|
|
identifyDate,
|
|
severity,
|
|
cvssVector,
|
|
cvssScore,
|
|
cvss3Vector,
|
|
cvss3Score,
|
|
exploitStatus,
|
|
incidentCount,
|
|
fixStatus,
|
|
vulStatus,
|
|
vulClass,
|
|
vulState,
|
|
other,
|
|
software,
|
|
environment,
|
|
cwes);
|
|
}
|
|
|
|
private static ImmutableArray<RuBduSoftwareDto> ParseSoftware(XElement? root)
|
|
{
|
|
if (root is null)
|
|
{
|
|
return ImmutableArray<RuBduSoftwareDto>.Empty;
|
|
}
|
|
|
|
var builder = ImmutableArray.CreateBuilder<RuBduSoftwareDto>();
|
|
foreach (var soft in root.Elements("soft"))
|
|
{
|
|
var vendor = Normalize(soft.Element("vendor")?.Value);
|
|
var name = Normalize(soft.Element("name")?.Value);
|
|
var version = Normalize(soft.Element("version")?.Value);
|
|
var platform = Normalize(soft.Element("platform")?.Value);
|
|
var types = soft.Element("types") is { } typesElement
|
|
? typesElement.Elements("type").Select(static x => Normalize(x.Value)).Where(static value => !string.IsNullOrWhiteSpace(value)).Cast<string>().ToImmutableArray()
|
|
: ImmutableArray<string>.Empty;
|
|
|
|
builder.Add(new RuBduSoftwareDto(vendor, name, version, platform, types));
|
|
}
|
|
|
|
return builder.ToImmutable();
|
|
}
|
|
|
|
private static ImmutableArray<RuBduEnvironmentDto> ParseEnvironment(XElement? root)
|
|
{
|
|
if (root is null)
|
|
{
|
|
return ImmutableArray<RuBduEnvironmentDto>.Empty;
|
|
}
|
|
|
|
var builder = ImmutableArray.CreateBuilder<RuBduEnvironmentDto>();
|
|
foreach (var os in root.Elements())
|
|
{
|
|
var vendor = Normalize(os.Element("vendor")?.Value);
|
|
var name = Normalize(os.Element("name")?.Value);
|
|
var version = Normalize(os.Element("version")?.Value);
|
|
var platform = Normalize(os.Element("platform")?.Value);
|
|
builder.Add(new RuBduEnvironmentDto(vendor, name, version, platform));
|
|
}
|
|
|
|
return builder.ToImmutable();
|
|
}
|
|
|
|
private static ImmutableArray<RuBduCweDto> ParseCwes(XElement? root)
|
|
{
|
|
if (root is null)
|
|
{
|
|
return ImmutableArray<RuBduCweDto>.Empty;
|
|
}
|
|
|
|
var builder = ImmutableArray.CreateBuilder<RuBduCweDto>();
|
|
foreach (var cwe in root.Elements("cwe"))
|
|
{
|
|
var identifier = Normalize(cwe.Element("identifier")?.Value);
|
|
if (string.IsNullOrWhiteSpace(identifier))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var name = Normalize(cwe.Element("name")?.Value);
|
|
builder.Add(new RuBduCweDto(identifier, name));
|
|
}
|
|
|
|
return builder.ToImmutable();
|
|
}
|
|
|
|
private static DateTimeOffset? ParseDate(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var trimmed = value.Trim();
|
|
if (DateTimeOffset.TryParse(trimmed, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var isoDate))
|
|
{
|
|
return isoDate;
|
|
}
|
|
|
|
if (DateTimeOffset.TryParseExact(trimmed, new[] { "dd.MM.yyyy", "dd.MM.yyyy HH:mm:ss" }, CultureInfo.GetCultureInfo("ru-RU"), DateTimeStyles.AssumeUniversal, out var ruDate))
|
|
{
|
|
return ruDate;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static double? ParseDouble(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (double.TryParse(value.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out var parsed))
|
|
{
|
|
return parsed;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static int? ParseInt(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (int.TryParse(value.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsed))
|
|
{
|
|
return parsed;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static string? Normalize(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return value.Replace('\r', ' ').Replace('\n', ' ').Trim();
|
|
}
|
|
}
|