/// <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)); }
/// <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)); }
/// <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)); }
/// <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); }
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(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); }
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)); }
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);