Пример #1
0
        /// <summary>
        /// Save the readme file from package stream. This method should throw if the package
        /// does not have an embedded readme file
        /// </summary>
        /// <param name="package">Package information.</param>
        /// <param name="packageStream">Package stream with .nupkg contents.</param>
        public async Task ExtractAndSaveReadmeFileAsync(Package package, Stream packageStream)
        {
            if (package == null)
            {
                throw new ArgumentNullException(nameof(package));
            }

            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            packageStream.Seek(0, SeekOrigin.Begin);
            using (var packageArchiveReader = new PackageArchiveReader(packageStream, leaveStreamOpen: true))
            {
                var packageMetadata = PackageMetadata.FromNuspecReader(packageArchiveReader.GetNuspecReader(), strict: true);
                if (string.IsNullOrWhiteSpace(packageMetadata.ReadmeFile))
                {
                    throw new InvalidOperationException("No readme file specified in the nuspec");
                }

                var filename        = FileNameHelper.GetZipEntryPath(packageMetadata.ReadmeFile);
                var ReadmeFileEntry = packageArchiveReader.GetEntry(filename); // throws on non-existent file
                using (var readmeFileStream = ReadmeFileEntry.Open())
                {
                    await SaveReadmeFileAsync(package, readmeFileStream);
                }
            }
        }
        public Task <Stream> DownloadValidationPackageFileAsync(Package package)
        {
            var fileName = FileNameHelper.BuildFileName(
                package,
                _metadata.FileSavePathTemplate,
                _metadata.FileExtension);

            return(_fileStorageService.GetFileAsync(_metadata.ValidationFolderName, fileName));
        }
Пример #3
0
        /// <summary>
        /// Deletes the package readme.md file from storage.
        /// </summary>
        /// <param name="package">The package associated with the readme.</param>
        public Task DeleteReadMeMdFileAsync(Package package)
        {
            if (package == null)
            {
                throw new ArgumentNullException(nameof(package));
            }

            var fileName = FileNameHelper.BuildFileName(package, ReadMeFilePathTemplateActive, ServicesConstants.MarkdownFileExtension);

            return(_fileStorageService.DeleteFileAsync(CoreConstants.Folders.PackageReadMesFolderName, fileName));
        }
        public Task <Uri> GetValidationPackageReadUriAsync(Package package, DateTimeOffset endOfAccess)
        {
            package = package ?? throw new ArgumentNullException(nameof(package));

            var fileName = FileNameHelper.BuildFileName(
                package,
                _metadata.FileSavePathTemplate,
                _metadata.FileExtension);

            return(_fileStorageService.GetFileReadUriAsync(_metadata.ValidationFolderName, fileName, endOfAccess));
        }
        public Task SavePackageFileAsync(Package package, Stream packageFile, bool overwrite)
        {
            if (packageFile == null)
            {
                throw new ArgumentNullException(nameof(packageFile));
            }

            var fileName = FileNameHelper.BuildFileName(package, _metadata.FileSavePathTemplate, _metadata.FileExtension);

            return(_fileStorageService.SaveFileAsync(_metadata.FileFolderName, fileName, packageFile, overwrite));
        }
Пример #6
0
        /// <summary>
        /// Saves the package readme.md file to storage.
        /// </summary>
        /// <param name="package">The package associated with the readme.</param>
        /// <param name="readMeMd">Markdown content.</param>
        public async Task SaveReadMeMdFileAsync(Package package, string readMeMd)
        {
            if (string.IsNullOrWhiteSpace(readMeMd))
            {
                throw new ArgumentNullException(nameof(readMeMd));
            }

            var fileName = FileNameHelper.BuildFileName(package, ReadMeFilePathTemplateActive, ServicesConstants.MarkdownFileExtension);

            using (var readMeMdStream = new MemoryStream(Encoding.UTF8.GetBytes(readMeMd)))
            {
                await _fileStorageService.SaveFileAsync(CoreConstants.Folders.PackageReadMesFolderName, fileName, readMeMdStream, overwrite : true);
            }
        }
        public Task DeleteValidationPackageFileAsync(string id, string version)
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }

            var normalizedVersion = NuGetVersionFormatter.Normalize(version);
            var fileName          = FileNameHelper.BuildFileName(
                id,
                normalizedVersion,
                _metadata.FileSavePathTemplate,
                _metadata.FileExtension);

            return(_fileStorageService.DeleteFileAsync(_metadata.ValidationFolderName, fileName));
        }
        /// <summary>
        /// Saves the package readme.md file to storage. This method should throw if the package
        /// does not have an embedded readme file
        /// </summary>
        /// <param name="package">The package associated with the readme.</param>
        /// <param name="readmeFile">The content of readme file.</param>
        public Task SaveReadmeFileAsync(Package package, Stream readmeFile)
        {
            if (package == null)
            {
                throw new ArgumentNullException(nameof(package));
            }

            if (readmeFile == null)
            {
                throw new ArgumentNullException(nameof(readmeFile));
            }

            if (package.EmbeddedReadmeType == EmbeddedReadmeFileType.Absent)
            {
                throw new ArgumentException("Package must have an embedded readme", nameof(package));
            }

            var fileName = FileNameHelper.BuildFileName(package, ReadMeFilePathTemplateActive, ServicesConstants.MarkdownFileExtension);

            return(_fileStorageService.SaveFileAsync(CoreConstants.Folders.PackageReadMesFolderName, fileName, readmeFile, overwrite: true));
        }
