feat: Implement comprehensive license enforcement and revenue protection
CRITICAL REVENUE PROTECTION: Fix $0 recurring revenue by enforcing BZZZ licensing This commit implements Phase 2A license enforcement, transforming BZZZ from having zero license validation to comprehensive revenue protection integrated with KACHING license authority. KEY BUSINESS IMPACT: • PREVENTS unlimited free usage - BZZZ now requires valid licensing to operate • ENABLES real-time license control - licenses can be suspended immediately via KACHING • PROTECTS against license sharing - unique cluster IDs bind licenses to specific deployments • ESTABLISHES recurring revenue foundation - licensing is now technically enforced CRITICAL FIXES: 1. Setup Manager Revenue Protection (api/setup_manager.go): - FIXED: License data was being completely discarded during setup (line 2085) - NOW: License data is extracted, validated, and saved to configuration - IMPACT: Closes $0 recurring revenue loophole - licenses are now required for deployment 2. Configuration System Integration (pkg/config/config.go): - ADDED: Complete LicenseConfig struct with KACHING integration fields - ADDED: License validation in config validation pipeline - IMPACT: Makes licensing a core requirement, not optional 3. Runtime License Enforcement (main.go): - ADDED: License validation before P2P node initialization (line 175) - ADDED: Fail-closed design - BZZZ exits if license validation fails - ADDED: Grace period support for offline operations - IMPACT: Prevents unlicensed BZZZ instances from starting 4. KACHING License Authority Integration: - REPLACED: Mock license validation (hardcoded BZZZ-2025-DEMO-EVAL-001) - ADDED: Real-time KACHING API integration for license activation - ADDED: Cluster ID generation for license binding - IMPACT: Enables centralized license management and immediate suspension 5. Frontend License Validation Enhancement: - UPDATED: License validation UI to indicate KACHING integration - MAINTAINED: Existing UX while adding revenue protection backend - IMPACT: Users now see real license validation, not mock responses TECHNICAL DETAILS: • Version bump: 1.0.8 → 1.1.0 (significant license enforcement features) • Fail-closed security design: System stops rather than degrading on license issues • Unique cluster ID generation prevents license sharing across deployments • Grace period support (24h default) for offline/network issue scenarios • Comprehensive error handling and user guidance for license issues TESTING REQUIREMENTS: • Test that BZZZ refuses to start without valid license configuration • Verify license data is properly saved during setup (no longer discarded) • Test KACHING integration for license activation and validation • Confirm cluster ID uniqueness and license binding DEPLOYMENT IMPACT: • Existing BZZZ deployments will require license configuration on next restart • Setup process now enforces license validation before deployment • Invalid/missing licenses will prevent BZZZ startup (revenue protection) This implementation establishes the foundation for recurring revenue by making valid licensing technically required for BZZZ operation. 🚀 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,36 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// LicenseConfig holds license verification and runtime enforcement configuration
|
||||
// BUSINESS CRITICAL: This config enables revenue protection by enforcing valid licenses
|
||||
type LicenseConfig struct {
|
||||
// Core license identification - REQUIRED for all BZZZ operations
|
||||
Email string `yaml:"email" json:"email"` // Licensed user email
|
||||
LicenseKey string `yaml:"license_key" json:"license_key"` // Unique license key
|
||||
|
||||
// Organization binding (optional but recommended for enterprise)
|
||||
OrganizationName string `yaml:"organization_name,omitempty" json:"organization_name,omitempty"`
|
||||
|
||||
// Cluster identity and binding - prevents license sharing across clusters
|
||||
ClusterID string `yaml:"cluster_id" json:"cluster_id"` // Unique cluster identifier
|
||||
ClusterName string `yaml:"cluster_name,omitempty" json:"cluster_name,omitempty"` // Human-readable cluster name
|
||||
|
||||
// KACHING license authority integration
|
||||
KachingURL string `yaml:"kaching_url" json:"kaching_url"` // KACHING server URL
|
||||
HeartbeatMinutes int `yaml:"heartbeat_minutes" json:"heartbeat_minutes"` // License heartbeat interval
|
||||
GracePeriodHours int `yaml:"grace_period_hours" json:"grace_period_hours"` // Offline grace period
|
||||
|
||||
// Runtime state tracking
|
||||
LastValidated time.Time `yaml:"last_validated,omitempty" json:"last_validated,omitempty"`
|
||||
ValidationToken string `yaml:"validation_token,omitempty" json:"validation_token,omitempty"` // Current auth token
|
||||
|
||||
// License details (populated by KACHING validation)
|
||||
LicenseType string `yaml:"license_type,omitempty" json:"license_type,omitempty"` // e.g., "standard", "enterprise"
|
||||
MaxNodes int `yaml:"max_nodes,omitempty" json:"max_nodes,omitempty"` // Maximum allowed nodes
|
||||
ExpiresAt time.Time `yaml:"expires_at,omitempty" json:"expires_at,omitempty"` // License expiration
|
||||
IsActive bool `yaml:"is_active" json:"is_active"` // Current license status
|
||||
}
|
||||
|
||||
// SecurityConfig holds cluster security and election configuration
|
||||
type SecurityConfig struct {
|
||||
// Admin key sharing
|
||||
@@ -55,6 +85,7 @@ type Config struct {
|
||||
UCXL UCXLConfig `yaml:"ucxl"` // UCXL protocol settings
|
||||
Security SecurityConfig `yaml:"security"` // Cluster security and elections
|
||||
AI AIConfig `yaml:"ai"` // AI/LLM integration settings
|
||||
License LicenseConfig `yaml:"license"` // License verification and enforcement - REVENUE CRITICAL
|
||||
}
|
||||
|
||||
// WHOOSHAPIConfig holds WHOOSH system integration settings
|
||||
@@ -380,6 +411,16 @@ func getDefaultConfig() *Config {
|
||||
Timeout: 30 * time.Second,
|
||||
},
|
||||
},
|
||||
// REVENUE CRITICAL: License configuration defaults
|
||||
// These settings ensure BZZZ can only run with valid licensing from KACHING
|
||||
License: LicenseConfig{
|
||||
KachingURL: "https://kaching.chorus.services", // KACHING license authority server
|
||||
HeartbeatMinutes: 60, // Check license validity every hour
|
||||
GracePeriodHours: 24, // Allow 24 hours offline before enforcement
|
||||
IsActive: false, // Default to inactive - MUST be validated during setup
|
||||
// Note: Email, LicenseKey, and ClusterID are required and will be set during setup
|
||||
// Leaving them empty in defaults forces setup process to collect them
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,6 +562,56 @@ func validateConfig(config *Config) error {
|
||||
return fmt.Errorf("slurp configuration invalid: %w", err)
|
||||
}
|
||||
|
||||
// REVENUE CRITICAL: Validate license configuration
|
||||
// This prevents BZZZ from running without valid licensing
|
||||
if err := validateLicenseConfig(config.License); err != nil {
|
||||
return fmt.Errorf("license configuration invalid: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateLicenseConfig ensures license configuration meets revenue protection requirements
|
||||
// BUSINESS CRITICAL: This function enforces license requirements that protect revenue
|
||||
func validateLicenseConfig(license LicenseConfig) error {
|
||||
// Check core license identification fields
|
||||
if license.Email == "" {
|
||||
return fmt.Errorf("license email is required - BZZZ cannot run without valid licensing")
|
||||
}
|
||||
|
||||
if license.LicenseKey == "" {
|
||||
return fmt.Errorf("license key is required - BZZZ cannot run without valid licensing")
|
||||
}
|
||||
|
||||
if license.ClusterID == "" {
|
||||
return fmt.Errorf("cluster ID is required - BZZZ cannot run without cluster binding")
|
||||
}
|
||||
|
||||
// Validate KACHING integration settings
|
||||
if license.KachingURL == "" {
|
||||
return fmt.Errorf("KACHING URL is required for license validation")
|
||||
}
|
||||
|
||||
// Validate URL format
|
||||
if err := validateURL(license.KachingURL); err != nil {
|
||||
return fmt.Errorf("invalid KACHING URL: %w", err)
|
||||
}
|
||||
|
||||
// Validate heartbeat and grace period settings
|
||||
if license.HeartbeatMinutes <= 0 {
|
||||
return fmt.Errorf("heartbeat interval must be positive (recommended: 60 minutes)")
|
||||
}
|
||||
|
||||
if license.GracePeriodHours <= 0 {
|
||||
return fmt.Errorf("grace period must be positive (recommended: 24 hours)")
|
||||
}
|
||||
|
||||
// FAIL-CLOSED DESIGN: License must be explicitly marked as active
|
||||
// This ensures setup process validates license before allowing operations
|
||||
if !license.IsActive {
|
||||
return fmt.Errorf("license is not active - run setup to validate with KACHING license authority")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user