@@ -5,6 +5,7 @@ namespace Microsoft.ComponentDetection.Detectors.NuGet;
55using System . IO ;
66using System . Linq ;
77using System . Reactive . Linq ;
8+ using System . Text . Json ;
89using System . Text . RegularExpressions ;
910using System . Threading . Tasks ;
1011using System . Xml ;
@@ -20,6 +21,7 @@ public class NuGetComponentDetector : FileComponentDetector
2021 private static readonly IEnumerable < string > LowConfidencePackages = new [ ] { "Newtonsoft.Json" } ;
2122
2223 public const string NugetConfigFileName = "nuget.config" ;
24+ public const string NugetLockfileName = "packages.lock.json" ;
2325
2426 private readonly IList < string > repositoryPathKeyNames = new List < string > { "repositorypath" , "globalpackagesfolder" } ;
2527
@@ -37,7 +39,15 @@ public NuGetComponentDetector(
3739
3840 public override IEnumerable < string > Categories => new [ ] { Enum . GetName ( typeof ( DetectorClass ) , DetectorClass . NuGet ) } ;
3941
40- public override IList < string > SearchPatterns { get ; } = new List < string > { "*.nupkg" , "*.nuspec" , NugetConfigFileName , "paket.lock" } ;
42+ public override IList < string > SearchPatterns { get ; }
43+ = new List < string >
44+ {
45+ "*.nupkg" ,
46+ "*.nuspec" ,
47+ NugetConfigFileName ,
48+ NugetLockfileName ,
49+ "paket.lock" ,
50+ } ;
4151
4252 public override IEnumerable < ComponentType > SupportedComponentTypes { get ; } = new [ ] { ComponentType . NuGet } ;
4353
@@ -105,6 +115,12 @@ private async Task ProcessFileAsync(ProcessRequest processRequest)
105115 else if ( "paket.lock" . Equals ( stream . Pattern , StringComparison . OrdinalIgnoreCase ) )
106116 {
107117 this . ParsePaketLock ( processRequest ) ;
118+ return ;
119+ }
120+ else if ( NugetLockfileName . Equals ( stream . Pattern , StringComparison . OrdinalIgnoreCase ) )
121+ {
122+ await this . ParseNugetLockfileAsync ( processRequest ) ;
123+ return ;
108124 }
109125 else
110126 {
@@ -174,6 +190,29 @@ private void ParsePaketLock(ProcessRequest processRequest)
174190 }
175191 }
176192
193+ private async Task ParseNugetLockfileAsync ( ProcessRequest processRequest )
194+ {
195+ var singleFileComponentRecorder = processRequest . SingleFileComponentRecorder ;
196+ var stream = processRequest . ComponentStream ;
197+
198+ var lockfile = await JsonSerializer . DeserializeAsync < NugetLockfileShape > ( stream . Stream ) ;
199+ if ( lockfile . Version != 1 )
200+ {
201+ // only version 1 is supported
202+ singleFileComponentRecorder . RegisterPackageParseFailure ( stream . Location ) ;
203+ return ;
204+ }
205+
206+ foreach ( var framework in lockfile . Dependencies . Values )
207+ {
208+ foreach ( var ( name , value ) in framework )
209+ {
210+ var component = new NuGetComponent ( name , value . Resolved ) ;
211+ singleFileComponentRecorder . RegisterUsage ( new DetectedComponent ( component ) ) ;
212+ }
213+ }
214+ }
215+
177216 private IList < DirectoryInfo > GetRepositoryPathsFromNugetConfig ( IComponentStream componentStream )
178217 {
179218 var potentialPaths = new List < string > ( ) ;
0 commit comments