Skip to content

Commit d6316e5

Browse files
authored
Merge pull request #9881 from NuGet/dev
[ReleasePrep][2024.03.26] RI of dev into main
2 parents c7a83a9 + 7224113 commit d6316e5

12 files changed

Lines changed: 140 additions & 107 deletions

File tree

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project>
22
<PropertyGroup>
33
<NuGetClientPackageVersion>6.9.1</NuGetClientPackageVersion>
4-
<ServerCommonPackageVersion>2.117.0</ServerCommonPackageVersion>
5-
<NuGetJobsPackageVersion>4.3.0-dev-9116469</NuGetJobsPackageVersion>
4+
<ServerCommonPackageVersion>2.120.0</ServerCommonPackageVersion>
5+
<NuGetJobsPackageVersion>4.3.0-dev-9310589</NuGetJobsPackageVersion>
66
</PropertyGroup>
77
<ItemGroup>
88
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers">

src/NuGetGallery.Core/Services/ITyposquattingServiceHelper.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,20 @@ public interface ITyposquattingServiceHelper
1515
/// <param name="packageId">Package Id compared to</param>
1616
/// <returns>Return true if distance is less than the threshold</returns>
1717
bool IsDistanceLessThanOrEqualToThreshold(string uploadedPackageId, string packageId);
18+
19+
/// <summary>
20+
/// This method is used to check if the distance between the currently uploaded package ID and another package ID is less than or equal to the threshold.
21+
/// </summary>
22+
/// <param name="uploadedPackageId">Uploaded package Id</param>
23+
/// <param name="normalizedPackageId">Normalized Package Id compared to</param>
24+
/// <returns>Return true if distance is less than the threshold</returns>
25+
bool IsDistanceLessThanOrEqualToThresholdWithNormalizedPackageId(string uploadedPackageId, string normalizedPackageId);
26+
27+
/// <summary>
28+
/// This method is used to normalize string.
29+
/// </summary>
30+
/// <param name="str">String to normalize</param>
31+
/// <returns>Normalized string</returns>
32+
string NormalizeString(string str);
1833
}
1934
}

src/NuGetGallery.Services/NuGetGallery.Services.csproj

Lines changed: 4 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

33
<Import Project="..\..\SdkProjects.props" />
44

@@ -66,6 +66,9 @@
6666
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation">
6767
<Version>1.0.0</Version>
6868
</PackageReference>
69+
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens">
70+
<Version>7.3.1</Version>
71+
</PackageReference>
6972
<PackageReference Include="Microsoft.Owin">
7073
<Version>4.2.2</Version>
7174
</PackageReference>

src/NuGetGallery/App_Data/Files/Content/Trusted-Image-Domains.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"img.shields.io",
2727
"i.imgur.com",
2828
"isitmaintained.com",
29+
"media.githubusercontent.com",
2930
"opencollective.com",
3031
"snyk.io",
3132
"sonarcloud.io",
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
// 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

4+
using System;
5+
46
namespace NuGetGallery.Services
57
{
68
public class ExactMatchTyposquattingServiceHelper : ITyposquattingServiceHelper
79
{
810
public bool IsDistanceLessThanOrEqualToThreshold(string uploadedPackageId, string packageId)
911
{
10-
return uploadedPackageId.ToLowerInvariant() == packageId.ToLowerInvariant();
12+
return StringComparer.OrdinalIgnoreCase.Equals(uploadedPackageId, packageId);
13+
}
14+
15+
public bool IsDistanceLessThanOrEqualToThresholdWithNormalizedPackageId(string uploadedPackageId, string normalizedPackageId)
16+
{
17+
return StringComparer.OrdinalIgnoreCase.Equals(uploadedPackageId, normalizedPackageId);
18+
}
19+
20+
public string NormalizeString(string packageId)
21+
{
22+
if (string.IsNullOrEmpty(packageId))
23+
{
24+
return string.Empty;
25+
}
26+
27+
return packageId.ToLowerInvariant();
1128
}
1229
}
1330
}

