Skip to content

Commit 3195321

Browse files
authored
[Repair Item] Fix unicode character on nuspec. (#10157)
* fix unicode characters * update test package * removed non needed file * gitignore update for testdata nupkg * added normalized warning and test. * removed non needed nupkg updated test for valid
1 parent 046da96 commit 3195321

8 files changed

Lines changed: 128 additions & 12 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ PublishScripts/
194194

195195
# NuGet Packages
196196
*.nupkg
197+
!**/TestData/*.nupkg
197198
# NuGet Symbol Packages
198199
*.snupkg
199200
# The packages folder can be ignored because of Package Restore

src/NuGetGallery/Services/PackageMetadataValidationService.cs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
55
using System.Collections.Generic;
66
using System.IO;
77
using System.Linq;
8+
using System.Text;
89
using System.Threading;
910
using System.Threading.Tasks;
1011
using System.Xml.Linq;
@@ -99,7 +100,7 @@ public async Task<PackageValidationResult> ValidateMetadataBeforeUploadAsync(
99100
{
100101
var warnings = new List<IValidationMessage>();
101102

102-
var result = await CheckPackageEntryCountAsync(nuGetPackage, warnings);
103+
PackageValidationResult result = await CheckPackageEntryCountAsync(nuGetPackage, warnings);
103104

104105
if (result != null)
105106
{
@@ -112,7 +113,7 @@ public async Task<PackageValidationResult> ValidateMetadataBeforeUploadAsync(
112113
{
113114
return result;
114115
}
115-
116+
116117
var nuspecFileEntry = nuGetPackage.GetEntry(nuGetPackage.GetNuspecFile());
117118
using (var nuspecFileStream = await nuGetPackage.GetNuspecAsync(CancellationToken.None))
118119
{
@@ -122,6 +123,13 @@ public async Task<PackageValidationResult> ValidateMetadataBeforeUploadAsync(
122123
}
123124
}
124125

126+
result = CheckNuspecNormalized(nuGetPackage, warnings);
127+
128+
if (result != null)
129+
{
130+
return result;
131+
}
132+
125133
result = await CheckForUnsignedPushAfterAuthorSignedAsync(
126134
nuGetPackage,
127135
warnings);
@@ -161,6 +169,26 @@ public async Task<PackageValidationResult> ValidateMetadataBeforeUploadAsync(
161169
return PackageValidationResult.AcceptedWithWarnings(warnings);
162170
}
163171

172+
private PackageValidationResult CheckNuspecNormalized(PackageArchiveReader nuGetPackage, List<IValidationMessage> warnings)
173+
{
174+
try
175+
{
176+
UserContentEnabledNuspecReader nuspecReader = GetNuspecReader(nuGetPackage);
177+
string nuspec = nuspecReader.Xml.ToStringSafe();
178+
179+
if (!nuspec.IsNormalized(NormalizationForm.FormC))
180+
{
181+
warnings.Add(new PlainTextOnlyValidationMessage(Strings.UploadPackage_NuspecIsNotNormalized));
182+
}
183+
}
184+
catch (Exception)
185+
{
186+
return PackageValidationResult.Invalid(Strings.UploadPackage_NuspecContainsInvalidUnicodeCharacters);
187+
}
188+
189+
return null;
190+
}
191+
164192
private async Task<PackageValidationResult> CheckLicenseMetadataAsync(PackageArchiveReader nuGetPackage, List<IValidationMessage> warnings, User user)
165193
{
166194
var nuspecReader = GetNuspecReader(nuGetPackage);
@@ -873,4 +901,4 @@ public async Task<PackageValidationResult> ValidateSignatureFilePresenceAsync(
873901
return null;
874902
}
875903
}
876-
}
904+
}

src/NuGetGallery/Strings.Designer.cs

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/NuGetGallery/Strings.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,4 +1263,10 @@ The {1} Team</value>
12631263
<data name="FrameworkFilters_Tooltip" xml:space="preserve">
12641264
<value>Filters packages based on the target frameworks they are compatible with.</value>
12651265
</data>
1266+
<data name="UploadPackage_NuspecContainsInvalidUnicodeCharacters" xml:space="preserve">
1267+
<value>The package nuspec file contains invalid unicode characters.</value>
1268+
</data>
1269+
<data name="UploadPackage_NuspecIsNotNormalized" xml:space="preserve">
1270+
<value>The package nuspec file is not compliant with the normalization form C (NFC).</value>
1271+
</data>
12661272
</root>

tests/NuGetGallery.Core.Facts/TestUtils/TestPackage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,4 +340,4 @@ public static MemoryStream CreateTestPackageStream(Action<ZipArchive> populatePa
340340
return packageStream;
341341
}
342342
}
343-
}
343+
}

tests/NuGetGallery.Facts/NuGetGallery.Facts.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFramework>net472</TargetFramework>
44
<RootNamespace>NuGetGallery</RootNamespace>
@@ -14,6 +14,7 @@
1414
<EmbeddedResource Include="TestData\PackageWithDoubleForwardSlash.1.0.0.nupkg" />
1515
<EmbeddedResource Include="TestData\PackageWithVeryLongZipFileEntry.1.0.0.nupkg" />
1616
<EmbeddedResource Include="TestData\Zip64Package.Corrupted.1.0.0.nupkg" />
17+
<EmbeddedResource Include="TestData\PackageWithInvalidUnicodeCharacters.1.0.0.nupkg" />
1718
</ItemGroup>
1819
<ItemGroup>
1920
<ProjectReference Include="..\..\src\NuGetGallery\NuGetGallery.csproj" />

tests/NuGetGallery.Facts/Services/PackageMetadataValidationServiceFacts.cs

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -361,6 +361,64 @@ public async Task WithNotTooManyPackageEntries_WhenRejectPackagesWithTooManyPack
361361
Assert.Empty(result.Warnings);
362362
}
363363

364+
[Fact]
365+
public async Task WithInvalidUnicodeCharactersInNuspec_ReturnsInvalidPackage()
366+
{
367+
// Arrange
368+
var package = TestDataResourceUtility.GetResourceBytes("PackageWithInvalidUnicodeCharacters.1.0.0.nupkg");
369+
var fakeFileStream = new MemoryStream(package);
370+
var reader = new PackageArchiveReader(fakeFileStream);
371+
372+
// Act
373+
PackageValidationResult result = await _target.ValidateMetadataBeforeUploadAsync(
374+
reader,
375+
PackageMetadata.FromNuspecReader(reader.GetNuspecReader(), strict: true),
376+
_currentUser);
377+
378+
// Assert
379+
Assert.Equal(PackageValidationResultType.Invalid, result.Type);
380+
Assert.Equal("The package nuspec file contains invalid unicode characters.", result.Message.PlainTextMessage);
381+
Assert.Empty(result.Warnings);
382+
}
383+
384+
[Fact]
385+
public async Task WithValidUnicodeCharactersInNuspec_ReturnsAcceptedPackage()
386+
{
387+
// Arrange
388+
var package = GeneratePackageWithUserContent(
389+
licenseUrl: GetLicenseExpressionDeprecationUrl("MIT"),
390+
licenseExpression: "MIT",
391+
releaseNotes: "Release notes");
392+
393+
// Act
394+
PackageValidationResult result = await _target.ValidateMetadataBeforeUploadAsync(
395+
package.Object,
396+
GetPackageMetadata(package),
397+
_currentUser);
398+
399+
// Assert
400+
Assert.Equal(PackageValidationResultType.Accepted, result.Type);
401+
Assert.Empty(result.Warnings);
402+
}
403+
404+
[Fact]
405+
public async Task WithNonNormalizeNuspec_ReturnsAcceptedPackageWithWarnings()
406+
{
407+
// Arrange
408+
var package = GeneratePackageWithUserContent(releaseNotes: "Non normalized character: e\u0301");
409+
410+
// Act
411+
PackageValidationResult result = await _target.ValidateMetadataBeforeUploadAsync(
412+
package.Object,
413+
GetPackageMetadata(package),
414+
_currentUser);
415+
416+
// Assert
417+
Assert.Equal(PackageValidationResultType.Accepted, result.Type);
418+
Assert.NotEmpty(result.Warnings);
419+
Assert.Equal("The package nuspec file is not compliant with the normalization form C (NFC).", result.Warnings[0].PlainTextMessage);
420+
}
421+
364422
[Theory]
365423
[InlineData("duplicatedFile.txt", "duplicatedFile.txt")]
366424
[InlineData("./temp/duplicatedFile.txt", "./temp/duplicatedFile.txt")]
@@ -448,10 +506,10 @@ public async Task HandlesMissingLicenseAccordingToSettings(bool allowLicenseless
448506
public async Task HandlesMissingLicenseAccordingToSettingsWhenDisplayUploadWarningV2Enabled(bool allowLicenselessPackages, bool expectedSuccess)
449507
{
450508
_nuGetPackage = GeneratePackageWithUserContent(
451-
licenseUrl: null,
452-
licenseExpression: null,
453-
licenseFilename: null,
454-
readmeFilename:"readme.md",
509+
licenseUrl: null,
510+
licenseExpression: null,
511+
licenseFilename: null,
512+
readmeFilename: "readme.md",
455513
readmeFileContents: "read me");
456514

457515
_config
@@ -2136,6 +2194,7 @@ protected static Mock<TestPackageReader> GeneratePackageWithUserContent(
21362194
string readmeFilename = null,
21372195
string readmeFileContents = null,
21382196
byte[] readmeFileBinaryContents = null,
2197+
string releaseNotes = null,
21392198
IReadOnlyList<string> entryNames = null)
21402199
{
21412200
var packageStream = GeneratePackageStream(
@@ -2155,6 +2214,7 @@ protected static Mock<TestPackageReader> GeneratePackageWithUserContent(
21552214
readmeFilename: readmeFilename,
21562215
readmeFileContents: readmeFileContents,
21572216
readmeFileBinaryContents: readmeFileBinaryContents,
2217+
releaseNotes: releaseNotes,
21582218
entryNames: entryNames);
21592219

21602220
return PackageServiceUtility.CreateNuGetPackage(packageStream);
@@ -2177,6 +2237,7 @@ protected static MemoryStream GeneratePackageStream(
21772237
string readmeFilename = null,
21782238
string readmeFileContents = null,
21792239
byte[] readmeFileBinaryContents = null,
2240+
string releaseNotes = null,
21802241
IReadOnlyList<string> entryNames = null)
21812242
{
21822243
return PackageServiceUtility.CreateNuGetPackageStream(
@@ -2195,6 +2256,7 @@ protected static MemoryStream GeneratePackageStream(
21952256
iconFileBinaryContents: iconFileBinaryContents,
21962257
readmeFilename: readmeFilename,
21972258
readmeFileContents: GetBinaryLicenseOrReadmeFileContents(readmeFileBinaryContents, readmeFileContents),
2259+
releaseNotes: releaseNotes,
21982260
entryNames: entryNames);
21992261
}
22002262

@@ -2214,4 +2276,4 @@ private static byte[] GetBinaryLicenseOrReadmeFileContents(byte[] binaryContents
22142276
}
22152277
}
22162278
}
2217-
}
2279+
}
Binary file not shown.

0 commit comments

Comments
 (0)