librnxengine 1.1.0

implement robust software licensing, activation, and validation systems.
Documentation
use serde::{Deserialize, Serialize};
use thiserror::Error;

/// Comprehensive error enumeration for the license management system.
///
/// This enum defines all possible error conditions that can occur during
/// license operations, including validation, activation, cryptography,
/// serialization, and network operations. Each variant includes human-readable
/// error messages and can be serialized for API responses or logging.
///
/// # Variants
/// The error types are categorized into logical groups:
/// - Cryptographic errors
/// - License validation errors
/// - Activation and hardware errors
/// - Network and server errors
/// - Serialization and I/O errors
/// - Configuration and state errors
#[derive(Error, Debug, Clone, Serialize, Deserialize)]
pub enum LicenseError {
    /// Cryptographic operation failure.
    ///
    /// Occurs when cryptographic operations (signing, verification, key generation)
    /// fail due to invalid parameters, unsupported algorithms, or internal errors.
    ///
    /// # Example Causes
    /// - Invalid key format or length
    /// - Unsupported cryptographic algorithm
    /// - Failed random number generation
    #[error("Crypto error: {0}")]
    CryptoError(String),

    /// Digital signature validation failure.
    ///
    /// Indicates that a license's digital signature could not be verified,
    /// suggesting the license may have been tampered with or is corrupt.
    ///
    /// # Example Causes
    /// - Invalid signature format
    /// - Mismatched public key
    /// - Corrupted license data
    /// - Signature algorithm mismatch
    #[error("Signature validation failed")]
    SignatureValidationFailed,

    /// General license validation failure.
    ///
    /// Covers various validation issues not captured by more specific variants.
    /// Includes detailed error message explaining the validation failure.
    ///
    /// # Example Causes
    /// - Missing required license fields
    /// - Invalid license structure
    /// - License violates business rules
    #[error("License validation failed: {0}")]
    ValidationFailed(String),

    /// License is invalid for use.
    ///
    /// Indicates the license exists but cannot be used in the current context.
    /// More specific than `ValidationFailed` for cases where the license
    /// structure is valid but content is not.
    ///
    /// # Example Causes
    /// - License issued for different product
    /// - License not yet active (future start date)
    /// - License violates usage terms
    #[error("Invalid license: {0}")]
    InvalidLicense(String),

    /// License has expired.
    ///
    /// The license's expiration date has passed and no grace period remains.
    /// Requires renewal or new license issuance.
    #[error("License expired")]
    LicenseExpired,

    /// License has been revoked.
    ///
    /// The license was valid but has been explicitly revoked by the issuer,
    /// typically due to terms violation, non-payment, or security concerns.
    ///
    /// # Note
    /// Requires server-side revocation list check to detect.
    #[error("License revoked")]
    LicenseRevoked,

    /// Maximum activation limit reached.
    ///
    /// The license has reached its maximum allowed number of concurrent
    /// device activations. Requires deactivation of existing devices or
    /// license upgrade.
    ///
    /// # Example
    /// License allows 5 activations, but 6 devices are trying to use it.
    #[error("Activation limit exceeded")]
    ActivationLimitExceeded,

    /// Hardware fingerprint mismatch.
    ///
    /// Occurs when attempting to activate or validate a license on a device
    /// with different hardware than originally activated. Prevents license
    /// sharing between different machines.
    ///
    /// # Example Causes
    /// - License activated on different computer
    /// - Major hardware changes (new motherboard)
    /// - Attempting to use virtual machine clone
    #[error("Hardware binding mismatch")]
    HardwareBindingMismatch,

    /// Offline validation attempted when not permitted.
    ///
    /// The license requires online validation but the system is offline.
    /// Occurs when `allow_offline` is false and network connectivity is unavailable.
    #[error("Offline validation not allowed")]
    OfflineNotAllowed,

    /// Server-side error during license operations.
    ///
    /// Indicates an error occurred on the license server during activation,
    /// validation, or revocation checks. Typically includes server-provided
    /// error message.
    ///
    /// # Example Causes
    /// - Server database error
    /// - Authentication failure
    /// - Internal server error (500)
    #[error("Server error: {0}")]
    ServerError(String),

    /// Network communication failure.
    ///
    /// Occurs when network requests to license servers fail due to connectivity
    /// issues, timeouts, or DNS problems.
    ///
    /// # Example Causes
    /// - Network unreachable
    /// - Connection timeout
    /// - SSL/TLS handshake failure
    /// - DNS resolution failure
    #[error("Network error: {0}")]
    NetworkError(String),

    /// Data serialization failure.
    ///
    /// Failed to serialize license data to a specific format (JSON, CBOR, etc.).
    /// Typically indicates programming error or data corruption.
    ///
    /// # Example Causes
    /// - Circular references in data
    /// - Unserializable data types
    /// - Encoding issues
    #[error("Serialization error: {0}")]
    SerializationError(String),

