github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/wordpress/parse_plugin.go (about)

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