108 lines
3.7 KiB
C#
108 lines
3.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace StellaOps.Feedser.Source.Distro.Debian.Internal;
|
|
|
|
internal static class DebianListParser
|
|
{
|
|
private static readonly Regex HeaderRegex = new("^\\[(?<date>[^\\]]+)\\]\\s+(?<id>DSA-\\d{4,}-\\d+)\\s+(?<title>.+)$", RegexOptions.Compiled);
|
|
private static readonly Regex CveRegex = new("CVE-\\d{4}-\\d{3,7}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
|
|
|
public static IReadOnlyList<DebianListEntry> Parse(string? content)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(content))
|
|
{
|
|
return Array.Empty<DebianListEntry>();
|
|
}
|
|
|
|
var entries = new List<DebianListEntry>();
|
|
var currentCves = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
DateTimeOffset currentDate = default;
|
|
string? currentId = null;
|
|
string? currentTitle = null;
|
|
string? currentPackage = null;
|
|
|
|
foreach (var rawLine in content.Split('\n'))
|
|
{
|
|
var line = rawLine.TrimEnd('\r');
|
|
if (string.IsNullOrWhiteSpace(line))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (line[0] == '[')
|
|
{
|
|
if (currentId is not null && currentTitle is not null && currentPackage is not null)
|
|
{
|
|
entries.Add(new DebianListEntry(
|
|
currentId,
|
|
currentDate,
|
|
currentTitle,
|
|
currentPackage,
|
|
currentCves.Count == 0 ? Array.Empty<string>() : new List<string>(currentCves)));
|
|
}
|
|
|
|
currentCves.Clear();
|
|
currentId = null;
|
|
currentTitle = null;
|
|
currentPackage = null;
|
|
|
|
var match = HeaderRegex.Match(line);
|
|
if (!match.Success)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!DateTimeOffset.TryParseExact(
|
|
match.Groups["date"].Value,
|
|
new[] { "dd MMM yyyy", "d MMM yyyy" },
|
|
CultureInfo.InvariantCulture,
|
|
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
|
|
out currentDate))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
currentId = match.Groups["id"].Value.Trim();
|
|
currentTitle = match.Groups["title"].Value.Trim();
|
|
|
|
var separatorIndex = currentTitle.IndexOf(" - ", StringComparison.Ordinal);
|
|
currentPackage = separatorIndex > 0
|
|
? currentTitle[..separatorIndex].Trim()
|
|
: currentTitle.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).FirstOrDefault();
|
|
if (string.IsNullOrWhiteSpace(currentPackage))
|
|
{
|
|
currentPackage = currentId;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (line[0] == '{')
|
|
{
|
|
foreach (Match match in CveRegex.Matches(line))
|
|
{
|
|
if (match.Success && !string.IsNullOrWhiteSpace(match.Value))
|
|
{
|
|
currentCves.Add(match.Value.ToUpperInvariant());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (currentId is not null && currentTitle is not null && currentPackage is not null)
|
|
{
|
|
entries.Add(new DebianListEntry(
|
|
currentId,
|
|
currentDate,
|
|
currentTitle,
|
|
currentPackage,
|
|
currentCves.Count == 0 ? Array.Empty<string>() : new List<string>(currentCves)));
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
}
|