    /// Data deserialization failure.
    ///
    /// Failed to parse serialized license data. Indicates corrupted, malformed,
    /// or version-incompatible license files.
    ///
    /// # Example Causes
    /// - Invalid JSON/CBOR syntax
    /// - Missing required fields
    /// - Type mismatch in serialized data
    /// - Version incompatibility
    #[error("Deserialization error: {0}")]
    DeserializationError(String),

    /// File I/O operation failure.
    ///
    /// Occurs when reading from or writing to filesystem fails during
    /// license operations (loading, saving, etc.).
    ///
    /// # Example Causes
    /// - File not found
    /// - Permission denied
    /// - Disk full
    /// - File locked by another process
    #[error("IO error: {0}")]
    IoError(String),

    /// Configuration error.
    ///
    /// Indicates invalid or missing configuration required for license
    /// operations. Helps debug deployment and setup issues.
    ///
    /// # Example Causes
    /// - Missing API endpoint URL
    /// - Invalid validation settings
    /// - Missing required environment variables
    #[error("Configuration error: {0}")]
    ConfigError(String),

    /// License not found in storage.
    ///
    /// The requested license could not be located in the local storage
    /// or cache. Different from `InvalidLicense` which means the license
    /// exists but is invalid.
    #[error("License not found")]
    LicenseNotFound,

    /// Invalid activation token.
    ///
    /// The provided activation token is malformed, expired, or doesn't
    /// match any known activation. Used for server-client activation flow.
    #[error("Invalid activation token")]
    InvalidActivationToken,

    /// Grace period has expired.
    ///
    /// The license's grace period (allowed usage after expiration) has ended.
    /// Final state before complete license deactivation.
    #[error("Grace period expired")]
    GracePeriodExpired,
}

/// Automatic conversion from `std::io::Error` to `LicenseError`.
///
/// Allows using `?` operator with I/O operations that may fail, automatically
/// converting `std::io::Error` into `LicenseError::IoError`.
impl From<std::io::Error> for LicenseError {
    fn from(err: std::io::Error) -> Self {
        LicenseError::IoError(err.to_string())
    }
}

/// Automatic conversion from `serde_json::Error` to `LicenseError`.
///
/// Enables seamless error handling when working with JSON serialization
/// using the `serde_json` crate. Converts JSON parsing/formatting errors
/// to appropriate license errors.
impl From<serde_json::Error> for LicenseError {
    fn from(err: serde_json::Error) -> Self {
        LicenseError::SerializationError(err.to_string())
    }
}

/// Automatic conversion from `serde_cbor::Error` to `LicenseError`.
///
/// Provides error conversion for CBOR (Concise Binary Object Representation)
/// serialization operations. Useful for binary license formats.
impl From<serde_cbor::Error> for LicenseError {
    fn from(err: serde_cbor::Error) -> Self {
        LicenseError::SerializationError(err.to_string())
    }
}

/// Automatic conversion from `reqwest::Error` to `LicenseError`.
///
/// Converts HTTP client errors from the `reqwest` crate to network-related
/// license errors. Enables clean error handling for web API calls.
impl From<reqwest::Error> for LicenseError {
    fn from(err: reqwest::Error) -> Self {
        LicenseError::NetworkError(err.to_string())
    }
}

// Note: The `thiserror` crate automatically implements `std::error::Error`
// trait for the enum, providing comprehensive error handling capabilities
// including source chain, backtraces (with std backtrace feature), and
// Display formatting via the `#[error(...)]` attributes.

// Note: The `Serialize` and `Deserialize` implementations allow these errors
// to be easily transmitted over network APIs or stored in logs. This is
// particularly useful for:
// - Client-server error reporting
// - Log aggregation and analysis
// - Remote debugging and diagnostics

// Note: The `Clone` implementation enables error propagation without
// consuming the original error, which is useful in async contexts or
// when errors need to be logged and returned.

// Note: Error variants are designed to be actionable:
// - `LicenseExpired`: Suggest renewal
// - `ActivationLimitExceeded`: Suggest deactivating old devices
// - `HardwareBindingMismatch`: Suggest contacting support
// - `OfflineNotAllowed`: Suggest checking network connection

// Note: For production use, consider adding:
// 1. Error codes for machine-readable error identification
// 2. More context fields (e.g., license_id, timestamp)
// 3. Help links or documentation references
// 4. Retry guidance for transient errors
// 5. Localization support for error messages

// Example usage pattern:
// ```
// fn load_license(path: &Path) -> Result<License, LicenseError> {
//     let data = std::fs::read(path)?;  // Converts io::Error automatically
//     let license: License = serde_json::from_slice(&data)?;  // Converts serde_json::Error
//     Ok(license)
// }
// ```

// Error recovery strategies by variant:
// - `LicenseExpired`: Check for grace period, prompt renewal
// - `NetworkError`: Implement retry with exponential backoff
// - `ActivationLimitExceeded`: Provide device management interface
// - `HardwareBindingMismatch`: Allow manual override with verification
// - `OfflineNotAllowed`: Cache validation results temporarily