Exemple #1
0
        private async Task <PackageValidationResult> CheckIconMetadataAsync(PackageArchiveReader nuGetPackage, List <IValidationMessage> warnings, User user)
        {
            var nuspecReader         = GetNuspecReader(nuGetPackage);
            var iconElement          = nuspecReader.IconElement;
            var embeddedIconsEnabled = _featureFlagService.AreEmbeddedIconsEnabled(user);

            if (iconElement == null)
            {
                if (embeddedIconsEnabled && !string.IsNullOrWhiteSpace(nuspecReader.GetIconUrl()))
                {
                    warnings.Add(new IconUrlDeprecationValidationMessage());
                }
                return(null);
            }

            if (!embeddedIconsEnabled)
            {
                return(PackageValidationResult.Invalid(Strings.UploadPackage_EmbeddedIconNotAccepted));
            }

            if (HasChildElements(iconElement))
            {
                return(PackageValidationResult.Invalid(string.Format(Strings.UploadPackage_NodeContainsChildren, IconNodeName)));
            }

            var iconFilePath = FileNameHelper.GetZipEntryPath(iconElement.Value);

            if (!FileExists(nuGetPackage, iconFilePath))
            {
                return(PackageValidationResult.Invalid(
                           string.Format(
                               Strings.UploadPackage_FileDoesNotExist,
                               Strings.UploadPackage_IconFileType,
                               iconFilePath)));
            }

            var iconFileExtension = Path.GetExtension(iconFilePath);

            if (!AllowedIconFileExtensions.Contains(iconFileExtension, StringComparer.OrdinalIgnoreCase))
            {
                return(PackageValidationResult.Invalid(
                           string.Format(
                               Strings.UploadPackage_InvalidIconFileExtension,
                               iconFileExtension,
                               string.Join(", ", AllowedIconFileExtensions.Where(x => x != string.Empty).Select(extension => $"'{extension}'")))));
            }

            var iconFileEntry = nuGetPackage.GetEntry(iconFilePath);

            if (iconFileEntry.Length > MaxAllowedIconLengthForUploading)
            {
                return(PackageValidationResult.Invalid(
                           string.Format(
                               Strings.UploadPackage_FileTooLong,
                               Strings.UploadPackage_IconFileType,
                               MaxAllowedLicenseLengthForUploading.ToUserFriendlyBytesLabel())));
            }

            if (!await IsStreamLengthMatchesReportedAsync(nuGetPackage, iconFilePath, iconFileEntry.Length))
            {
                return(PackageValidationResult.Invalid(Strings.UploadPackage_CorruptNupkg));
            }

            bool isJpg = await IsJpegAsync(nuGetPackage, iconFilePath);

            bool isPng = await IsPngAsync(nuGetPackage, iconFilePath);

            if (!isPng && !isJpg)
            {
                return(PackageValidationResult.Invalid(Strings.UploadPackage_UnsupportedIconImageFormat));
            }

            return(null);
        }
        private async Task <PackageValidationResult> CheckLicenseMetadataAsync(PackageArchiveReader nuGetPackage, List <IValidationMessage> warnings, User user)
        {
            var nuspecReader = GetNuspecReader(nuGetPackage);

            var licenseElement = nuspecReader.LicenseElement;

            if (licenseElement != null)
            {
                if (licenseElement.Value.Length > MaxAllowedLicenseNodeValueLength)
                {
                    return(PackageValidationResult.Invalid(Strings.UploadPackage_LicenseNodeValueTooLong));
                }

                if (HasChildElements(licenseElement))
                {
                    return(PackageValidationResult.Invalid(Strings.UploadPackage_LicenseNodeContainsChildren));
                }

                var typeText = GetLicenseType(licenseElement);

                if (!AllowedLicenseTypes.Contains(typeText, StringComparer.OrdinalIgnoreCase))
                {
                    return(PackageValidationResult.Invalid(string.Format(Strings.UploadPackage_UnsupportedLicenseType, typeText)));
                }

                var versionText = GetLicenseVersion(licenseElement);

                if (versionText != null && AllowedLicenseVersion != versionText)
                {
                    return(PackageValidationResult.Invalid(
                               string.Format(
                                   Strings.UploadPackage_UnsupportedLicenseVersion,
                                   versionText)));
                }
            }

            var licenseUrl            = nuspecReader.GetLicenseUrl();
            var licenseMetadata       = nuspecReader.GetLicenseMetadata();
            var licenseDeprecationUrl = GetExpectedLicenseUrl(licenseMetadata);

            // TODO: move out when full blown validation is implemented https://github.com/nuget/nugetgallery/issues/7063
            if (nuspecReader.IconExists && !_featureFlagService.AreEmbeddedIconsEnabled(user))
            {
                return(PackageValidationResult.Invalid(Strings.UploadPackage_EmbeddedIconNotAccepted));
            }

            if (licenseMetadata == null)
            {
                if (string.IsNullOrWhiteSpace(licenseUrl))
                {
                    if (!_config.AllowLicenselessPackages)
                    {
                        return(PackageValidationResult.Invalid(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_MissingLicenseInformation)));
                    }
                    else
                    {
                        warnings.Add(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_LicenseShouldBeSpecified));
                    }
                }

                if (licenseDeprecationUrl == licenseUrl)
                {
                    return(PackageValidationResult.Invalid(Strings.UploadPackage_DeprecationUrlUsage));
                }

                if (!string.IsNullOrWhiteSpace(licenseUrl))
                {
                    if (_config.BlockLegacyLicenseUrl)
                    {
                        return(PackageValidationResult.Invalid(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_LegacyLicenseUrlNotAllowed)));
                    }
                    else
                    {
                        warnings.Add(new LicenseUrlDeprecationValidationMessage(Strings.UploadPackage_DeprecatingLicenseUrl));
                    }
                }

                // we will return here, so the code below would not need to check for licenseMetadata to be non-null over and over.
                return(null);
            }

            if (licenseMetadata.WarningsAndErrors != null && licenseMetadata.WarningsAndErrors.Any())
            {
                _telemetryService.TrackInvalidLicenseMetadata(licenseMetadata.License);
                return(PackageValidationResult.Invalid(
                           string.Format(
                               Strings.UploadPackage_InvalidLicenseMetadata,
                               string.Join(" ", licenseMetadata.WarningsAndErrors))));
            }

            if (licenseDeprecationUrl != licenseUrl)
            {
                if (IsMalformedDeprecationUrl(licenseUrl))
                {
                    return(PackageValidationResult.Invalid(new InvalidUrlEncodingForLicenseUrlValidationMessage()));
                }

                if (licenseMetadata.Type == LicenseType.File)
                {
                    return(PackageValidationResult.Invalid(
                               new InvalidLicenseUrlValidationMessage(
                                   string.Format(Strings.UploadPackage_DeprecationUrlRequiredForLicenseFiles, licenseDeprecationUrl))));
                }
                else if (licenseMetadata.Type == LicenseType.Expression)
                {
                    return(PackageValidationResult.Invalid(
                               new InvalidLicenseUrlValidationMessage(
                                   string.Format(Strings.UploadPackage_DeprecationUrlRequiredForLicenseExpressions, licenseDeprecationUrl))));
                }
            }

            if (licenseMetadata.Type == LicenseType.File)
            {
                // fix the path separator. Client enforces forward slashes in all file paths when packing
                var licenseFilename = FileNameHelper.GetZipEntryPath(licenseMetadata.License);
                if (licenseFilename != licenseMetadata.License)
                {
                    var packageIdentity = nuspecReader.GetIdentity();
                    _trace.Information($"Transformed license file name from `{licenseMetadata.License}` to `{licenseFilename}` for package {packageIdentity.Id} {packageIdentity.Version}");
                }

                // check if specified file is present in the package
                var fileList = new HashSet <string>(nuGetPackage.GetFiles());
                if (!fileList.Contains(licenseFilename))
                {
                    return(PackageValidationResult.Invalid(
                               string.Format(
                                   Strings.UploadPackage_LicenseFileDoesNotExist,
                                   licenseFilename)));
                }

                // check if specified file has allowed extension
                var licenseFileExtension = Path.GetExtension(licenseFilename);
                if (!AllowedLicenseFileExtensions.Contains(licenseFileExtension, StringComparer.OrdinalIgnoreCase))
                {
                    return(PackageValidationResult.Invalid(
                               string.Format(
                                   Strings.UploadPackage_InvalidLicenseFileExtension,
                                   licenseFileExtension,
                                   string.Join(", ", AllowedLicenseFileExtensions.Where(x => x != string.Empty).Select(extension => $"'{extension}'")))));
                }

                var licenseFileEntry = nuGetPackage.GetEntry(licenseFilename);
                if (licenseFileEntry.Length > MaxAllowedLicenseLengthForUploading)
                {
                    return(PackageValidationResult.Invalid(
                               string.Format(
                                   Strings.UploadPackage_LicenseFileTooLong,
                                   MaxAllowedLicenseLengthForUploading.ToUserFriendlyBytesLabel())));
                }

                using (var licenseFileStream = nuGetPackage.GetStream(licenseFilename))
                {
                    if (!await IsStreamLengthMatchesReportedAsync(licenseFileStream, licenseFileEntry.Length))
                    {
                        return(PackageValidationResult.Invalid(Strings.UploadPackage_CorruptNupkg));
                    }
                }

                // zip streams do not support seeking, so we'll have to reopen them
                using (var licenseFileStream = nuGetPackage.GetStream(licenseFilename))
                {
                    // check if specified file is a text file
                    if (!await TextHelper.LooksLikeUtf8TextStreamAsync(licenseFileStream))
                    {
                        return(PackageValidationResult.Invalid(Strings.UploadPackage_LicenseMustBePlainText));
                    }
                }
            }

            if (licenseMetadata.Type == LicenseType.Expression)
            {
                if (licenseMetadata.LicenseExpression == null)
                {
                    throw new InvalidOperationException($"Unexpected value of {nameof(licenseMetadata.LicenseExpression)} property");
                }

                var licenseList        = GetLicenseList(licenseMetadata.LicenseExpression);
                var unapprovedLicenses = licenseList.Where(license => !license.IsOsiApproved && !license.IsFsfLibre).ToList();
                if (unapprovedLicenses.Any())
                {
                    _telemetryService.TrackNonFsfOsiLicenseUse(licenseMetadata.License);
                    return(PackageValidationResult.Invalid(
                               string.Format(
                                   Strings.UploadPackage_NonFsfOrOsiLicense, string.Join(", ", unapprovedLicenses.Select(l => l.LicenseID)))));
                }
            }

            return(null);
        }