up
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user