Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/Bootstrap/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions src/Catalog/CatalogCommitItem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -40,6 +40,12 @@ public CatalogCommitItem(
Types = types;
TypeUris = typeUris;

Utils.AssertValidPackageId(packageIdentity.Id);
if (packageIdentity.Version is null)
{
throw new ArgumentNullException("The version in the package identity must not be null.");
}

IsPackageDetails = HasTypeUri(Schema.DataTypes.PackageDetails);
IsPackageDelete = HasTypeUri(Schema.DataTypes.PackageDelete);
}
Expand Down Expand Up @@ -123,4 +129,4 @@ private static IEnumerable<string> GetTypes(JObject commitItem)
}
}
}
}
}
11 changes: 9 additions & 2 deletions src/Catalog/CatalogIndexEntry.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -136,8 +136,15 @@ private void Initialize(
throw new ArgumentNullException(nameof(packageIdentity));
}

if (packageIdentity.Version is null)
{
throw new ArgumentNullException("The ID and version of the package identity must not be null.");
}

Utils.AssertValidPackageId(packageIdentity.Id);

Id = packageIdentity.Id;
Version = packageIdentity.Version;
}
}
}
}
34 changes: 9 additions & 25 deletions src/Catalog/Dnx/DnxCatalogCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using NuGet.Packaging;
using NuGet.Protocol.Catalog;
using NuGet.Services.Metadata.Catalog.Helpers;
using NuGet.Services.Metadata.Catalog.Persistence;
Expand Down Expand Up @@ -456,35 +457,18 @@ private async Task<string> GetNuspecAsync(

private static string GetNuspec(Stream stream, string id)
{
string name = $"{id}.nuspec";
using var archive = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true);
using var packageArchiveReader = new PackageArchiveReader(archive);

using (var archive = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true))
var actualId = packageArchiveReader.GetIdentity().Id;
if (!StringComparer.OrdinalIgnoreCase.Equals(id, actualId))
{
// first look for a nuspec file named as the package id
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.FullName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
using (TextReader reader = new StreamReader(entry.Open()))
{
return reader.ReadToEnd();
}
}
}
// failing that, just return the first file that appears to be a nuspec
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.FullName.EndsWith(".nuspec", StringComparison.InvariantCultureIgnoreCase))
{
using (TextReader reader = new StreamReader(entry.Open()))
{
return reader.ReadToEnd();
}
}
}
throw new InvalidOperationException($"The package ID in the catalog leaf '{id}' does not match the package ID in the .nupkg '{actualId}'.");
}

return null;
using var nuspecStream = packageArchiveReader.GetNuspec();
using var nuspecReader = new StreamReader(nuspecStream);
return nuspecReader.ReadToEnd();
}

private static Dictionary<string, string> GetTelemetryProperties(CatalogEntry catalogEntry)
Expand Down
8 changes: 7 additions & 1 deletion src/Catalog/FlatContainerPackagePathProvider.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -27,6 +27,9 @@ public string GetPackagePath(string id, string version)
throw new ArgumentNullException(nameof(version));
}

Utils.AssertValidPackageId(id);
Utils.AssertValidPackageVersion(version);

var idLowerCase = id.ToLowerInvariant();
var versionLowerCase = NuGetVersionUtility.NormalizeVersion(version).ToLowerInvariant();
var packageFileName = PackageUtility.GetPackageFileName(idLowerCase, versionLowerCase);
Expand All @@ -51,6 +54,9 @@ public string GetIconPath(string id, string version, bool normalize)
throw new ArgumentNullException(nameof(version));
}

Utils.AssertValidPackageId(id);
Utils.AssertValidPackageVersion(version);

var idLowerCase = id.ToLowerInvariant();

string versionLowerCase;
Expand Down
5 changes: 3 additions & 2 deletions src/Catalog/Helpers/NuGetVersionUtility.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using NuGet.Versioning;

