librnxengine 1.1.0

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

/// Core license data payload containing all license information.
///
/// This struct represents the actual data contained within a license,
/// excluding cryptographic signatures and metadata. It's the payload
/// that gets signed during license creation.
///
/// # Fields
/// - `license_id`: Unique identifier for this specific license instance
/// - `customer_id`: Identifier for the customer/organization
/// - `product_id`: Identifier for the licensed product
/// - `expires_at`: Date and time when the license becomes invalid
/// - `issued_at`: Date and time when the license was created
/// - `max_activations`: Maximum number of concurrent device activations allowed
/// - `features`: List of enabled product features
/// - `metadata`: Flexible JSON field for additional custom data
///
/// # Example JSON Representation
/// ```json
/// {
///   "license_id": "123e4567-e89b-12d3-a456-426614174000",
///   "customer_id": "customer-123",
///   "product_id": "product-pro",
///   "expires_at": "2024-12-31T23:59:59Z",
///   "issued_at": "2024-01-01T00:00:00Z",
///   "max_activations": 3,
///   "features": ["premium", "api-access", "support-24/7"],
///   "metadata": {"allowed_ips": ["192.168.1.1"], "version": "2.0"}
/// }
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LicensePayload {
    pub license_id: Uuid,
    pub customer_id: String,
    pub product_id: String,
    pub expires_at: DateTime<Utc>,
    pub issued_at: DateTime<Utc>,
    pub max_activations: u32,
    pub features: Vec<String>,
    pub metadata: serde_json::Value,
}

/// Complete license structure including cryptographic signature.
///
/// This is the main license object that gets distributed to end-users.
/// It contains both the license data (`payload`) and its digital signature
/// to ensure authenticity and integrity.
///
/// # Fields
/// - `version`: License format version (for backward compatibility)
/// - `payload`: The actual license data (see `LicensePayload`)
/// - `signature`: Cryptographic signature of the serialized payload
/// - `algorithm`: Algorithm used for signing (e.g., "ed25519")
///
/// # Security Notes
/// - The `signature` is computed over the serialized `payload`
/// - The `algorithm` field helps with future cryptographic migrations
/// - Always verify the signature before trusting the license data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct License {
    pub version: u32,
    pub payload: LicensePayload,
    pub signature: Vec<u8>,
    pub algorithm: String,
}

impl License {
    /// Returns the unique identifier for this license.
    ///
    /// This is a shortcut to access the UUID from the payload.
    ///
    /// # Returns
    /// The `license_id` UUID that uniquely identifies this license.
    pub fn license_id(&self) -> Uuid {
        self.payload.license_id
    }

    /// Returns the customer identifier associated with this license.
    ///
    /// # Returns
    /// A string slice containing the customer ID.
    pub fn customer_id(&self) -> &str {
        &self.payload.customer_id
    }

    /// Returns the product identifier for which this license is valid.
    ///
    /// # Returns
    /// A string slice containing the product ID.
    pub fn product_id(&self) -> &str {
        &self.payload.product_id
    }

    /// Returns the expiration date and time of the license.
    ///
    /// # Returns
    /// A UTC `DateTime` when the license expires.
    pub fn expires_at(&self) -> DateTime<Utc> {
        self.payload.expires_at
    }

    /// Returns a list of features enabled by this license.
    ///
    /// # Returns
    /// A slice of strings, each representing an enabled feature.
    ///
    /// # Example
    /// ```rust
    /// for feature in license.features() {
    ///     println!("Enabled feature: {}", feature);
    /// }
    /// ```
    pub fn features(&self) -> &[String] {
        &self.payload.features
    }

    /// Checks if a specific feature is enabled in this license.
    ///
    /// # Parameters
    /// - `feature`: The feature name to check (case-sensitive)
    ///
    /// # Returns
    /// - `true`: The feature is present in the license
    /// - `false`: The feature is not included
    ///
    /// # Example
    /// ```rust
    /// if license.has_feature("api-access") {
    ///     enable_api_features();
    /// }
    /// ```
    pub fn has_feature(&self, feature: &str) -> bool {
        self.payload.features.iter().any(|f| f == feature)
    }

    /// Checks if the license has expired based on current system time.
    ///
    /// # Returns
    /// - `true`: License expiration date is in the past
    /// - `false`: License is still valid (expiration in future)
    ///
    /// # Notes
    /// - Uses `Utc::now()` for comparison
    /// - Consider time zone differences when validating
    /// - This check doesn't consider grace periods
    pub fn is_expired(&self) -> bool {
        self.payload.expires_at < Utc::now()
    }

    /// Calculates how many days remain until license expiration.
    ///
    /// # Returns
    /// - Positive number: Days until expiration
    /// - Zero: Expires today
    /// - Negative number: Days since expiration
    ///
    /// # Notes
    /// - Returns full days (fractional days are truncated)
    /// - Negative values indicate expired licenses
    ///
    /// # Example
    /// ```rust
    /// match license.days_remaining() {
    ///     d if d > 30 => println!("License valid for {} days", d),
    ///     d if d > 0 => println!("License expires in {} days", d),
    ///     _ => println!("License has expired"),
    /// }
    /// ```
    pub fn days_remaining(&self) -> i64 {
        let now = Utc::now();
        let duration = self.payload.expires_at - now;
        duration.num_days()
    }
}

/// Structured representation of license features with typed values.
///
/// This provides a more structured alternative to the string-based
/// features list in `LicensePayload`. Useful for applications with
/// well-defined feature sets.
///
/// # Fields
/// - `premium`: Whether premium features are enabled
/// - `api_access`: Whether API access is allowed
/// - `max_users`: Maximum number of concurrent users
/// - `custom_domains`: Number of allowed custom domains
/// - `storage_gb`: Amount of storage in gigabytes
/// - `support_level`: Type of support included
/// - `expires_at`: Optional specific expiration for these features
///
/// # Example Usage
/// ```rust
/// let features = LicenseFeatures {
///     premium: true,
///     api_access: true,
///     max_users: 10,
///     custom_domains: 3,
///     storage_gb: 100,
///     support_level: "24/7".to_string(),
///     expires_at: Some(Utc::now() + chrono::Duration::days(365)),
/// };
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LicenseFeatures {
    pub premium: bool,
    pub api_access: bool,
    pub max_users: u32,
    pub custom_domains: u32,
    pub storage_gb: u32,
    pub support_level: String,
    pub expires_at: Option<DateTime<Utc>>,
}

// Note: The `License` struct implements `Serialize` and `Deserialize`
// for easy serialization to/from JSON, CBOR, or other formats.
// This is useful for:
// - Storing licenses in files or databases
// - Transmitting licenses over networks
// - Embedding licenses in configuration files

// Note: The `metadata` field in `LicensePayload` provides flexibility
// for custom extensions without modifying the core structure.
// Common uses include:
// - IP address restrictions
// - Geographic limitations
// - Version constraints
// - Custom business logic flags

// Note: UUIDs are used for identifiers to ensure global uniqueness
// and avoid collisions across distributed systems.

// Note: All timestamps use UTC to avoid timezone confusion
// and ensure consistent validation across different regions.