@@ -17,15 +17,13 @@ SPDX-License-Identifier: Apache-2.0
1717Copyright (c) OWASP Foundation. All Rights Reserved.
1818*/
1919
20- import { type Dirent , readdirSync , readFileSync } from 'node:fs'
21- import { dirname , join } from 'node:path'
20+ import { dirname } from 'node:path'
2221
2322import * as CDX from '@cyclonedx/cyclonedx-library'
2423import normalizePackageJson from 'normalize-package-data'
2524import type { Compilation , Module } from 'webpack'
2625
2726import {
28- getMimeForLicenseFile ,
2927 getPackageDescription ,
3028 isNonNullable ,
3129 type PackageDescription ,
@@ -38,15 +36,18 @@ export class Extractor {
3836 readonly #compilation: Compilation
3937 readonly #componentBuilder: CDX . Builders . FromNodePackageJson . ComponentBuilder
4038 readonly #purlFactory: CDX . Factories . FromNodePackageJson . PackageUrlFactory
39+ readonly #leGatherer: CDX . Utils . LicenseUtility . LicenseEvidenceGatherer
4140
4241 constructor (
4342 compilation : Compilation ,
4443 componentBuilder : CDX . Builders . FromNodePackageJson . ComponentBuilder ,
45- purlFactory : CDX . Factories . FromNodePackageJson . PackageUrlFactory
44+ purlFactory : CDX . Factories . FromNodePackageJson . PackageUrlFactory ,
45+ leFetcher : CDX . Utils . LicenseUtility . LicenseEvidenceGatherer
4646 ) {
4747 this . #compilation = compilation
4848 this . #componentBuilder = componentBuilder
4949 this . #purlFactory = purlFactory
50+ this . #leGatherer = leFetcher
5051 }
5152
5253 generateComponents ( modules : Iterable < Module > , collectEvidence : boolean , logger ?: WebpackLogger ) : Iterable < CDX . Models . Component > {
@@ -146,47 +147,24 @@ export class Extractor {
146147 }
147148 }
148149
149- readonly #LICENSE_FILENAME_PATTERN = / ^ (?: U N ) ? L I C E N [ C S ] E | .\. L I C E N [ C S ] E $ | ^ N O T I C E $ / i
150-
151150 public * getLicenseEvidence ( packageDir : string , logger ?: WebpackLogger ) : Generator < CDX . Models . License > {
152- let pcis : Dirent [ ] = [ ]
153- try {
154- pcis = readdirSync ( packageDir , { withFileTypes : true } )
155- } catch ( e ) {
156- logger ?. warn ( 'collecting license evidence in' , packageDir , 'failed:' , e )
157- return
158- }
159- for ( const pci of pcis ) {
160- if (
161- // Ignore all directories - they are not files :-)
162- // Don't follow symlinks for security reasons!
163- ! pci . isFile ( ) ||
164- ! this . #LICENSE_FILENAME_PATTERN. test ( pci . name )
165- ) {
166- continue
151+ const files = this . #leGatherer. getFileAttachments (
152+ packageDir ,
153+ ( error : Error ) : void => {
154+ /* c8 ignore next 2 */
155+ logger ?. info ( error . message )
156+ logger ?. debug ( error . message , error )
167157 }
168-
169- const contentType = getMimeForLicenseFile ( pci . name )
170- if ( contentType === undefined ) {
171- continue
172- }
173-
174- const fp = join ( packageDir , pci . name )
175- try {
176- yield new CDX . Models . NamedLicense (
177- `file: ${ pci . name } ` ,
178- {
179- text : new CDX . Models . Attachment (
180- readFileSync ( fp ) . toString ( 'base64' ) ,
181- {
182- contentType,
183- encoding : CDX . Enums . AttachmentEncoding . Base64
184- }
185- )
186- } )
187- } catch ( e ) { // may throw if `readFileSync()` fails
188- logger ?. warn ( 'collecting license evidence from' , fp , 'failed:' , e )
158+ )
159+ try {
160+ for ( const { file, text} of files ) {
161+ yield new CDX . Models . NamedLicense ( `file: ${ file } ` , { text } )
189162 }
190163 }
164+ /* c8 ignore next 3 */
165+ catch ( e ) {
166+ // generator will not throw before first `.nest()` is called ...
167+ logger ?. warn ( 'collecting license evidence in' , packageDir , 'failed:' , e )
168+ }
191169 }
192170}
0 commit comments