예제 #1
0
        /// <inheritdoc />
        public override async Task <PackageMetadata?> GetPackageMetadataAsync(PackageURL purl, bool useCache = true)
        {
            PackageMetadata metadata = new();
            string?         content  = await GetMetadataAsync(purl, useCache);

            if (string.IsNullOrEmpty(content))
            {
                return(null);
            }

            JsonDocument contentJSON = JsonDocument.Parse(content);
            JsonElement  root        = contentJSON.RootElement;

            JsonElement infoElement = root.GetProperty("info");

            metadata.Name        = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "name");
            metadata.Description = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "summary");          // Summary is the short description. Description is usually the readme.

            metadata.LatestPackageVersion = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "version"); // Ran in the root, always points to latest version.

            metadata.PackageManagerUri = ENV_PYPI_ENDPOINT;
            metadata.PackageUri        = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "package_url");
            metadata.Keywords          = OssUtilities.ConvertJSONToList(OssUtilities.GetJSONPropertyIfExists(infoElement, "keywords"));

            // author
            User author = new()
            {
                Name  = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "author"),
                Email = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "author_email"),
            };

            metadata.Authors ??= new List <Model.User>();
            metadata.Authors.Add(author);

            // maintainers
            User maintainer = new()
            {
                Name  = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "maintainer"),
                Email = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "maintainer_email"),
            };

            metadata.Maintainers ??= new List <User>();
            metadata.Maintainers.Add(maintainer);

            // repository
            Dictionary <PackageURL, double>?repoMappings = await SearchRepoUrlsInPackageMetadata(purl, content);

            foreach (KeyValuePair <PackageURL, double> repoMapping in repoMappings)
            {
                Repository repository = new()
                {
                    Rank = repoMapping.Value,
                    Type = repoMapping.Key.Type
                };
                await repository.ExtractRepositoryMetadata(repoMapping.Key);

                metadata.Repository ??= new List <Repository>();
                metadata.Repository.Add(repository);
            }

            // license
            string?licenseType = OssUtilities.GetJSONPropertyStringIfExists(infoElement, "license");

            if (!string.IsNullOrWhiteSpace(licenseType))
            {
                metadata.Licenses ??= new List <License>();
                metadata.Licenses.Add(new License()
                {
                    Name = licenseType
                });
            }

            // get the version, either use the provided one, or if null then use the LatestPackageVersion.
            metadata.PackageVersion = purl.Version ?? metadata.LatestPackageVersion;

            // if we found any version at all, get the information.
            if (metadata.PackageVersion is not null)
            {
                Version     versionToGet   = new(metadata.PackageVersion);
                JsonElement?versionElement = GetVersionElement(contentJSON, versionToGet);
                if (versionElement is not null)
                {
                    // fill the version specific entries

                    if (versionElement.Value.ValueKind == JsonValueKind.Array) // I think this should always be true.
                    {
                        foreach (JsonElement releaseFile in versionElement.Value.EnumerateArray())
                        {
                            // digests
                            if (OssUtilities.GetJSONPropertyIfExists(releaseFile, "digests")?.EnumerateObject()
                                is JsonElement.ObjectEnumerator digests)
                            {
                                metadata.Signature ??= new List <Digest>();
                                foreach (JsonProperty digest in digests)
                                {
                                    metadata.Signature.Add(new Digest()
                                    {
                                        Algorithm = digest.Name,
                                        Signature = digest.Value.ToString()
                                    });
                                }
                            }

                            // TODO: Want to figure out how to store info for .whl files as well.
                            if (OssUtilities.GetJSONPropertyStringIfExists(releaseFile, "packagetype") == "sdist")
                            {
                                // downloads
                                if (OssUtilities.GetJSONPropertyIfExists(releaseFile, "downloads")?.GetInt64() is long downloads &&
                                    downloads != -1)
                                {
                                    metadata.Downloads ??= new Downloads()
                                    {
                                        Overall = downloads
                                    };
                                }

                                metadata.Size               = OssUtilities.GetJSONPropertyIfExists(releaseFile, "size")?.GetInt64();
                                metadata.Active             = !OssUtilities.GetJSONPropertyIfExists(releaseFile, "yanked")?.GetBoolean();
                                metadata.VersionUri         = $"{ENV_PYPI_ENDPOINT}/project/{purl.Name}/{purl.Version}";
                                metadata.VersionDownloadUri = OssUtilities.GetJSONPropertyStringIfExists(releaseFile, "url");

                                string?uploadTime = OssUtilities.GetJSONPropertyStringIfExists(releaseFile, "upload_time");
                                if (uploadTime != null)
                                {
                                    metadata.UploadTime = DateTime.Parse(uploadTime);
                                }
                            }
                        }
                    }
                }
            }

            return(metadata);
        }
