124 lines
4.2 KiB
C#
124 lines
4.2 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
|
|
namespace StellaOps.Feedser.Source.Vndr.Cisco.Internal;
|
|
|
|
internal static class CiscoCsafParser
|
|
{
|
|
public static CiscoCsafData Parse(string content)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(content))
|
|
{
|
|
return new CiscoCsafData(
|
|
Products: new Dictionary<string, CiscoCsafProduct>(0, StringComparer.OrdinalIgnoreCase),
|
|
ProductStatuses: new Dictionary<string, IReadOnlyCollection<string>>(0, StringComparer.OrdinalIgnoreCase));
|
|
}
|
|
|
|
using var document = JsonDocument.Parse(content);
|
|
var root = document.RootElement;
|
|
|
|
var products = ParseProducts(root);
|
|
var statuses = ParseStatuses(root);
|
|
|
|
return new CiscoCsafData(products, statuses);
|
|
}
|
|
|
|
private static IReadOnlyDictionary<string, CiscoCsafProduct> ParseProducts(JsonElement root)
|
|
{
|
|
var dictionary = new Dictionary<string, CiscoCsafProduct>(StringComparer.OrdinalIgnoreCase);
|
|
if (!root.TryGetProperty("product_tree", out var productTree))
|
|
{
|
|
return dictionary;
|
|
}
|
|
|
|
if (productTree.TryGetProperty("full_product_names", out var fullProductNames)
|
|
&& fullProductNames.ValueKind == JsonValueKind.Array)
|
|
{
|
|
foreach (var entry in fullProductNames.EnumerateArray())
|
|
{
|
|
var productId = entry.TryGetProperty("product_id", out var idElement) && idElement.ValueKind == JsonValueKind.String
|
|
? idElement.GetString()
|
|
: null;
|
|
|
|
if (string.IsNullOrWhiteSpace(productId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var name = entry.TryGetProperty("name", out var nameElement) && nameElement.ValueKind == JsonValueKind.String
|
|
? nameElement.GetString()
|
|
: null;
|
|
|
|
if (string.IsNullOrWhiteSpace(name))
|
|
{
|
|
name = productId;
|
|
}
|
|
|
|
dictionary[productId] = new CiscoCsafProduct(productId, name);
|
|
}
|
|
}
|
|
|
|
return dictionary;
|
|
}
|
|
|
|
private static IReadOnlyDictionary<string, IReadOnlyCollection<string>> ParseStatuses(JsonElement root)
|
|
{
|
|
var map = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
if (!root.TryGetProperty("vulnerabilities", out var vulnerabilities)
|
|
|| vulnerabilities.ValueKind != JsonValueKind.Array)
|
|
{
|
|
return map.ToDictionary(
|
|
static kvp => kvp.Key,
|
|
static kvp => (IReadOnlyCollection<string>)kvp.Value.ToArray(),
|
|
StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
foreach (var vulnerability in vulnerabilities.EnumerateArray())
|
|
{
|
|
if (!vulnerability.TryGetProperty("product_status", out var productStatus)
|
|
|| productStatus.ValueKind != JsonValueKind.Object)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var property in productStatus.EnumerateObject())
|
|
{
|
|
var statusLabel = property.Name;
|
|
if (property.Value.ValueKind != JsonValueKind.Array)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var productIdElement in property.Value.EnumerateArray())
|
|
{
|
|
if (productIdElement.ValueKind != JsonValueKind.String)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var productId = productIdElement.GetString();
|
|
if (string.IsNullOrWhiteSpace(productId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!map.TryGetValue(productId, out var set))
|
|
{
|
|
set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
map[productId] = set;
|
|
}
|
|
|
|
set.Add(statusLabel);
|
|
}
|
|
}
|
|
}
|
|
|
|
return map.ToDictionary(
|
|
static kvp => kvp.Key,
|
|
static kvp => (IReadOnlyCollection<string>)kvp.Value.ToArray(),
|
|
StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
}
|