github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/analyzer/language/dotnet/nuget/nuspec.go (about)

     1  package nuget
     2  
     3  import (
     4  	"encoding/xml"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"golang.org/x/xerrors"
    11  
    12  	"github.com/devseccon/trivy/pkg/log"
    13  	"github.com/devseccon/trivy/pkg/utils/fsutils"
    14  )
    15  
    16  const nuspecExt = "nuspec"
    17  
    18  // https://learn.microsoft.com/en-us/nuget/reference/nuspec
    19  type Package struct {
    20  	Metadata Metadata `xml:"metadata"`
    21  }
    22  
    23  type Metadata struct {
    24  	License License `xml:"license"`
    25  }
    26  
    27  type License struct {
    28  	Text string `xml:",chardata"`
    29  	Type string `xml:"type,attr"`
    30  }
    31  
    32  type nuspecParser struct {
    33  	packagesDir string // global packages folder - https: //learn.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders
    34  }
    35  
    36  func newNuspecParser() nuspecParser {
    37  	// cf. https: //learn.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders
    38  	packagesDir := os.Getenv("NUGET_PACKAGES")
    39  	if packagesDir == "" {
    40  		packagesDir = filepath.Join(os.Getenv("HOME"), ".nuget", "packages")
    41  	}
    42  
    43  	if !fsutils.DirExists(packagesDir) {
    44  		log.Logger.Debugf("The nuget packages directory couldn't be found. License search disabled")
    45  		return nuspecParser{}
    46  	}
    47  
    48  	return nuspecParser{
    49  		packagesDir: packagesDir,
    50  	}
    51  }
    52  
    53  func (p nuspecParser) findLicense(name, version string) ([]string, error) {
    54  	if p.packagesDir == "" {
    55  		return nil, nil
    56  	}
    57  
    58  	// package path uses lowercase letters only
    59  	// e.g. `$HOME/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.nuspec`
    60  	// for `Newtonsoft.Json` v13.0.3
    61  	name = strings.ToLower(name)
    62  	version = strings.ToLower(version)
    63  
    64  	nuspecFileName := fmt.Sprintf("%s.%s", name, nuspecExt)
    65  	path := filepath.Join(p.packagesDir, name, version, nuspecFileName)
    66  
    67  	f, err := os.Open(path)
    68  	if err != nil {
    69  		return nil, xerrors.Errorf("unable to open %q file: %w", path, err)
    70  	}
    71  	defer func() { _ = f.Close() }()
    72  
    73  	var pkg Package
    74  	if err = xml.NewDecoder(f).Decode(&pkg); err != nil {
    75  		return nil, xerrors.Errorf("unable to decode %q file: %w", path, err)
    76  	}
    77  
    78  	if license := pkg.Metadata.License; license.Type != "expression" || license.Text == "" {
    79  		return nil, nil
    80  	}
    81  	return []string{pkg.Metadata.License.Text}, nil
    82  }