Example #1
0
func toPackages(criteria criteria) []*database.Package {
	// There are duplicates in Red Hat .xml files.
	// This map is for deduplication.
	packagesParameters := make(map[string]*database.Package)

	possibilities := getPossibilities(criteria)
	for _, criterions := range possibilities {
		var (
			pkg       database.Package
			osVersion int
			err       error
		)

		// Attempt to parse package data from trees of criterions.
		for _, c := range criterions {
			if strings.Contains(c.Comment, " is installed") {
				const prefixLen = len("Red Hat Enterprise Linux ")
				osVersion, err = strconv.Atoi(strings.TrimSpace(c.Comment[prefixLen : prefixLen+strings.Index(c.Comment[prefixLen:], " ")]))
				if err != nil {
					log.Warningf("could not parse Red Hat release version from: '%s'.", c.Comment)
				}
			} else if strings.Contains(c.Comment, " is earlier than ") {
				const prefixLen = len(" is earlier than ")
				pkg.Name = strings.TrimSpace(c.Comment[:strings.Index(c.Comment, " is earlier than ")])
				pkg.Version, err = types.NewVersion(c.Comment[strings.Index(c.Comment, " is earlier than ")+prefixLen:])
				if err != nil {
					log.Warningf("could not parse package version '%s': %s. skipping", c.Comment[strings.Index(c.Comment, " is earlier than ")+prefixLen:], err.Error())
				}
			}
		}

		if osVersion > firstConsideredRHEL {
			pkg.OS = "centos" + ":" + strconv.Itoa(osVersion)
		} else {
			continue
		}

		if pkg.OS != "" && pkg.Name != "" && pkg.Version.String() != "" {
			packagesParameters[pkg.Key()] = &pkg
		} else {
			log.Warningf("could not determine a valid package from criterions: %v", criterions)
		}
	}

	// Convert the map to slice.
	var packagesParametersArray []*database.Package
	for _, p := range packagesParameters {
		packagesParametersArray = append(packagesParametersArray, p)
	}

	return packagesParametersArray
}
Example #2
0
// Detect detects packages using var/lib/dpkg/status from the input data
func (detector *DpkgPackagesDetector) Detect(data map[string][]byte) ([]*database.Package, error) {
	f, hasFile := data["var/lib/dpkg/status"]
	if !hasFile {
		return []*database.Package{}, nil
	}

	// Create a map to store packages and ensure their uniqueness
	packagesMap := make(map[string]*database.Package)

	var pkg *database.Package
	var err error
	scanner := bufio.NewScanner(strings.NewReader(string(f)))
	for scanner.Scan() {
		line := scanner.Text()

		if strings.HasPrefix(line, "Package: ") {
			// Package line
			// Defines the name of the package

			pkg = &database.Package{
				Name: strings.TrimSpace(strings.TrimPrefix(line, "Package: ")),
			}
		} else if pkg != nil && strings.HasPrefix(line, "Source: ") {
			// Source line (Optionnal)
			// Gives the name of the source package
			// May also specifies a version

			srcCapture := dpkgSrcCaptureRegexp.FindAllStringSubmatch(line, -1)[0]
			md := map[string]string{}
			for i, n := range srcCapture {
				md[dpkgSrcCaptureRegexpNames[i]] = strings.TrimSpace(n)
			}

			pkg.Name = md["name"]
			if md["version"] != "" {
				pkg.Version, err = types.NewVersion(md["version"])
				if err != nil {
					log.Warningf("could not parse package version '%s': %s. skipping", line[1], err.Error())
				}
			}
		} else if pkg != nil && strings.HasPrefix(line, "Version: ") && pkg.Version.String() == "" {
			// Version line
			// Defines the version of the package
			// This version is less important than a version retrieved from a Source line
			// because the Debian vulnerabilities often skips the epoch from the Version field
			// which is not present in the Source version, and because +bX revisions don't matter
			pkg.Version, err = types.NewVersion(strings.TrimPrefix(line, "Version: "))
			if err != nil {
				log.Warningf("could not parse package version '%s': %s. skipping", line[1], err.Error())
			}
		}

		// Add the package to the result array if we have all the informations
		if pkg != nil && pkg.Name != "" && pkg.Version.String() != "" {
			packagesMap[pkg.Key()] = pkg
			pkg = nil
		}
	}

	// Convert the map to a slice
	packages := make([]*database.Package, 0, len(packagesMap))
	for _, pkg := range packagesMap {
		packages = append(packages, pkg)
	}

	return packages, nil
}