librnxengine 1.1.0

implement robust software licensing, activation, and validation systems.
Documentation
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};

/// Represents the outcome of a license validation operation.
///
/// This struct provides detailed information about the validation status,
/// including violations, warnings, expiration data, and enabled features.
///
/// # Fields
/// - `is_valid`: Overall validation status (true if no violations)
/// - `violations`: Critical issues that invalidate the license
/// - `warnings`: Non-critical issues that don't affect validity
/// - `expires_at`: When the license expires (None if expired or not applicable)
/// - `days_remaining`: Days until expiration (None if expired)
/// - `features`: List of enabled features from the license
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationResult {
    pub is_valid: bool,
    pub violations: Vec<String>,
    pub warnings: Vec<String>,
    pub expires_at: Option<DateTime<Utc>>,
    pub days_remaining: Option<i64>,
    pub features: Vec<String>,
}

impl ValidationResult {
    /// Creates a new `ValidationResult` with default values.
    ///
    /// # Returns
    /// A `ValidationResult` with:
    /// - `is_valid`: true (assumes valid until proven otherwise)
    /// - Empty violations and warnings vectors
    /// - No expiration data
    /// - Empty features list
    pub fn new() -> Self {
        Self {
            is_valid: true,
            violations: Vec::new(),
            warnings: Vec::new(),
            expires_at: None,
            days_remaining: None,
            features: Vec::new(),
        }
    }

    /// Adds a validation violation and automatically marks the result as invalid.
    ///
    /// # Parameters
    /// - `violation`: A string describing the validation failure
    ///
    /// # Side Effects
    /// - Appends the violation to the violations list
    /// - Sets `is_valid` to false
    pub fn add_violation(&mut self, violation: String) {
        self.violations.push(violation);
        self.is_valid = false;
    }

    /// Adds a non-critical warning that doesn't affect license validity.
    ///
    /// # Parameters
    /// - `warning`: A string describing the warning condition
    ///
    /// # Note
    /// Warnings don't affect the `is_valid` status and are meant for
    /// informational purposes only (e.g., upcoming expiration).
    pub fn add_warning(&mut self, warning: String) {
        self.warnings.push(warning);
    }

    /// Checks if the validation passed without critical violations.
    ///
    /// # Returns
    /// - `true`: No violations present (license is valid)
    /// - `false`: One or more violations present (license is invalid)
    pub fn is_valid(&self) -> bool {
        self.is_valid
    }
}

/// Validates software licenses with configurable validation rules.
///
/// This struct provides methods to validate licenses with options for:
/// - Offline vs online validation requirements
/// - Hardware binding checks
/// - Grace periods after expiration
///
/// # Fields
/// - `allow_offline`: Whether the license can be validated without network access
/// - `grace_period_days`: Days of grace allowed after license expiration
/// - `require_hardware_check`: Whether hardware fingerprint validation is required
pub struct LicenseValidator {
    pub allow_offline: bool,
    pub grace_period_days: u32,
    pub require_hardware_check: bool,
}

impl LicenseValidator {
    /// Validates a license against the configured validation rules.
    ///
    /// Performs the following checks in order:
    /// 1. License expiration check
    /// 2. Hardware fingerprint requirement (if enabled)
    /// 3. Online validation requirement (if enabled)
    ///
    /// # Parameters
    /// - `license`: The license object to validate (implements `License` trait)
    /// - `hardware_fingerprint`: Optional hardware fingerprint for device binding
    /// - `is_online`: Whether the system currently has network connectivity
    ///
    /// # Returns
    /// A `ValidationResult` containing:
    /// - Overall validity status
    /// - List of violations (if any)
    /// - List of warnings (if any)
    /// - Expiration information (if license is not expired)
    /// - List of enabled features
    ///
    /// # Example
    /// ```rust
    /// use librnxlic::{LicenseValidator, License};
    ///
    /// let validator = LicenseValidator {
    ///     allow_offline: false,
    ///     grace_period_days: 7,
    ///     require_hardware_check: true,
    /// };
    ///
    /// let result = validator.validate_license(
    ///     &license,
    ///     Some("fingerprint123"),
    ///     true
    /// );
    ///
    /// if result.is_valid() {
    ///     println!("License is valid");
    /// } else {
    ///     eprintln!("Violations: {:?}", result.violations);
    /// }
    /// ```
    pub fn validate_license(
        &self,
        license: &crate::license::License,
        hardware_fingerprint: Option<&str>,
        is_online: bool,
    ) -> ValidationResult {
        // Initialize result with default values
        let mut result = ValidationResult::new();

        // Check 1: License expiration
        if license.is_expired() {
            result.add_violation("License has expired".to_string());
        } else {
            // Populate expiration information for valid licenses
            result.expires_at = Some(license.expires_at());
            result.days_remaining = Some(license.days_remaining());
        }

        // Extract enabled features from license
        result.features = license.features().to_vec();

        // Check 2: Hardware fingerprint requirement
        if self.require_hardware_check && hardware_fingerprint.is_none() {
            result.add_violation("Hardware fingerprint required".to_string());
        }

        // Check 3: Online validation requirement
        if !self.allow_offline && !is_online {
            result.add_violation("Online validation required".to_string());
        }

        // Log validation outcome
        if !result.is_valid {
            warn!("License validation failed: {:?}", result.violations);
        } else {
            debug!("License validation passed");
        }

        result
    }
}

// Note: Grace period logic is not implemented in this validator.
// For grace period validation, use the LicenseEngine in engine.rs
// which provides more comprehensive validation including grace periods.

// Note: This validator does NOT perform cryptographic signature verification.
// For cryptographic validation, use the LicenseEngine which verifies
// digital signatures to ensure license integrity and authenticity.

// Note: Hardware fingerprint validation in this module only checks
// if a fingerprint is provided when required. Actual fingerprint
// verification (comparing against stored value) should be done
// server-side or using additional validation logic.