|
1 | 1 | # Copyright (C) 2022 Intel Corporation
|
2 | 2 | # SPDX-License-Identifier: GPL-3.0-or-later
|
3 | 3 |
|
| 4 | +import re |
| 5 | +import sqlite3 |
| 6 | +from pathlib import Path |
| 7 | +from typing import List, Tuple |
| 8 | + |
4 | 9 | from packageurl import PackageURL
|
5 | 10 |
|
| 11 | +from cve_bin_tool.error_handler import CVEDBError |
6 | 12 | from cve_bin_tool.util import ProductInfo, ScanInfo
|
7 | 13 |
|
8 | 14 | __all__ = [
|
@@ -89,3 +95,62 @@ def generate_purl(self, product, vendor, qualifier={}, subpath=None):
|
89 | 95 | subpath=subpath,
|
90 | 96 | )
|
91 | 97 | return purl
|
| 98 | + |
| 99 | + def find_vendor_from_purl(self, purl, ver) -> Tuple[List[ScanInfo], bool]: |
| 100 | + """ |
| 101 | + Finds the vendor information for a given PackageURL (purl) and version from the database. |
| 102 | +
|
| 103 | + This method queries the database to retrieve Common Platform Enumeration (CPE) data associated with the given purl. |
| 104 | + It then decodes the CPE data to extract vendor, product, and version information. If the version matches the provided |
| 105 | + version, it constructs a ScanInfo object for each matching entry and returns a list of these objects. |
| 106 | + """ |
| 107 | + |
| 108 | + query = "SELECT cpe from purl2cpe WHERE purl=?" |
| 109 | + cursor = self.db_open_and_get_cursor() |
| 110 | + cursor.execute(query, [str(purl)]) |
| 111 | + cpeList = cursor.fetchall() |
| 112 | + vendorlist: list[ScanInfo] = [] |
| 113 | + vendors = set() |
| 114 | + |
| 115 | + if cpeList != []: |
| 116 | + for item in cpeList: |
| 117 | + vendor, product, version = self.decode_cpe23(str(item)) |
| 118 | + vendors.add((vendor, product)) |
| 119 | + else: |
| 120 | + return vendorlist, False |
| 121 | + |
| 122 | + for vendor, product in vendors: |
| 123 | + vendorlist.append( |
| 124 | + ScanInfo( |
| 125 | + ProductInfo(vendor, product, ver, "/usr/local/bin/product"), |
| 126 | + self.filename, |
| 127 | + ) |
| 128 | + ) |
| 129 | + |
| 130 | + return vendorlist, True |
| 131 | + |
| 132 | + def db_open_and_get_cursor(self) -> sqlite3.Cursor: |
| 133 | + """Opens connection to sqlite database, returns cursor object.""" |
| 134 | + |
| 135 | + dbpath = ( |
| 136 | + Path("~").expanduser() / ".cache" / "cve-bin-tool" / "purl2cpe/purl2cpe.db" |
| 137 | + ) |
| 138 | + connection = sqlite3.connect(dbpath) |
| 139 | + |
| 140 | + if connection is not None: |
| 141 | + cursor = connection.cursor() |
| 142 | + if cursor is None: |
| 143 | + raise CVEDBError |
| 144 | + return cursor |
| 145 | + |
| 146 | + def decode_cpe23(self, cpe23) -> Tuple[str, str, str]: |
| 147 | + """ |
| 148 | + Decodes a CPE 2.3 formatted string to extract vendor, product, and version information. |
| 149 | +
|
| 150 | + """ |
| 151 | + |
| 152 | + # split on `:` only if it's not escaped |
| 153 | + cpe = re.split(r"(?<!\\):", cpe23) |
| 154 | + vendor, product, version = cpe[3], cpe[4], cpe[5] |
| 155 | + # Return available data, convert empty fields to None |
| 156 | + return (vendor, product, version) |
0 commit comments