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(0, StringComparer.OrdinalIgnoreCase), ProductStatuses: new Dictionary>(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 ParseProducts(JsonElement root) { var dictionary = new Dictionary(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> ParseStatuses(JsonElement root) { var map = new Dictionary>(StringComparer.OrdinalIgnoreCase); if (!root.TryGetProperty("vulnerabilities", out var vulnerabilities) || vulnerabilities.ValueKind != JsonValueKind.Array) { return map.ToDictionary( static kvp => kvp.Key, static kvp => (IReadOnlyCollection)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(StringComparer.OrdinalIgnoreCase); map[productId] = set; } set.Add(statusLabel); } } } return map.ToDictionary( static kvp => kvp.Key, static kvp => (IReadOnlyCollection)kvp.Value.ToArray(), StringComparer.OrdinalIgnoreCase); } }