Ejemplo n.º 1
0
 public Info(OSSVulnerability v, FeedType feedType, string packageName, IEnumerable <string> versions)
 {
     this.v               = v;
     this.FeedType        = feedType;
     this.PackageName     = packageName;
     this.PackageVersions = VulnerabilityPackageVersionRange.Multiple(versions.Select(VulnerabilityPackageVersionRange.Single));
 }
Ejemplo n.º 2
0
        public override async IAsyncEnumerable <VulnerabilityInfo> GetVulnerabilitiesAsync(IVulnerabilitySourceContext context, [EnumeratorCancellation] CancellationToken cancellationToken = default)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            using (var client = this.GetHttpClient())
            {
                var serializer = new JsonSerializer();

                var receivedVulnerabilities = new Dictionary <string, OSSVulnerability>();

                foreach (var chunk in GetCoordinateChunks(context.Packages))
                {
                    int retries = 0;
Retry:


                    using (var content = getChunkContent(chunk))
                        using (var response = await client.PostAsync("https://ossindex.sonatype.org/api/v3/component-report", content, cancellationToken))
                        {
                            if ((int)response.StatusCode == 429 && retries < 5)
                            {
                                this.LogWarning($"Detected rate limiting. Waiting five minutes before retrying. Attempt {(retries + 1)} of 5.");
                                await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken);

                                retries++;
                                goto Retry;
                            }

                            if (!response.IsSuccessStatusCode)
                            {
                                this.LogError("OSS Index returned failure error code: " + (int)response.StatusCode);
                                this.LogDebug("Content of response: " + await response.Content.ReadAsStringAsync(cancellationToken));
                                yield break;
                            }
                            using (var responseStream = new BufferedStream(await response.Content.ReadAsStreamAsync(cancellationToken)))
                                using (var textReader = new StreamReader(responseStream, InedoLib.UTF8Encoding))
                                    using (var jsonTextReader = new JsonTextReader(textReader))
                                    {
                                        var pvs = serializer.Deserialize <IEnumerable <PackageVulnerabilities> >(jsonTextReader);
                                        this.LogDebug($"Request returned {pvs.Count()} vulnerability records.");

                                        foreach (var pv in pvs)
                                        {
                                            var match = CoordinateRegex.Match(pv.Coordinates);
                                            if (!match.Success)
                                            {
                                                this.LogWarning($"Unable to parse returned package coordinate string '{pv.Coordinates}'");
                                                continue;
                                            }

                                            var feedType = ParseFeedType(match.Groups[1].Value);
                                            if (feedType == null)
                                            {
                                                this.LogWarning($"Unable to determine feed type for returned package coordinate string '{pv.Coordinates}'");
                                                continue;
                                            }

                                            var packageName    = Uri.UnescapeDataString(match.Groups[2].Value);
                                            var packageVersion = match.Groups[3].Value;

                                            foreach (var v in pv.Vulnerabilities)
                                            {
                                                if (!receivedVulnerabilities.TryGetValue(v.Id, out var vulnerability))
                                                {
                                                    vulnerability = new OSSVulnerability(v.Id, v.Title, v.Description, v.CVSSScore, v.Reference);
                                                    receivedVulnerabilities.Add(v.Id, vulnerability);
                                                }

                                                vulnerability.AddPackageVersion(feedType.Value, packageName, packageVersion);
                                            }
                                        }
                                    }
                        }
                }

                foreach (var vulnInfo in receivedVulnerabilities.Values.SelectMany(v => v.GetVulnerabilityInfos()))
                {
                    yield return(vulnInfo);
                }
            }

            HttpContent getChunkContent(string[] chunk)
            {
                var stream = new MemoryStream();

                using (var textWriter = new StreamWriter(stream, InedoLib.UTF8Encoding, 16, true))
                    using (var jsonWriter = new JsonTextWriter(textWriter))
                    {
                        jsonWriter.WriteStartObject();
                        jsonWriter.WritePropertyName("coordinates");
                        jsonWriter.WriteStartArray();
                        foreach (var c in chunk)
                        {
                            jsonWriter.WriteValue(c);
                        }
                        jsonWriter.WriteEndArray();
                        jsonWriter.WriteEndObject();
                    }

                stream.Position = 0;
                return(new StreamContent(stream)
                {
                    Headers =
                    {
                        ContentType = new MediaTypeHeaderValue("application/vnd.ossindex.component-report-request.v1+json")
                    }
                });
            }
        }