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 metadata
FileStorage Methods
StoreCPE
func (f *FileStorage) StoreCPE(cpe *CPE) error
Stores 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() *MemoryStorage
Creates 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) *StorageManager
Creates 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() *SearchOptions
Returns 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())
}
}