| File: Packaging\NuGetSourceIdentity.cs | Web Access |
| Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Security.Cryptography; using System.Text; namespace Aspire.Cli.Packaging; internal static class NuGetSourceIdentity { public const int KeySizeInBytes = 32; public static string Compute(string source, ReadOnlySpan<byte> key) { ArgumentException.ThrowIfNullOrWhiteSpace(source); if (key.Length != KeySizeInBytes) { throw new ArgumentException($"The NuGet source identity key must be {KeySizeInBytes} bytes.", nameof(key)); } return Convert.ToHexString(HMACSHA256.HashData( key, Encoding.UTF8.GetBytes(Normalize(source)))); } public static string Normalize(string source) { var trimmed = source.Trim(); if (Uri.TryCreate(trimmed, UriKind.Absolute, out var uri)) { if (uri.IsFile) { return $"path:{NormalizePath(uri.LocalPath)}"; } return $"uri:{uri.AbsoluteUri}"; } if (Path.IsPathFullyQualified(trimmed)) { return $"path:{NormalizePath(trimmed)}"; } return $"name:{trimmed.ToUpperInvariant()}"; } public static bool HasCredentialMaterial(string source) { var trimmedSource = source.Trim(); var looksHttp = trimmedSource.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || trimmedSource.StartsWith("https://", StringComparison.OrdinalIgnoreCase); if (!Uri.TryCreate(trimmedSource, UriKind.Absolute, out var uri)) { return looksHttp; } return (uri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) || uri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)) && (!string.IsNullOrEmpty(uri.UserInfo) || !string.IsNullOrEmpty(uri.Query) || !string.IsNullOrEmpty(uri.Fragment)); } private static string NormalizePath(string path) { var normalized = Path.GetFullPath(path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)); return OperatingSystem.IsWindows() ? normalized.ToUpperInvariant() : normalized; } }