Exemplo n.º 1
0
        private async Task <CSTRepository?> FetchGithubRepositoryMetadata(PackageURL purl)
        {
            try
            {
                GitHubClient github       = new(new ProductHeaderValue("OSSGadget"));
                GHRepository ghRepository = await github.Repository.Get(purl.Namespace, purl.Name);

                if (ghRepository is null)
                {
                    return(null);
                }
                Archived          = ghRepository.Archived;
                CreatedAt         = ghRepository.CreatedAt;
                UpdatedAt         = ghRepository.UpdatedAt;
                Description       = OssUtilities.GetMaxClippedLength(ghRepository.Description);
                IsFork            = ghRepository.Fork;
                Forks             = ghRepository.ForksCount;
                Homepage          = OssUtilities.GetMaxClippedLength(ghRepository.Homepage);
                Id                = ghRepository.Id;
                Language          = OssUtilities.GetMaxClippedLength(ghRepository.Language);
                Name              = ghRepository.Name;
                OpenIssuesCount   = ghRepository.OpenIssuesCount;
                Parent            = ghRepository.Parent?.Url;
                PushedAt          = ghRepository.PushedAt;
                Size              = ghRepository.Size;
                FollowersCount    = ghRepository.StargazersCount;
                Uri               = OssUtilities.GetMaxClippedLength(ghRepository.Url);
                StakeholdersCount = ghRepository.WatchersCount;

                if (ghRepository.License is not null)
                {
                    Licenses ??= new List <Model.License>();
                    Licenses.Add(new Model.License()
                    {
                        Name    = ghRepository.License.Name,
                        Url     = ghRepository.License.Url,
                        SPIX_ID = ghRepository.License.SpdxId
                    });
                }

                Owner ??= new Model.User()
                {
                    Id     = ghRepository.Owner.Id,
                    Name   = ghRepository.Owner.Name,
                    Email  = ghRepository.Owner.Email,
                    Url    = ghRepository.Owner.Url,
                    Active = !ghRepository.Owner.Suspended
                };
            }
            catch (Exception ex)
            {
                Logger.Debug($"Exception occurred while retrieving repository data: {ex}");
            }
            return(this);
        }
Exemplo n.º 2
0
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        protected async Task <Dictionary <PackageURL, double> > SearchRepoUrlsInPackageMetadata(PackageURL purl,
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
                                                                                                JsonDocument contentJSON)
        {
            Dictionary <PackageURL, double>?mapping = new();

            if (purl.Name is string purlName && (purlName.StartsWith('_') || npm_internal_modules.Contains(purlName)))
            {
                // url = 'https://github.com/nodejs/node/tree/master/lib' + package.name,

                mapping.Add(new PackageURL(purl.Type, purl.Namespace, purl.Name,
                                           null, null, "node/tree/master/lib"), 1.0F);
                return(mapping);
            }

            // if a version is provided, search that JSONElement, otherwise, just search the latest
            // version, which is more likely best maintained
            // TODO: If the latest version JSONElement doesnt have the repo infor, should we search all elements
            // on that chance that one of them might have it?
            JsonElement?versionJSON = string.IsNullOrEmpty(purl?.Version) ? GetLatestVersionElement(contentJSON) :
                                      GetVersionElement(contentJSON, new Version(purl.Version));

            if (versionJSON is JsonElement notNullVersionJSON)
            {
                try
                {
                    if (!notNullVersionJSON.TryGetProperty("repository", out JsonElement repository))
                    {
                        return(mapping);
                    }
                    if (repository.ValueKind == JsonValueKind.Object)
                    {
                        string?repoType = OssUtilities.GetJSONPropertyStringIfExists(repository, "type")?.ToLower();
                        string?repoURL  = OssUtilities.GetJSONPropertyStringIfExists(repository, "url");

                        // right now we deal with only github repos
                        if (repoType == "git" && repoURL is not null)
                        {
                            PackageURL gitPURL = GitHubProjectManager.ParseUri(new Uri(repoURL));
                            // we got a repository value the author specified in the metadata - so no
                            // further processing needed
                            mapping.Add(gitPURL, 1.0F);
                            return(mapping);
                        }
                    }
                }
                catch (KeyNotFoundException) { /* continue onwards */ }
                catch (UriFormatException) { /* the uri specified in the metadata invalid */ }
            }

            return(mapping);
        }