예제 #2
0
        /// <inheritdoc />
        public override async Task <PackageMetadata?> GetPackageMetadataAsync(PackageURL purl, bool useCache = true)
        {
            PackageMetadata metadata = new();
            string?         content  = await GetMetadataAsync(purl, useCache);

            if (string.IsNullOrEmpty(content))
            {
                return(null);
            }

            // convert NPM package data to normalized form
            JsonDocument contentJSON = JsonDocument.Parse(content);
            JsonElement  root        = contentJSON.RootElement;

            metadata.Name        = root.GetProperty("name").GetString();
            metadata.Description = OssUtilities.GetJSONPropertyStringIfExists(root, "description");

            metadata.PackageManagerUri = ENV_NPM_ENDPOINT;
            metadata.Platform          = "NPM";
            metadata.Language          = "JavaScript";
            metadata.PackageUri        = $"{metadata.PackageManagerUri}/package/{metadata.Name}";
            metadata.ApiPackageUri     = $"{ENV_NPM_API_ENDPOINT}/{metadata.Name}";

            List <Version> versions      = GetVersions(contentJSON);
            Version?       latestVersion = GetLatestVersion(versions);

            if (purl.Version != null)
            {
                // find the version object from the collection
                metadata.PackageVersion = purl.Version;
            }
            else
            {
                metadata.PackageVersion = latestVersion is null ? purl.Version : latestVersion?.ToString();
            }

            // if we found any version at all, get the information
            if (metadata.PackageVersion != null)
            {
                Version     versionToGet   = new(metadata.PackageVersion);
                JsonElement?versionElement = GetVersionElement(contentJSON, versionToGet);

                if (root.TryGetProperty("time", out JsonElement time))
                {
                    string?uploadTime = OssUtilities.GetJSONPropertyStringIfExists(time, metadata.PackageVersion);
                    if (uploadTime != null)
                    {
                        metadata.UploadTime = DateTime.Parse(uploadTime);
                    }
                }

                if (versionElement != null)
                {
                    // redo the generic values to version specific values
                    metadata.PackageUri    = $"{ENV_NPM_ENDPOINT}/package/{metadata.Name}";
                    metadata.VersionUri    = $"{ENV_NPM_ENDPOINT}/package/{metadata.Name}/v/{metadata.PackageVersion}";
                    metadata.ApiVersionUri = $"{ENV_NPM_API_ENDPOINT}/{metadata.Name}/{metadata.PackageVersion}";

                    // prioritize the version level description
                    if (OssUtilities.GetJSONPropertyStringIfExists(versionElement, "description") is string description)
                    {
                        metadata.Description = description;
                    }

                    JsonElement?distElement = OssUtilities.GetJSONPropertyIfExists(versionElement, "dist");
                    if (OssUtilities.GetJSONPropertyIfExists(distElement, "tarball") is JsonElement tarballElement)
                    {
                        metadata.VersionDownloadUri = tarballElement.ToString().IsBlank() ?
                                                      $"{ENV_NPM_API_ENDPOINT}/{metadata.Name}/-/{metadata.Name}-{metadata.PackageVersion}.tgz"
                            : tarballElement.ToString();
                    }

                    if (OssUtilities.GetJSONPropertyIfExists(distElement, "integrity") is JsonElement integrityElement &&
                        integrityElement.ToString() is string integrity &&
                        integrity.Split('-') is string[] pair &&
                        pair.Length == 2)
                    {
                        metadata.Signature ??= new List <Digest>();
                        metadata.Signature.Add(new Digest()
                        {
                            Algorithm = pair[0],
                            Signature = pair[1]
                        });
                    }

                    // size
                    if (OssUtilities.GetJSONPropertyIfExists(distElement, "unpackedSize") is JsonElement sizeElement &&
                        sizeElement.GetInt64() is long size)
                    {
                        metadata.Size = size;
                    }

                    // check for typescript
                    List <string>?devDependencies = OssUtilities.ConvertJSONToList(OssUtilities.GetJSONPropertyIfExists(versionElement, "devDependencies"));
                    if (devDependencies is not null && devDependencies.Count > 0 && devDependencies.Any(stringToCheck => stringToCheck.Contains("\"typescript\":")))
                    {
                        metadata.Language = "TypeScript";
                    }

                    // homepage
                    if (OssUtilities.GetJSONPropertyStringIfExists(versionElement, "homepage") is string homepage &&
                        !string.IsNullOrWhiteSpace(homepage))
                    {
                        metadata.Homepage = homepage;
                    }

                    // commit id
                    if (OssUtilities.GetJSONPropertyStringIfExists(versionElement, "gitHead") is string gitHead &&
                        !string.IsNullOrWhiteSpace(gitHead))
                    {
                        metadata.CommitId = gitHead;
                    }

                    // install scripts
                    List <string>?scripts = OssUtilities.ConvertJSONToList(OssUtilities.GetJSONPropertyIfExists(versionElement, "scripts"));
                    if (scripts is not null && scripts.Count > 0)
                    {
                        metadata.Scripts ??= new List <Command>();
                        scripts.ForEach((element) => metadata.Scripts.Add(new Command {
                            CommandLine = element
                        }));
                    }

                    // dependencies
                    List <string>?dependencies = OssUtilities.ConvertJSONToList(OssUtilities.GetJSONPropertyIfExists(versionElement, "dependencies"));
                    if (dependencies is not null && dependencies.Count > 0)
                    {
                        metadata.Dependencies ??= new List <Dependency>();
                        dependencies.ForEach((dependency) => metadata.Dependencies.Add(new Dependency()
                        {
                            Package = dependency
                        }));
                    }

                    // author(s)
                    JsonElement?authorElement = OssUtilities.GetJSONPropertyIfExists(versionElement, "_npmUser");
                    if (authorElement is not null)
                    {
                        User author = new()
                        {
                            Name  = OssUtilities.GetJSONPropertyStringIfExists(authorElement, "name"),
                            Email = OssUtilities.GetJSONPropertyStringIfExists(authorElement, "email"),
                            Url   = OssUtilities.GetJSONPropertyStringIfExists(authorElement, "url")
                        };

                        metadata.Authors ??= new List <User>();
                        metadata.Authors.Add(author);
                    }

                    // maintainers
                    JsonElement?maintainersElement = OssUtilities.GetJSONPropertyIfExists(versionElement, "maintainers");
                    if (maintainersElement?.EnumerateArray() is JsonElement.ArrayEnumerator maintainerEnumerator)
                    {
                        metadata.Maintainers ??= new List <User>();
                        maintainerEnumerator.ToList().ForEach((element) =>
                        {
                            metadata.Maintainers.Add(
                                new User
                            {
                                Name  = OssUtilities.GetJSONPropertyStringIfExists(element, "name"),
                                Email = OssUtilities.GetJSONPropertyStringIfExists(element, "email"),
                                Url   = OssUtilities.GetJSONPropertyStringIfExists(element, "url")
                            });
                        });
                    }

                    // repository
                    Dictionary <PackageURL, double> repoMappings = await SearchRepoUrlsInPackageMetadata(purl, content);

                    foreach (KeyValuePair <PackageURL, double> repoMapping in repoMappings)
                    {
                        Repository repository = new()
                        {
                            Rank = repoMapping.Value,
                            Type = repoMapping.Key.Type
                        };
                        await repository.ExtractRepositoryMetadata(repoMapping.Key);

                        metadata.Repository ??= new List <Repository>();
                        metadata.Repository.Add(repository);
                    }

                    // keywords
                    metadata.Keywords = OssUtilities.ConvertJSONToList(OssUtilities.GetJSONPropertyIfExists(versionElement, "keywords"));

                    // licenses
                    {
                        if (OssUtilities.GetJSONEnumerator(OssUtilities.GetJSONPropertyIfExists(versionElement, "licenses"))
                            is JsonElement.ArrayEnumerator enumeratorElement &&
                            enumeratorElement.ToList() is List <JsonElement> enumerator &&
                            enumerator.Any())
                        {
                            metadata.Licenses ??= new List <License>();
                            // TODO: Convert/append SPIX_ID values?
                            enumerator.ForEach((license) =>
                            {
                                metadata.Licenses.Add(new License()
                                {
                                    Name = OssUtilities.GetJSONPropertyStringIfExists(license, "type"),
                                    Url  = OssUtilities.GetJSONPropertyStringIfExists(license, "url")
                                });
                            });
                        }
                    }
                }
            }

            if (latestVersion is not null)
            {
                metadata.LatestPackageVersion = latestVersion.ToString();
            }

            return(metadata);
        }