namespace NuGet.Services.Metadata.Catalog.Helpers
Expand All @@ -12,7 +13,7 @@ public static string NormalizeVersion(string version)
NuGetVersion parsedVersion;
if (!NuGetVersion.TryParse(version, out parsedVersion))
{
return version;
throw new InvalidOperationException($"Invalid version found when normalized: '{version}'");
}

return parsedVersion.ToNormalizedString();
Expand Down
7 changes: 5 additions & 2 deletions src/Catalog/Helpers/PackageUtility.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand All @@ -19,7 +19,10 @@ public static string GetPackageFileName(string packageId, string packageVersion)
throw new ArgumentException(Strings.ArgumentMustNotBeNullOrEmpty, nameof(packageVersion));
}

Utils.AssertValidPackageId(packageId);
Utils.AssertValidPackageVersion(packageVersion);

return $"{packageId}.{packageVersion}.nupkg";
}
}
}
}
54 changes: 33 additions & 21 deletions src/Catalog/Helpers/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
using System.Xml;
using System.Xml.Linq;
using System.Xml.Xsl;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NuGet.Services.Metadata.Catalog.Helpers;
using NuGet.Packaging;
using NuGet.Versioning;

#if NETFRAMEWORK
using JsonLD.Core;
using Newtonsoft.Json;
using NuGet.Services.Metadata.Catalog.JsonLDIntegration;
using NuGet.Services.Metadata.Catalog.Helpers;
using VDS.RDF;
using VDS.RDF.Parsing;
#endif
Expand All @@ -28,16 +31,16 @@ namespace NuGet.Services.Metadata.Catalog
{
public static class Utils
{
#if NETFRAMEWORK
private const string XslTransformNuSpec = "xslt.nuspec.xslt";
private const string XslTransformNormalizeNuSpecNamespace = "xslt.normalizeNuspecNamespace.xslt";

private static readonly Lazy<XslCompiledTransform> XslTransformNuSpecCache = new Lazy<XslCompiledTransform>(() => SafeLoadXslTransform(XslTransformNuSpec));
private static readonly Lazy<XslCompiledTransform> XslTransformNormalizeNuSpecNamespaceCache = new Lazy<XslCompiledTransform>(() => SafeLoadXslTransform(XslTransformNormalizeNuSpecNamespace));
#endif

private static readonly char[] TagTrimChars = { ',', ' ', '\t', '|', ';' };

private static readonly char[] Slashes = { '/', '\\' };

public static string[] SplitTags(string original)
{
var fields = original
Expand All @@ -49,6 +52,22 @@ public static string[] SplitTags(string original)
return fields;
}

public static void AssertValidPackageId(string packageId)
{
if (packageId is null || !PackageIdValidator.IsValidPackageId(packageId))
{
throw new InvalidOperationException($"The package ID {(packageId is null ? "<null>" : $"'{packageId}'")} is not valid.");
}
}

public static void AssertValidPackageVersion(string packageVersion)
{
if (packageVersion is null || !NuGetVersion.TryParse(packageVersion, out _))
{
throw new InvalidOperationException($"The package version {(packageVersion is null ? "<null>" : $"'{packageVersion}'")} is not valid.");
}
}

public static Stream GetResourceStream(string resourceName)
{
if (string.IsNullOrEmpty(resourceName))
Expand Down Expand Up @@ -114,20 +133,10 @@ private static XslCompiledTransform SafeLoadXslTransform(string resourceName)
return transform;
}

public static XDocument GetNuspec(ZipArchive package)
public static XDocument GetNuspecXDocument(PackageArchiveReader packageArchiveReader)
{
if (package == null) { return null; }

foreach (ZipArchiveEntry part in package.Entries)
{
if (part.FullName.EndsWith(".nuspec") && part.FullName.IndexOfAny(Slashes) == -1)
{
XDocument nuspec = XDocument.Load(part.Open());
return nuspec;
}
}

return null;
using var nuspecStream = packageArchiveReader.GetNuspec();
return XDocument.Load(nuspecStream);
}

public static Uri Expand(JToken context, string term)
Expand Down Expand Up @@ -203,14 +212,17 @@ public static NupkgMetadata GetNupkgMetadata(Stream stream, string packageHash)
stream.Seek(0, SeekOrigin.Begin);

using (var package = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true))
using (var packageArchiveReader = new PackageArchiveReader(package))
{
var nuspec = GetNuspec(package);

if (nuspec == null)
var identity = packageArchiveReader.GetIdentity();
AssertValidPackageId(identity.Id);
if (identity.Version is null)
{
throw new InvalidDataException("Unable to find nuspec");
throw new InvalidOperationException("The version from the package identity must not be null.");
}

var nuspec = GetNuspecXDocument(packageArchiveReader);

var entries = GetEntries(package);

return new NupkgMetadata(nuspec, entries, packageSize, packageHash);
Expand Down
13 changes: 12 additions & 1 deletion src/Catalog/Helpers/XsltHelper.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Xml;
using System.Xml.XPath;
using NuGet.Packaging;
using NuGet.Services.Metadata.Catalog.Helpers;
using NuGet.Versioning;

Expand Down Expand Up @@ -40,6 +41,16 @@ public string LowerCase(string original)
return original.ToLowerInvariant();
}

public bool IsValidPackageId(string original)
{
return PackageIdValidator.IsValidPackageId(original);
}

public bool IsValidVersion(string original)
{
return NuGetVersion.TryParse(original, out _);
}

public string NormalizeVersion(string original)
{
return NuGetVersionUtility.NormalizeVersion(original);
Expand Down
8 changes: 1 addition & 7 deletions src/Catalog/Persistence/AzureStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -438,13 +438,7 @@ protected override async Task OnDeleteAsync(Uri resourceUri, DeleteRequestOption
public override Uri GetUri(string name)
{
var baseUri = RemoveQueryString(_directory.Uri);

if (baseUri.EndsWith("/"))
{
return new Uri($"{baseUri}{name}", UriKind.Absolute);
}

return new Uri($"{baseUri}/{name}", UriKind.Absolute);
return new Uri(baseUri.TrimEnd('/') + '/' + name.TrimStart('/'), UriKind.Absolute);
}

public override async Task<bool> AreSynchronized(Uri firstResourceUri, Uri secondResourceUri)
Expand Down
36 changes: 2 additions & 34 deletions src/Catalog/Persistence/Storage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public virtual Task<bool> UpdateCacheControlAsync(Uri resourceUri, string cacheC

public Uri ResolveUri(string relativeUri)
{
return new Uri(BaseAddress, relativeUri);
return Services.Storage.Storage.ResolveUri(BaseAddress, relativeUri);
}

/// <summary>
Expand All @@ -197,39 +197,7 @@ public virtual Task<bool> AreSynchronized(Uri firstResourceUri, Uri secondResour

public string GetName(Uri uri)
{
if (uri is null)
{
throw new ArgumentNullException(nameof(uri));
}

if (BaseAddress is null)
{
throw new InvalidOperationException("BaseAddress must be set.");
}

// The GetLeftPart method performs encoding under the hood, which could be problematic if it contains Unicode characters.
// It doesn't perform double encoding; the Uri object knows if it's already encoded and skips encoding it again.
// Decoding the base address to remove any encoded characters.
string address = Uri.UnescapeDataString(BaseAddress.GetLeftPart(UriPartial.Path)); // Remove potential query or SAS from the URI
if (!address.EndsWith("/"))
{
address += "/";
}

// Do the same with the above to get it decoded.
string fullPath = Uri.UnescapeDataString(uri.GetLeftPart(UriPartial.Path)); // Remove potential query or SAS from the URI

// handle mismatched scheme (http vs https)
int schemeLengthDifference = uri.Scheme.Length - BaseAddress.Scheme.Length;

string name = fullPath.Substring(address.Length + schemeLengthDifference);

if (name.Contains("#"))
{
name = name.Substring(0, name.IndexOf("#"));
}

return name;
return Services.Storage.Storage.GetName(BaseAddress, uri);
}

public virtual Uri GetUri(string name)
Expand Down
Loading
Loading