Пример #9
0
        /// <summary>
        /// Downloads the readme.md from storage.
        /// </summary>
        /// <param name="package">The package associated with the readme.</param>
        public async Task <string> DownloadReadMeMdFileAsync(Package package)
        {
            if (package == null)
            {
                throw new ArgumentNullException(nameof(package));
            }

            var fileName = FileNameHelper.BuildFileName(package, ReadMeFilePathTemplateActive, ServicesConstants.MarkdownFileExtension);

            using (var readMeMdStream = await _fileStorageService.GetFileAsync(CoreConstants.Folders.PackageReadMesFolderName, fileName))
            {
                // Note that fileStorageService implementations return null if not found.
                if (readMeMdStream != null)
                {
                    using (var readMeMdReader = new StreamReader(readMeMdStream))
                    {
                        return(await readMeMdReader.ReadToEndAsync());
                    }
                }
            }

            return(null);
        }
Пример #10
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);
        }
Пример #11
0
        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(string.Format(Strings.UploadPackage_NodeContainsChildren, LicenseNodeName)));
                }

                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);

            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
                if (!FileExists(nuGetPackage, licenseFilename))
                {
                    return(PackageValidationResult.Invalid(
                               string.Format(
                                   Strings.UploadPackage_FileDoesNotExist,
                                   Strings.UploadPackage_LicenseFileType,
                                   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_FileTooLong,
                                   Strings.UploadPackage_LicenseFileType,
                                   MaxAllowedLicenseLengthForUploading.ToUserFriendlyBytesLabel())));
                }

                if (!await IsStreamLengthMatchesReportedAsync(nuGetPackage, licenseFilename, 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);
        }
Пример #12
0
 private string BuildReadmeFileName(string id, string version)
 => FileNameHelper.BuildFileName(id, version, ReadmePathTemplate, string.Empty);
        public Task <ActionResult> CreateDownloadSymbolPackageActionResultAsync(Uri requestUrl, string id, string version)
        {
            var fileName = FileNameHelper.BuildFileName(id, version, CoreConstants.PackageFileSavePathTemplate, CoreConstants.NuGetSymbolPackageFileExtension);

            return(_fileStorageService.CreateDownloadFileActionResultAsync(requestUrl, CoreConstants.Folders.SymbolPackagesFolderName, fileName));
        }
Пример #14
0
 private string BuildReadmeFileName(Package package)
 => FileNameHelper.BuildFileName(package, ReadmePathTemplate, string.Empty);
 private string BuildLicenseFileName(Package package)
 => FileNameHelper.BuildFileName(package, LicensePathTemplate, string.Empty);
        public Task <bool> DoesPackageFileExistAsync(Package package)
        {
            var fileName = FileNameHelper.BuildFileName(package, _metadata.FileSavePathTemplate, _metadata.FileExtension);

            return(_fileStorageService.FileExistsAsync(_metadata.FileFolderName, fileName));
        }
        public Task <Uri> GetPackageReadUriAsync(Package package)
        {
            var fileName = FileNameHelper.BuildFileName(package, _metadata.FileSavePathTemplate, _metadata.FileExtension);

            return(_fileStorageService.GetFileReadUriAsync(_metadata.FileFolderName, fileName, endOfAccess: null));
        }
        private async Task <PackageValidationResult> CheckReadmeMetadataAsync(PackageArchiveReader nuGetPackage, User user)
        {
            var nuspecReader  = GetNuspecReader(nuGetPackage);
            var readmeElement = nuspecReader.ReadmeElement;

            if (readmeElement == null)
            {
                return(null);
            }

            var embeddedReadmeEnabled = _featureFlagService.AreEmbeddedReadmesEnabled(user);

            if (!embeddedReadmeEnabled)
            {
                return(PackageValidationResult.Invalid(Strings.UploadPackage_EmbeddedReadmeNotAccepted));
            }

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

            var readmeFilePath = FileNameHelper.GetZipEntryPath(readmeElement.Value);

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

            var readmeFileExtension = Path.GetExtension(readmeFilePath);

            if (!AllowedReadmeFileExtensions.Contains(readmeFileExtension, StringComparer.OrdinalIgnoreCase))
            {
                var result = PackageValidationResult.Invalid(
                    string.Format(
                        Strings.UploadPackage_InvalidReadmeFileExtension,
                        readmeFileExtension,
                        string.Join(", ", AllowedReadmeFileExtensions.Where(x => x != string.Empty).Select(extension => $"'{extension}'"))));
                return(result);
            }

            var readmeFileEntry = nuGetPackage.GetEntry(readmeFilePath);

            if (readmeFileEntry.Length > MaxAllowedReadmeLengthForUploading)
            {
                return(PackageValidationResult.Invalid(
                           string.Format(
                               Strings.UploadPackage_FileTooLong,
                               Strings.UploadPackage_ReadmeFileType,
                               MaxAllowedReadmeLengthForUploading.ToUserFriendlyBytesLabel())));
            }

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

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

            return(null);
        }
 private string BuildLicenseFileName(string id, string version)
 => FileNameHelper.BuildFileName(id, version, LicensePathTemplate, string.Empty);