github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/wordpress/parse_plugin.go (about)

     1  package wordpress
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path/filepath"
     7  	"regexp"
     8  
     9  	"github.com/anchore/syft/internal"
    10  	"github.com/anchore/syft/syft/artifact"
    11  	"github.com/anchore/syft/syft/file"
    12  	"github.com/anchore/syft/syft/pkg"
    13  	"github.com/anchore/syft/syft/pkg/cataloger/generic"
    14  )
    15  
    16  const contentBufferSize = 4096
    17  
    18  var patterns = map[string]*regexp.Regexp{
    19  	// match example:	"Plugin Name: WP Migration"	--->	WP Migration
    20  	"name": regexp.MustCompile(`(?i)plugin name:\s*(?P<name>.+)`),
    21  
    22  	// match example:	"Version: 5.3"				--->	5.3
    23  	"version": regexp.MustCompile(`(?i)version:\s*(?P<version>[\d.]+)`),
    24  
    25  	// match example:	"License: GPLv3"			--->	GPLv3
    26  	"license": regexp.MustCompile(`(?i)license:\s*(?P<license>\w+)`),
    27  
    28  	// match example:	"Author: MonsterInsights"	--->	MonsterInsights
    29  	"author": regexp.MustCompile(`(?i)author:\s*(?P<author>.+)`),
    30  
    31  	// match example:	"Author URI: https://servmask.com/"	--->	https://servmask.com/
    32  	"author_uri": regexp.MustCompile(`(?i)author uri:\s*(?P<author_uri>.+)`),
    33  }
    34  
    35  type pluginData struct {
    36  	Licenses                 []string `mapstructure:"licenses" json:"licenses,omitempty"`
    37  	pkg.WordpressPluginEntry `mapstructure:",squash" json:",inline"`
    38  }
    39  
    40  func parseWordpressPluginFiles(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    41  	var pkgs []pkg.Package
    42  	var fields = make(map[string]interface{})
    43  	buffer := make([]byte, contentBufferSize)
    44  
    45  	_, err := reader.Read(buffer)
    46  	if err != nil {
    47  		return nil, nil, fmt.Errorf("failed to read %s file: %w", reader.Location.Path(), err)
    48  	}
    49  
    50  	fileContent := string(buffer)
    51  	for field, pattern := range patterns {
    52  		matchMap := internal.MatchNamedCaptureGroups(pattern, fileContent)
    53  		if value := matchMap[field]; value != "" {
    54  			fields[field] = value
    55  		}
    56  	}
    57  
    58  	name, nameOk := fields["name"]
    59  	version, versionOk := fields["version"]
    60  
    61  	// get a plugin name from a plugin's directory name
    62  	pluginInstallDirectory := filepath.Base(filepath.Dir(reader.RealPath))
    63  
    64  	if nameOk && name != "" && versionOk && version != "" {
    65  		var metadata pluginData
    66  
    67  		metadata.PluginInstallDirectory = pluginInstallDirectory
    68  
    69  		author, authorOk := fields["author"]
    70  		if authorOk && author != "" {
    71  			metadata.Author = author.(string)
    72  		}
    73  
    74  		authorURI, authorURIOk := fields["author_uri"]
    75  		if authorURIOk && authorURI != "" {
    76  			metadata.AuthorURI = authorURI.(string)
    77  		}
    78  
    79  		license, licenseOk := fields["license"]
    80  		if licenseOk && license != "" {
    81  			licenses := make([]string, 0)
    82  			licenses = append(licenses, license.(string))
    83  			metadata.Licenses = licenses
    84  		}
    85  
    86  		pkgs = append(
    87  			pkgs,
    88  			newWordpressPluginPackage(
    89  				name.(string),
    90  				version.(string),
    91  				metadata,
    92  				reader.Location,
    93  			),
    94  		)
    95  	}
    96  
    97  	return pkgs, nil, nil
    98  }