Exemplo n.º 3
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);
        }
Exemplo n.º 4
0
        /// <summary>
        ///     Download one Composer (PHP) package and extract it to the target directory.
        /// </summary>
        /// <param name="purl"> Package URL of the package to download. </param>
        /// <returns> n/a </returns>
        public override async Task <IEnumerable <string> > DownloadVersionAsync(PackageURL purl, bool doExtract, bool cached = false)
        {
            Logger.Trace("DownloadVersion {0}", purl?.ToString());

            string?       packageNamespace = purl?.Namespace;
            string?       packageName      = purl?.Name;
            string?       packageVersion   = purl?.Version;
            List <string> downloadedPaths  = new();

            if (string.IsNullOrWhiteSpace(packageNamespace) || string.IsNullOrWhiteSpace(packageName) ||
                string.IsNullOrWhiteSpace(packageVersion))
            {
                Logger.Debug("Unable to download [{0} {1} {2}]. All three must be defined.", packageNamespace, packageName, packageVersion);
                return(downloadedPaths);
            }

            try
            {
                HttpClient httpClient             = CreateHttpClient();
                System.Text.Json.JsonDocument doc = await GetJsonCache(httpClient, $"{ENV_COMPOSER_ENDPOINT}/p/{packageNamespace}/{packageName}.json");

                foreach (System.Text.Json.JsonProperty topObject in doc.RootElement.GetProperty("packages").EnumerateObject())
                {
                    foreach (System.Text.Json.JsonProperty versionObject in topObject.Value.EnumerateObject())
                    {
                        if (versionObject.Name != packageVersion)
                        {
                            continue;
                        }
                        string?url = versionObject.Value.GetProperty("dist").GetProperty("url").GetString();
                        System.Net.Http.HttpResponseMessage?result = await httpClient.GetAsync(url);

                        result.EnsureSuccessStatusCode();
                        Logger.Debug("Downloading {0}...", purl);

                        string fsNamespace = OssUtilities.NormalizeStringForFileSystem(packageNamespace);
                        string fsName      = OssUtilities.NormalizeStringForFileSystem(packageName);
                        string fsVersion   = OssUtilities.NormalizeStringForFileSystem(packageVersion);

                        string targetName     = $"composer-{fsNamespace}-{fsName}@{fsVersion}";
                        string extractionPath = Path.Combine(TopLevelExtractionDirectory, targetName);
                        if (doExtract && Directory.Exists(extractionPath) && cached == true)
                        {
                            downloadedPaths.Add(extractionPath);
                            return(downloadedPaths);
                        }
                        if (doExtract)
                        {
                            downloadedPaths.Add(await ArchiveHelper.ExtractArchiveAsync(TopLevelExtractionDirectory, targetName, await result.Content.ReadAsStreamAsync(), cached));
                        }
                        else
                        {
                            extractionPath += ".zip";
                            await File.WriteAllBytesAsync(extractionPath, await result.Content.ReadAsByteArrayAsync());

                            downloadedPaths.Add(extractionPath);
                        }
                    }
                }
                if (downloadedPaths.Count == 0)
                {
                    Logger.Debug("Unable to find version {0} to download.", packageVersion);
                }
            }
            catch (Exception ex)
            {
                Logger.Debug(ex, "Error downloading Composer package: {0}", ex.Message);
            }
            return(downloadedPaths);
        }
Exemplo n.º 5
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);
        }