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
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.

#nullable disable

using System;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
Expand All @@ -11,10 +9,14 @@ namespace NuGet.Protocol
{
public class PackageVulnerabilityMetadata
{
/// <summary>
/// NULL_INC: The advisory URL for this vulnerability.
/// Guaranteed non-null by the protocol: https://learn.microsoft.com/en-us/nuget/api/registration-base-url-resource#vulnerabilities
/// </summary>
[JsonProperty(PropertyName = JsonProperties.AdvisoryUrl, ItemConverterType = typeof(SafeUriConverter))]
[JsonPropertyName(JsonProperties.AdvisoryUrl)]
[JsonInclude]
public Uri AdvisoryUrl { get; internal set; }
public Uri AdvisoryUrl { get; internal set; } = null!;

[JsonProperty(PropertyName = JsonProperties.Severity)]
[JsonPropertyName(JsonProperties.Severity)]
Expand All @@ -24,10 +26,11 @@ public class PackageVulnerabilityMetadata

public PackageVulnerabilityMetadata(Uri advisoryUrl, int severity)
{
AdvisoryUrl = advisoryUrl;
AdvisoryUrl = advisoryUrl ?? throw new ArgumentNullException(nameof(advisoryUrl));
Severity = severity;
}

// Parameterless constructor for JSON deserialization.
public PackageVulnerabilityMetadata()
{
}
Expand Down
4 changes: 1 addition & 3 deletions src/NuGet.Core/NuGet.Protocol/Model/RegistrationIndex.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.

#nullable disable

using System.Collections.Generic;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
Expand All @@ -16,6 +14,6 @@ internal class RegistrationIndex
{
[JsonProperty("items")]
[JsonPropertyName("items")]
public List<RegistrationPage> Items { get; set; }
public List<RegistrationPage>? Items { get; set; }
}
}
6 changes: 2 additions & 4 deletions src/NuGet.Core/NuGet.Protocol/Model/RegistrationLeafItem.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.

#nullable disable

using System;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
Expand All @@ -16,10 +14,10 @@ internal class RegistrationLeafItem
{
[JsonProperty("catalogEntry")]
[JsonPropertyName("catalogEntry")]
public PackageSearchMetadataRegistration CatalogEntry { get; set; }
public PackageSearchMetadataRegistration? CatalogEntry { get; set; }

[JsonProperty(PropertyName = JsonProperties.PackageContent)]
[JsonPropertyName(JsonProperties.PackageContent)]
public Uri PackageContent { get; set; }
public Uri? PackageContent { get; set; }
}
}
16 changes: 10 additions & 6 deletions src/NuGet.Core/NuGet.Protocol/Model/RegistrationPage.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.

#nullable disable

