Storage
The CPE library provides a flexible storage interface with multiple implementations for persisting CPE data, CVE information, and dictionaries.
Storage Interface
Storage
type Storage interface {
// Lifecycle
Initialize() error
Close() error
// CPE operations
StoreCPE(cpe *CPE) error
RetrieveCPE(id string) (*CPE, error)
UpdateCPE(cpe *CPE) error
DeleteCPE(id string) error
SearchCPE(criteria *CPE, options *MatchOptions) ([]*CPE, error)
AdvancedSearchCPE(criteria *CPE, options *AdvancedMatchOptions) ([]*CPE, error)
// CVE operations
StoreCVE(cve *CVEReference) error
RetrieveCVE(cveID string) (*CVEReference, error)
UpdateCVE(cve *CVEReference) error
DeleteCVE(cveID string) error
SearchCVE(query string, options *SearchOptions) ([]*CVEReference, error)
FindCVEsByCPE(cpe *CPE) ([]*CVEReference, error)
FindCPEsByCVE(cveID string) ([]*CPE, error)
// Dictionary operations
StoreDictionary(dict *CPEDictionary) error
RetrieveDictionary() (*CPEDictionary, error)
// Metadata operations
StoreModificationTimestamp(key string, timestamp time.Time) error
RetrieveModificationTimestamp(key string) (time.Time, error)
}File Storage
NewFileStorage
func NewFileStorage(baseDir string, enableCache bool) (*FileStorage, error)Creates a new file-based storage implementation.
Parameters:
baseDir- Base directory for storing filesenableCache- Whether to enable in-memory caching
Returns:
*FileStorage- File storage instanceerror- Error if creation fails
Example:
// Create file storage with caching
storage, err := cpe.NewFileStorage("./cpe-data", true)
if err != nil {
log.Fatal(err)
}
defer storage.Close()
// Initialize storage
err = storage.Initialize()
if err != nil {
log.Fatal(err)
}FileStorage Structure
The file storage organizes data in the following directory structure:
baseDir/
├── cpes/ # CPE files (JSON format)
├── cves/ # CVE files (JSON format)
├── dictionary.json # CPE dictionary
└── metadata.json # Timestamps and metadataFileStorage Methods
StoreCPE
func (f *FileStorage) StoreCPE(cpe *CPE) errorStores a CPE object to the file system.
Parameters:
cpe- CPE object to store
Returns:
error- Error if storage fails
Example:
cpeObj, _ := cpe.ParseCpe23("cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*")
err := storage.StoreCPE(cpeObj)
if err != nil {
log.Printf("Failed to store CPE: %v", err)
}RetrieveCPE
func (f *FileStorage) RetrieveCPE(id string) (*CPE, error)Retrieves a CPE object by its ID (URI).
Parameters:
id- CPE URI or identifier
Returns:
*CPE- Retrieved CPE objecterror- Error if retrieval fails or CPE not found
Example:
cpeObj, err := storage.RetrieveCPE("cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*")
if err != nil {
if errors.Is(err, cpe.ErrNotFound) {
fmt.Println("CPE not found")
} else {
log.Printf("Failed to retrieve CPE: %v", err)
}
} else {
fmt.Printf("Retrieved: %s\n", cpeObj.GetURI())
}SearchCPE
func (f *FileStorage) SearchCPE(criteria *CPE, options *MatchOptions) ([]*CPE, error)Searches for CPEs matching the given criteria.
Parameters:
criteria- CPE pattern to search foroptions- Matching options
Returns:
[]*CPE- Array of matching CPEserror- Error if search fails
Example:
// Search for all Microsoft products
criteria := &cpe.CPE{
Vendor: cpe.Vendor("microsoft"),
}
options := cpe.DefaultMatchOptions()
results, err := storage.SearchCPE(criteria, options)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d Microsoft products\n", len(results))
for _, result := range results {
fmt.Printf("- %s\n", result.GetURI())
}AdvancedSearchCPE
func (f *FileStorage) AdvancedSearchCPE(criteria *CPE, options *AdvancedMatchOptions) ([]*CPE, error)Performs advanced search with sophisticated matching algorithms.
Example:
criteria := &cpe.CPE{
Vendor: cpe.Vendor("microsoft"),
ProductName: cpe.Product("windows"),
}
options := cpe.NewAdvancedMatchOptions()
options.MatchMode = "distance"
options.ScoreThreshold = 0.8
results, err := storage.AdvancedSearchCPE(criteria, options)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d Windows products\n", len(results))Memory Storage
NewMemoryStorage
func NewMemoryStorage() *MemoryStorageCreates a new in-memory storage implementation (primarily for testing).
Returns:
*MemoryStorage- Memory storage instance
Example:
storage := cpe.NewMemoryStorage()
err := storage.Initialize()
if err != nil {
log.Fatal(err)
}
// Use the storage
cpeObj, _ := cpe.ParseCpe23("cpe:2.3:a:test:product:1.0:*:*:*:*:*:*:*")
err = storage.StoreCPE(cpeObj)
if err != nil {
log.Fatal(err)
}Storage Manager
StorageManager
type StorageManager struct {
Primary Storage // Primary storage backend
Cache Storage // Cache storage backend
CacheEnabled bool // Whether caching is enabled
CacheTTLSeconds int // Cache TTL in seconds
}NewStorageManager
func NewStorageManager(primary Storage) *StorageManagerCreates a new storage manager with the specified primary storage.
Parameters:
primary- Primary storage backend
Returns:
*StorageManager- Storage manager instance
SetCache
func (sm *StorageManager) SetCache(cache Storage)Sets the cache storage backend and enables caching.
Parameters:
cache- Cache storage backend
Example:
// Create primary storage
primaryStorage, _ := cpe.NewFileStorage("./data", false)
// Create cache storage
cacheStorage := cpe.NewMemoryStorage()
// Create storage manager
manager := cpe.NewStorageManager(primaryStorage)
manager.SetCache(cacheStorage)
// Initialize both storages
primaryStorage.Initialize()
cacheStorage.Initialize()Search Options
SearchOptions
type SearchOptions struct {
Limit int // Maximum number of results
Offset int // Number of results to skip
SortBy string // Field to sort by
SortOrder string // Sort order ("asc" or "desc")
IncludeAll bool // Include all fields in results
}DefaultSearchOptions
func DefaultSearchOptions() *SearchOptionsReturns default search options.
Example:
options := cpe.DefaultSearchOptions()
options.Limit = 50
options.SortBy = "vendor"
options.SortOrder = "asc"
cves, err := storage.SearchCVE("apache", options)
if err != nil {
log.Fatal(err)
}Storage Statistics
StorageStats
type StorageStats struct {
TotalCPEs int // Total number of CPEs
TotalCVEs int // Total number of CVEs
TotalDictionaryItems int // Total dictionary items
StorageBytes int64 // Storage size in bytes
LastUpdated time.Time // Last update timestamp
}Error Handling
The storage interface defines several standard errors:
var (
ErrNotFound = errors.New("record not found")
ErrDuplicate = errors.New("duplicate record")
ErrInvalidData = errors.New("invalid data")
ErrStorageDisconnected = errors.New("storage is disconnected")
)Example:
cpeObj, err := storage.RetrieveCPE("non-existent-cpe")
if err != nil {
if errors.Is(err, cpe.ErrNotFound) {
fmt.Println("CPE not found")
} else {
log.Printf("Storage error: %v", err)
}
}Complete Example
package main
import (
"fmt"
"log"
"github.com/scagogogo/cpe"
)
func main() {
// Create and initialize storage
storage, err := cpe.NewFileStorage("./cpe-storage", true)
if err != nil {
log.Fatal(err)
}
defer storage.Close()
err = storage.Initialize()
if err != nil {
log.Fatal(err)
}
// Store some CPEs
cpes := []string{
"cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*",
"cpe:2.3:a:microsoft:office:2019:*:*:*:*:*:*:*",
"cpe:2.3:a:apache:tomcat:9.0:*:*:*:*:*:*:*",
}
for _, cpeStr := range cpes {
cpeObj, err := cpe.ParseCpe23(cpeStr)
if err != nil {
log.Printf("Failed to parse %s: %v", cpeStr, err)
continue
}
err = storage.StoreCPE(cpeObj)
if err != nil {
log.Printf("Failed to store %s: %v", cpeStr, err)
} else {
fmt.Printf("Stored: %s\n", cpeStr)
}
}
// Search for Microsoft products
criteria := &cpe.CPE{
Vendor: cpe.Vendor("microsoft"),
}
results, err := storage.SearchCPE(criteria, cpe.DefaultMatchOptions())
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nFound %d Microsoft products:\n", len(results))
for _, result := range results {
fmt.Printf("- %s %s %s\n",
result.Vendor, result.ProductName, result.Version)
}
// Retrieve specific CPE
retrieved, err := storage.RetrieveCPE("cpe:2.3:a:apache:tomcat:9.0:*:*:*:*:*:*:*")
if err != nil {
log.Printf("Failed to retrieve: %v", err)
} else {
fmt.Printf("\nRetrieved: %s\n", retrieved.GetURI())
}
}