src/NuGetGallery/Services/TyposquattingCheckListCacheService.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ namespace NuGetGallery
1010
public class TyposquattingCheckListCacheService : ITyposquattingCheckListCacheService
1111
{
1212
private readonly object Locker = new object();
13+
private readonly ITyposquattingServiceHelper _typosquattingServiceHelper;
1314

1415
private List<string> Cache;
1516
private DateTime LastRefreshTime;
1617

1718
private int TyposquattingCheckListConfiguredLength;
1819

19-
public TyposquattingCheckListCacheService()
20+
public TyposquattingCheckListCacheService(ITyposquattingServiceHelper typosquattingServiceHelper)
2021
{
2122
TyposquattingCheckListConfiguredLength = -1;
2223
LastRefreshTime = DateTime.MinValue;
24+
_typosquattingServiceHelper = typosquattingServiceHelper;
2325
}
2426

2527
public IReadOnlyCollection<string> GetTyposquattingCheckList(int checkListConfiguredLength, TimeSpan checkListExpireTime, IPackageService packageService)
@@ -44,14 +46,17 @@ public IReadOnlyCollection<string> GetTyposquattingCheckList(int checkListConfig
4446
if (ShouldCacheBeUpdated(checkListConfiguredLength, checkListExpireTime))
4547
{
4648
TyposquattingCheckListConfiguredLength = checkListConfiguredLength;
47-
48-
Cache = packageService.GetAllPackageRegistrations()
49+
List<string> cachedPackages = packageService.GetAllPackageRegistrations()
4950
.OrderByDescending(pr => pr.IsVerified)
5051
.ThenByDescending(pr => pr.DownloadCount)
5152
.Select(pr => pr.Id)
5253
.Take(TyposquattingCheckListConfiguredLength)
5354
.ToList();
5455

56+
Cache = cachedPackages
57+
.Select(pr => _typosquattingServiceHelper.NormalizeString(pr))
58+
.ToList();
59+
5560
LastRefreshTime = DateTime.UtcNow;
5661
}
5762
}

src/NuGetGallery/Services/TyposquattingService.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,20 @@ public bool IsUploadedPackageIdTyposquatting(string uploadedPackageId, User uplo
6060

6161
var totalTimeStopwatch = Stopwatch.StartNew();
6262
var checklistRetrievalStopwatch = Stopwatch.StartNew();
63-
var packageIdsCheckList = _typosquattingCheckListCacheService.GetTyposquattingCheckList(checkListConfiguredLength, checkListExpireTimeInHours, _packageService);
63+
64+
// It must be normalized during initial list creation
65+
var normalizedPackageIdsCheckList = _typosquattingCheckListCacheService.GetTyposquattingCheckList(checkListConfiguredLength, checkListExpireTimeInHours, _packageService);
6466
checklistRetrievalStopwatch.Stop();
6567

6668
_telemetryService.TrackMetricForTyposquattingChecklistRetrievalTime(uploadedPackageId, checklistRetrievalStopwatch.Elapsed);
6769

6870
var algorithmProcessingStopwatch = Stopwatch.StartNew();
6971
var collisionIds = new ConcurrentBag<string>();
70-
Parallel.ForEach(packageIdsCheckList, (packageId, loopState) =>
72+
Parallel.ForEach(normalizedPackageIdsCheckList, (normalizedPackageId, loopState) =>
7173
{
72-
if (_typosquattingServiceHelper.IsDistanceLessThanOrEqualToThreshold(uploadedPackageId, packageId))
74+
if (_typosquattingServiceHelper.IsDistanceLessThanOrEqualToThresholdWithNormalizedPackageId(uploadedPackageId, normalizedPackageId))
7375
{
74-
collisionIds.Add(packageId);
76+
collisionIds.Add(normalizedPackageId);
7577
}
7678
});
7779
algorithmProcessingStopwatch.Stop();
@@ -86,7 +88,7 @@ public bool IsUploadedPackageIdTyposquatting(string uploadedPackageId, User uplo
8688
totalTimeStopwatch.Elapsed,
8789
wasUploadBlocked,
8890
typosquattingCheckCollisionIds,
89-
packageIdsCheckList.Count,
91+
normalizedPackageIdsCheckList.Count,
9092
checkListExpireTimeInHours);
9193

9294
return false;
@@ -126,7 +128,7 @@ public bool IsUploadedPackageIdTyposquatting(string uploadedPackageId, User uplo
126128
totalTimeStopwatch.Elapsed,
127129
wasUploadBlocked,
128130
typosquattingCheckCollisionIds,
129-
packageIdsCheckList.Count,
131+
normalizedPackageIdsCheckList.Count,
130132
checkListExpireTimeInHours);
131133

132134
return wasUploadBlocked;

src/NuGetGallery/ViewModels/LogOnViewModel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ public enum ExistingUserLinkingErrorType
4949
public class SignInViewModel
5050
{
5151
[Required]
52-
[Display(Name = "Username or Email")]
53-
[Hint("Enter your username or email address.")]
52+
[Display(Name = "Email Address")]
53+
[Hint("Enter your email address.")]
5454
public string UserNameOrEmail { get; set; }
5555

5656
[Required]
Lines changed: 52 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@using String = NuGetGallery.Strings;
22
@using NuGetGallery.Frameworks;
3+
34
@model PackageFrameworkCompatibilityBadges
45
@{
56
var eventName = "search-selection";
@@ -18,6 +19,7 @@
1819
itemIndex = parsedItemIndex;
1920
}
2021
}
22+
2123
@functions
2224
{
2325
public enum FrameworkContext
@@ -31,25 +33,7 @@
3133
public string GetBadgeTooltip(FrameworkContext context, PackageFrameworkCompatibilityData tfmCompatibilityData)
3234
{
3335
var badgeVersion = tfmCompatibilityData.Framework.GetBadgeVersion();
34-
string tfmType;
35-
switch (context)
36-
{
37-
case FrameworkContext.Net:
38-
tfmType = ".NET";
39-
break;
40-
case FrameworkContext.NetCore:
41-
tfmType = ".NET Core";
42-
break;
43-
case FrameworkContext.NetStandard:
44-
tfmType = ".NET Standard";
45-
break;
46-
case FrameworkContext.NetFramework:
47-
tfmType = ".NET Framework";
48-
break;
49-
default:
50-
tfmType = "";
51-
break;
52-
}
36+
string tfmType = GetFrameworkProductName(context);
5337

5438
if (badgeVersion.IsEmpty())
5539
{
@@ -65,85 +49,68 @@
6549

6650
return toolTip;
6751
}
52+
53+
public string GetBadgeDisplayName(FrameworkContext context, PackageFrameworkCompatibilityData tfmCompatibilityData)
54+
{
55+
var badgeVersion = tfmCompatibilityData.Framework.GetBadgeVersion();
56+
string displayName = GetFrameworkProductName(context);
57+
58+
if (badgeVersion.IsEmpty())
59+
{
60+
return displayName;
61+
}
62+
63+
return displayName + " " + badgeVersion;
64+
}
65+
66+
public string GetFrameworkProductName(FrameworkContext context)
67+
{
68+
switch (context)
69+
{
70+
case FrameworkContext.Net:
71+
return ".NET";
72+
case FrameworkContext.NetCore:
73+
return ".NET Core";
74+
case FrameworkContext.NetStandard:
75+
return ".NET Standard";
76+
case FrameworkContext.NetFramework:
77+
return ".NET Framework";
78+
default:
79+
return "";
80+
}
81+
}
82+
}
83+
84+
@helper DisplayFrameworkBadge(PackageFrameworkCompatibilityData tfmCompatibilityData, FrameworkContext context, int? itemIndex, string eventName)
85+
{
86+
<a href=@Url.FrameworksTab(Model.PackageId, Model.PackageVersion)
87+
@if (itemIndex.HasValue)
88+
{
89+
@: data-track="@eventName" data-track-value="@itemIndex" data-click-source="FrameworkBadge"
90+
@: data-package-id="@Model.PackageId" data-package-version="@Model.PackageVersion"
91+
@: data-badge-framework="@tfmCompatibilityData.Framework.GetShortFolderName()" data-badge-is-computed="@tfmCompatibilityData.IsComputed"
92+
}>
93+
<span class=@(tfmCompatibilityData.IsComputed ? "framework-badge-computed" : "framework-badge-asset") aria-label="@GetBadgeTooltip(context, tfmCompatibilityData)" data-content="@GetBadgeTooltip(context, tfmCompatibilityData)">
94+
@GetBadgeDisplayName(context, tfmCompatibilityData)
95+
</span>
96+
</a>
6897
}
6998

7099
<div class="framework framework-badges">
71100
@if (Model.Net != null)
72101
{
73-
<!-- .NET cannot be an empty version since the lowest version for this framework is "net5.0", if the package contains just "net" framework it will fall into .NET Framework badge instead.' -->
74-
<a href=@Url.FrameworksTab(Model.PackageId, Model.PackageVersion)
75-
@if (itemIndex.HasValue)
76-
{
77-
@:data-track="@eventName" data-track-value="@itemIndex" data-click-source="FrameworkBadge"
78-
@:data-package-id="@Model.PackageId" data-package-version="@Model.PackageVersion"
79-
@:data-badge-framework="@Model.Net.Framework.GetShortFolderName()" data-badge-is-computed="@Model.Net.IsComputed"
80-
}>
81-
<span class=@(Model.Net.IsComputed ? "framework-badge-computed" : "framework-badge-asset") aria-label="@GetBadgeTooltip(FrameworkContext.Net, Model.Net)" data-content="@GetBadgeTooltip(FrameworkContext.Net, Model.Net)">
82-
.NET @Model.Net.Framework.GetBadgeVersion()
83-
</span>
84-
</a>
102+
@DisplayFrameworkBadge(Model.Net, FrameworkContext.Net, itemIndex, eventName)
85103
}
86104
@if (Model.NetCore != null)
87105
{
88-
<a href=@Url.FrameworksTab(Model.PackageId, Model.PackageVersion)
89-
@if (itemIndex.HasValue)
90-
{
91-
@:data-track="@eventName" data-track-value="@itemIndex" data-click-source="FrameworkBadge"
92-
@:data-package-id="@Model.PackageId" data-package-version="@Model.PackageVersion"
93-
@:data-badge-framework="@Model.NetCore.Framework.GetShortFolderName()" data-badge-is-computed="@Model.NetCore.IsComputed"
94-
}>
95-
<span class=@(Model.NetCore.IsComputed ? "framework-badge-computed" : "framework-badge-asset") aria-label="@GetBadgeTooltip(FrameworkContext.NetCore, Model.NetCore)" data-content="@GetBadgeTooltip(FrameworkContext.NetCore, Model.NetCore)">
96-
@if (Model.NetCore.Framework.GetBadgeVersion().IsEmpty())
97-
{
98-
@:.NET Core
99-
}
100-
else
101-
{
102-
@:.NET Core @Model.NetCore.Framework.GetBadgeVersion()
103-
}
104-
</span>
105-
</a>
106+
@DisplayFrameworkBadge(Model.NetCore, FrameworkContext.NetCore, itemIndex, eventName)
106107
}
107108
@if (Model.NetStandard != null)
108109
{
109-
<a href=@Url.FrameworksTab(Model.PackageId, Model.PackageVersion)
110-
@if (itemIndex.HasValue)
111-
{
112-
@:data-track="@eventName" data-track-value="@itemIndex" data-click-source="FrameworkBadge"
113-
@:data-package-id="@Model.PackageId" data-package-version="@Model.PackageVersion"
114-
@:data-badge-framework="@Model.NetStandard.Framework.GetShortFolderName()" data-badge-is-computed="@Model.NetStandard.IsComputed"
115-
}>
116-
<span class=@(Model.NetStandard.IsComputed ? "framework-badge-computed" : "framework-badge-asset") aria-label="@GetBadgeTooltip(FrameworkContext.NetStandard, Model.NetStandard)" data-content="@GetBadgeTooltip(FrameworkContext.NetStandard, Model.NetStandard)">
117-
@if (Model.NetStandard.Framework.GetBadgeVersion().IsEmpty())
118-
{
119-
@:.NET Standard
120-
}
121-
else
122-
{
123-
@:.NET Standard @Model.NetStandard.Framework.GetBadgeVersion()
124-
}
125-
</span>
126-
</a>
110+
@DisplayFrameworkBadge(Model.NetStandard, FrameworkContext.NetStandard, itemIndex, eventName)
127111
}
128112
@if (Model.NetFramework != null)
129113
{
130-
<a href=@Url.FrameworksTab(Model.PackageId, Model.PackageVersion)
131-
@if (itemIndex.HasValue)
132-
{
133-
@:data-track="@eventName" data-track-value="@itemIndex" data-click-source="FrameworkBadge"
134-
@:data-package-id="@Model.PackageId" data-package-version="@Model.PackageVersion"
135-
@:data-badge-framework="@Model.NetFramework.Framework.GetShortFolderName()" data-badge-is-computed="@Model.NetFramework.IsComputed"
136-
}>
137-
<span class=@(Model.NetFramework.IsComputed ? "framework-badge-computed" : "framework-badge-asset") aria-label="@GetBadgeTooltip(FrameworkContext.NetFramework, Model.NetFramework)" data-content="@GetBadgeTooltip(FrameworkContext.NetFramework, Model.NetFramework)">
138-
@if (Model.NetFramework.Framework.GetBadgeVersion().IsEmpty())
139-
{
140-
@:.NET Framework
141-
}
142-
else
143-
{
144-
@:.NET Framework @Model.NetFramework.Framework.GetBadgeVersion()
145-
}
146-
</span>
147-
</a>
114+
@DisplayFrameworkBadge(Model.NetFramework, FrameworkContext.NetFramework, itemIndex, eventName)
148115
}
149116
</div>

src/NuGetGallery/Web.config

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,22 @@
586586
</system.diagnostics>
587587
<runtime>
588588
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
589+
<dependentAssembly>
590+
<assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
591+
<bindingRedirect oldVersion="0.0.0.0-7.3.1.0" newVersion="7.3.1.0"/>
592+
</dependentAssembly>
593+
<dependentAssembly>
594+
<assemblyIdentity name="Microsoft.IdentityModel.Logging" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
595+
<bindingRedirect oldVersion="0.0.0.0-7.3.1.0" newVersion="7.3.1.0"/>
596+
</dependentAssembly>
597+
<dependentAssembly>
598+
<assemblyIdentity name="Microsoft.IdentityModel.JsonWebTokens" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
599+
<bindingRedirect oldVersion="0.0.0.0-7.3.1.0" newVersion="7.3.1.0"/>
600+
</dependentAssembly>
601+
<dependentAssembly>
602+
<assemblyIdentity name="Microsoft.IdentityModel.Abstractions" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
603+
<bindingRedirect oldVersion="0.0.0.0-7.3.1.0" newVersion="7.3.1.0"/>
604+
</dependentAssembly>
589605
<dependentAssembly>
590606
<assemblyIdentity name="WebGrease" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
591607
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930"/>

0 commit comments

Comments
 (0)