using System.Collections.Generic;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
Expand All @@ -16,9 +14,11 @@ namespace NuGet.Protocol.Model
/// </summary>
internal class RegistrationPage
{
// NULL_INC: Annotated as non-null per protocol spec (link above). JSON deserialization may leave these
// as null if the server sends malformed data, but existing code assumes non-null without checks.
[JsonProperty("@id")]
[JsonPropertyName("@id")]
public string Url { get; set; }
public string Url { get; set; } = null!;

/// <summary>
/// This property can be null when this model is used as an item in <see cref="RegistrationIndex.Items"/> when
Expand All @@ -27,14 +27,18 @@ internal class RegistrationPage
/// </summary>
[JsonProperty("items")]
[JsonPropertyName("items")]
public List<RegistrationLeafItem> Items { get; set; }
public List<RegistrationLeafItem>? Items { get; set; }

// NULL_INC: Annotated as non-null per protocol spec (link above). JSON deserialization may leave these
// as null if the server sends malformed data, but existing code assumes non-null without checks.
[JsonProperty("lower")]
[JsonPropertyName("lower")]
public string Lower { get; set; }
public string Lower { get; set; } = null!;

// NULL_INC: Annotated as non-null per protocol spec (link above). JSON deserialization may leave these
// as null if the server sends malformed data, but existing code assumes non-null without checks.
[JsonProperty("upper")]
[JsonPropertyName("upper")]
public string Upper { get; set; }
public string Upper { get; set; } = null!;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.

#nullable disable

using System;
using System.Globalization;
using System.Linq;
Expand All @@ -18,21 +16,21 @@ namespace NuGet.Protocol
{
public class RepositorySignatureResourceProvider : ResourceProvider
{
private readonly IEnvironmentVariableReader _environmentVariableReader;
private readonly IEnvironmentVariableReader? _environmentVariableReader;

public RepositorySignatureResourceProvider() : this(null) { }

internal RepositorySignatureResourceProvider(IEnvironmentVariableReader environmentVariableReader)
internal RepositorySignatureResourceProvider(IEnvironmentVariableReader? environmentVariableReader)
: base(typeof(RepositorySignatureResource),
nameof(RepositorySignatureResource),
NuGetResourceProviderPositions.Last)
{
_environmentVariableReader = environmentVariableReader;
}

public override async Task<Tuple<bool, INuGetResource>> TryCreate(SourceRepository source, CancellationToken token)
public override async Task<Tuple<bool, INuGetResource?>> TryCreate(SourceRepository source, CancellationToken token)
{
RepositorySignatureResource resource = null;
RepositorySignatureResource? resource = null;
var serviceIndex = await source.GetResourceAsync<ServiceIndexResourceV3>(token);
if (serviceIndex != null)
{
Expand All @@ -44,10 +42,10 @@ public override async Task<Tuple<bool, INuGetResource>> TryCreate(SourceReposito
}
}

return new Tuple<bool, INuGetResource>(resource != null, resource);
return new Tuple<bool, INuGetResource?>(resource != null, resource);
}

private async Task<RepositorySignatureResource> GetRepositorySignatureResourceAsync(
private async Task<RepositorySignatureResource?> GetRepositorySignatureResourceAsync(
SourceRepository source,
ServiceIndexEntry serviceEntry,
ILogger log,
Expand All @@ -62,7 +60,8 @@ private async Task<RepositorySignatureResource> GetRepositorySignatureResourceAs
throw new FatalProtocolException(string.Format(CultureInfo.CurrentCulture, Strings.RepositorySignaturesResourceMustBeHttps, source.PackageSource.Source));
}

var httpSourceResource = await source.GetResourceAsync<HttpSourceResource>(token);
var httpSourceResource = await source.GetResourceAsync<HttpSourceResource>(token)
?? throw new InvalidOperationException($"The source '{source.PackageSource.Source}' does not provide {nameof(HttpSourceResource)}.");
var client = httpSourceResource.HttpSource;
var cacheKey = GenerateCacheKey(serviceEntry);

Expand Down Expand Up @@ -91,9 +90,10 @@ private async Task<RepositorySignatureResource> GetRepositorySignatureResourceAs
async httpSourceResult =>
{
var model = await JsonSerializer.DeserializeAsync(
httpSourceResult.Stream,
httpSourceResult.Stream!,
RepositorySignatureJsonContext.Default.RepositorySignatureModel,
token);
token)
?? throw new FatalProtocolException(string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToReadRepositorySignature, repositorySignaturesResourceUri.AbsoluteUri));
return new RepositorySignatureResource(model, source);
},
log,
Expand All @@ -117,14 +117,15 @@ private async Task<RepositorySignatureResource> GetRepositorySignatureResourceAs
if (NuGetFeatureFlags.IsSystemTextJsonDeserializationEnabledByEnvironment(_environmentVariableReader))
{
var model = await JsonSerializer.DeserializeAsync(
httpSourceResult.Stream,
httpSourceResult.Stream!,
RepositorySignatureJsonContext.Default.RepositorySignatureModel,
token);
token)
?? throw new FatalProtocolException(string.Format(CultureInfo.CurrentCulture, Strings.Log_FailedToReadRepositorySignature, repositorySignaturesResourceUri.AbsoluteUri));
return new RepositorySignatureResource(model, source);
}
else
{
var json = await httpSourceResult.Stream.AsJObjectAsync(token);
var json = (await httpSourceResult.Stream!.AsJObjectAsync(token))!;
#pragma warning disable IL2026, IL3050 // Legacy Newtonsoft.Json code path is unreachable when feature switch is true; ILC trims this branch in AOT
return new RepositorySignatureResource(json, source);
#pragma warning restore IL2026, IL3050
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// 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.

#nullable disable

using System;
using System.Collections.Concurrent;
using System.Globalization;
Expand Down Expand Up @@ -31,7 +29,7 @@ public class ServiceIndexResourceV3Provider : ResourceProvider
private readonly ConcurrentDictionary<string, ServiceIndexCacheInfo> _cache;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly EnhancedHttpRetryHelper _enhancedHttpRetryHelper;
private readonly IEnvironmentVariableReader _environmentVariableReader;
private readonly IEnvironmentVariableReader? _environmentVariableReader;

/// <summary>
/// Maximum amount of time to store index.json
Expand All @@ -40,7 +38,7 @@ public class ServiceIndexResourceV3Provider : ResourceProvider

public ServiceIndexResourceV3Provider() : this(environmentVariableReader: null) { }

internal ServiceIndexResourceV3Provider(IEnvironmentVariableReader environmentVariableReader)
internal ServiceIndexResourceV3Provider(IEnvironmentVariableReader? environmentVariableReader)
: base(typeof(ServiceIndexResourceV3),
nameof(ServiceIndexResourceV3Provider),
NuGetResourceProviderPositions.Last)
Expand All @@ -51,10 +49,10 @@ internal ServiceIndexResourceV3Provider(IEnvironmentVariableReader environmentVa
_enhancedHttpRetryHelper = new EnhancedHttpRetryHelper(environmentVariableReader ?? EnvironmentVariableWrapper.Instance);
}

public override async Task<Tuple<bool, INuGetResource>> TryCreate(SourceRepository source, CancellationToken token)
public override async Task<Tuple<bool, INuGetResource?>> TryCreate(SourceRepository source, CancellationToken token)
{
ServiceIndexResourceV3 index = null;
ServiceIndexCacheInfo cacheInfo = null;
ServiceIndexResourceV3? index = null;
ServiceIndexCacheInfo? cacheInfo = null;
var url = source.PackageSource.Source;

// the file type can easily rule out if we need to request the url
Expand Down Expand Up @@ -102,7 +100,7 @@ public override async Task<Tuple<bool, INuGetResource>> TryCreate(SourceReposito
index = cacheInfo.Index;
}

return new Tuple<bool, INuGetResource>(index != null, index);
return new Tuple<bool, INuGetResource?>(index != null, index);
}

/// <summary>
Expand All @@ -116,14 +114,15 @@ public override async Task<Tuple<bool, INuGetResource>> TryCreate(SourceReposito
/// <exception cref="OperationCanceledException">Logged to any provided <paramref name="log"/> as LogMinimal prior to throwing.</exception>
/// <exception cref="FatalProtocolException">Encapsulates all other exceptions.</exception>
/// <returns></returns>
private async Task<ServiceIndexResourceV3> GetServiceIndexResourceV3(
private async Task<ServiceIndexResourceV3?> GetServiceIndexResourceV3(
SourceRepository source,
DateTime utcNow,
ILogger log,
CancellationToken token)
{
var url = source.PackageSource.Source;
var httpSourceResource = await source.GetResourceAsync<HttpSourceResource>(token);
var httpSourceResource = await source.GetResourceAsync<HttpSourceResource>(token)
?? throw new InvalidOperationException($"The source '{source.PackageSource.Source}' does not provide {nameof(HttpSourceResource)}.");
var client = httpSourceResource.HttpSource;

int maxRetries = _enhancedHttpRetryHelper.RetryCountOrDefault;
Expand All @@ -149,7 +148,7 @@ private async Task<ServiceIndexResourceV3> GetServiceIndexResourceV3(
},
async httpSourceResult =>
{
var result = await ConsumeServiceIndexStreamAsync(httpSourceResult.Stream, utcNow, source.PackageSource, token);
var result = await ConsumeServiceIndexStreamAsync(httpSourceResult.Stream!, utcNow, source.PackageSource, token);

return result;
},
Expand Down Expand Up @@ -211,7 +210,7 @@ private async Task<ServiceIndexResourceV3> ConsumeServiceIndexStreamAsync(Stream

private static async Task<ServiceIndexResourceV3> ConsumeServiceIndexStreamStjAsync(Stream stream, DateTime utcNow, PackageSource source, CancellationToken token)
{
ServiceIndexModel index;
ServiceIndexModel? index;
try
{
index = await JsonSerializer.DeserializeAsync(stream, JsonContext.Default.ServiceIndexModel, token);
Expand All @@ -233,7 +232,7 @@ private static async Task<ServiceIndexResourceV3> ConsumeServiceIndexStreamStjAs
}

// Use SemVer instead of NuGetVersion; the service index should always be in strict SemVer format.
if (!SemanticVersion.TryParse(index.Version, out SemanticVersion version) || version.Major != 3)
if (!SemanticVersion.TryParse(index.Version, out SemanticVersion? version) || version.Major != 3)
{
throw new InvalidDataException(string.Format(
CultureInfo.CurrentCulture,
Expand All @@ -247,16 +246,16 @@ private static async Task<ServiceIndexResourceV3> ConsumeServiceIndexStreamStjAs
private static async Task<ServiceIndexResourceV3> ConsumeServiceIndexStreamNsjAsync(Stream stream, DateTime utcNow, PackageSource source, CancellationToken token)
{
// Parse the JSON
JObject json = await stream.AsJObjectAsync(token);
JObject json = (await stream.AsJObjectAsync(token))!;

// Use SemVer instead of NuGetVersion, the service index should always be
// in strict SemVer format
JToken versionToken;
JToken? versionToken;
if (json.TryGetValue("version", out versionToken) &&
versionToken.Type == JTokenType.String)
{
SemanticVersion version;
if (SemanticVersion.TryParse((string)versionToken, out version) &&
SemanticVersion? version;
if (SemanticVersion.TryParse((string)versionToken!, out version) &&
version.Major == 3)
{
#pragma warning disable IL2026, IL3050 // Legacy Newtonsoft.Json code path is unreachable when feature switch is true; ILC trims this branch in AOT
Expand All @@ -268,7 +267,7 @@ private static async Task<ServiceIndexResourceV3> ConsumeServiceIndexStreamNsjAs
string errorMessage = string.Format(
CultureInfo.CurrentCulture,
Strings.Protocol_UnsupportedVersion,
(string)versionToken);
(string?)versionToken);
throw new InvalidDataException(errorMessage);
}
}
Expand All @@ -280,7 +279,7 @@ private static async Task<ServiceIndexResourceV3> ConsumeServiceIndexStreamNsjAs

protected class ServiceIndexCacheInfo
{
public ServiceIndexResourceV3 Index { get; set; }
public ServiceIndexResourceV3? Index { get; set; }

public DateTime CachedTime { get; set; }
}
Expand Down
Loading