Beispiel #1
0
 /*
  * Adds a Component to the map using the PackageURL of the component as the key.
  */
 void AddPreventDuplicates(Model.Component component)
 {
     if (component.Purl != null && !dependencyMap.ContainsKey(component.Purl))
     {
         dependencyMap.Add(component.Purl, component);
     }
 }
Beispiel #2
0
        /*
         * Retrieves additional information for the specified Component from NuGet and
         * updates the component.
         */
        async Task <int> RetrieveExtendedNugetAttributes(Model.Component component, bool followTransitive)
        {
            var url = baseUrl + component.Name + "/" + component.Version + "/" + component.Name + ".nuspec";

            Console.WriteLine("Retrieving " + component.Name + " " + component.Version);
            var client = new HttpClient();

            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
            HttpResponseMessage response;

            try {
                response = await client.GetAsync(url);
            } catch (Exception ex) {
                Console.WriteLine($"  An unhandled exception occurred while querying nuget.org for additional package information: {ex.Message}");
                return(1);
            }
            var contentAsString = await response.Content.ReadAsStringAsync();

            if (!response.IsSuccessStatusCode)
            {
                if ((int)response.StatusCode != 404)
                {
                    Console.WriteLine($"  An unhandled exception occurred while querying nuget.org for additional package information: {(int)response.StatusCode} {response.StatusCode} {contentAsString}");
                }
                return(1);
            }
            var doc = new XmlDocument();

            doc.LoadXml(contentAsString);
            var root     = doc.DocumentElement;
            var metadata = root.SelectSingleNode("/*[local-name() = 'package']/*[local-name() = 'metadata']");

            component.Publisher = getNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'authors']");
            component.Copyright = getNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'copyright']");
            var title       = getNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'title']");
            var summary     = getNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'summary']");
            var description = getNodeValue(metadata, "/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'description']");

            if (summary != null)
            {
                component.Description = summary;
            }
            else if (description != null)
            {
                component.Description = description;
            }
            else if (title != null)
            {
                component.Description = title;
            }

            // Utilize the new license expression field present in more recent packages
            // TODO: Need to have more robust parsing to support composite expressions seen in (https://github.com/NuGet/Home/wiki/Packaging-License-within-the-nupkg#project-properties)
            var licenseNode = metadata.SelectSingleNode("/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'license']");

            if (licenseNode?.Attributes["type"].Value == "expression")
            {
                var licenses = licenseNode.FirstChild.Value
                               .Replace("AND", ";")
                               .Replace("OR", ";")
                               .Replace("WITH", ";")
                               .Replace("+", "")
                               .Split(';').ToList();
                foreach (var license in licenses)
                {
                    component.Licenses.Add(new Model.License
                    {
                        Id   = license.Trim(),
                        Name = license.Trim()
                    });
                }
            }

            // As a final step (and before optionally fetching transitive dependencies), add the component to the dictionary.
            AddPreventDuplicates(component);

            if (followTransitive)
            {
                var dependencies = metadata.SelectNodes("/*[local-name() = 'package']/*[local-name() = 'metadata']/*[local-name() = 'dependencies']/*[local-name() = 'dependency']");
                foreach (XmlNode dependency in dependencies)
                {
                    var id      = dependency.Attributes["id"];
                    var version = dependency.Attributes["version"];
                    if (id != null && version != null)
                    {
                        var transitive = new Model.Component();
                        transitive.Name    = id.Value;
                        transitive.Version = version.Value;
                        transitive.Purl    = generatePackageUrl(transitive.Name, transitive.Version);
                        await RetrieveExtendedNugetAttributes(transitive, false);
                    }
                }
            }
            return(0);
        }
Beispiel #3
0
        /*
         * Analyzes a single Project.
         */
        async Task <int> AnalyzeProjectAsync(string projectFile)
        {
            var components = new List <Model.Component>();

            if (!File.Exists(projectFile))
            {
                Console.Error.WriteLine($"Project file \"{projectFile}\" does not exist");
                return(1);
            }
            Console.WriteLine();
            Console.WriteLine($"» Analyzing: {projectFile}");
            Console.WriteLine("  Getting packages".PadRight(64));
            try {
                using (XmlReader reader = XmlReader.Create(projectFile)) {
                    while (reader.Read())
                    {
                        if (reader.IsStartElement())
                        {
                            switch (reader.Name)
                            {
                            case "PackageReference": {     // For managed NuGet dependencies defined in a project (csproj/vbproj)
                                var component      = new Model.Component();
                                var packageName    = reader["Include"];
                                var packageVersion = reader["Version"];
                                component.Name    = packageName;
                                component.Version = packageVersion;
                                component.Purl    = generatePackageUrl(packageName, packageVersion);
                                int val = await RetrieveExtendedNugetAttributes(component, true);

                                if (val != 0)
                                {
                                    // An error occurred while fetching the unmanaged dependency from NuGet.
                                    // Add the dependency to the component dictionary.
                                    AddPreventDuplicates(component);
                                }
                                components.Add(component);
                                break;
                            }

                            case "package": {     // For managed NuGet dependencies defined in a seperate packages.config
                                var component      = new Model.Component();
                                var packageName    = reader["id"];
                                var packageVersion = reader["version"];
                                component.Name    = packageName;
                                component.Version = packageVersion;
                                component.Purl    = generatePackageUrl(packageName, packageVersion);
                                int val = await RetrieveExtendedNugetAttributes(component, true);

                                if (val != 0)
                                {
                                    // An error occurred while fetching the unmanaged dependency from NuGet.
                                    // Add the dependency to the component dictionary.
                                    AddPreventDuplicates(component);
                                }
                                components.Add(component);
                                break;
                            }
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                Console.Error.WriteLine($"  An unhandled exception occurred while getting the packages: {ex.Message}");
                return(1);
            }
            if (!components.Any())
            {
                Console.Error.WriteLine("  No packages found".PadRight(64));
            }
            return(0);
        }