Saltar al contenido principal

🦀 SDK Oficial para Rust (Manual Técnico & API de Métodos)

El crate oficial validlicense_rs está diseñado para aplicaciones nativas de ultra-alto rendimiento, bajo consumo de memoria y máxima seguridad en Rust. Implementa el algoritmo Ed25519 utilizando el crate auditado ed25519-dalek con soporte para Tokio Async.


🏛️ 1. Estructuras de Datos y Tipos​

ValidLicenseOptions<'a>​

Opciones de configuración del cliente:

pub struct ValidLicenseOptions<'a> {
pub server_url: &'a str, // URL base del servidor VPS (ej: "https://licencias.labtec.sbs")
pub public_key_hex: Option<&'a str>, // Clave Pública Ed25519 en formato hexadecimal (64 caracteres)
pub client_version: Option<&'a str>, // Versión del software cliente (por defecto "2026.1")
pub timeout: Option<Duration>, // Timeout de red (por defecto 6 segundos)
}

ValidLicenseRecord​

Estructura inmutable con el estado de la licencia:

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidLicenseRecord {
pub is_active: bool, // true si la licencia está vigente y autorizada
pub status: String, // "ACTIVE", "SUSPENDED", "EXPIRED", "REVOKED"
pub company_name: String, // Razón social de la empresa cliente
pub company_nit: Option<String>, // NIT o documento tributario
pub plan: String, // Nombre comercial del plan contratado
pub expires_at: String, // Timestamp ISO 8601 de expiración
pub days_left: i64, // Días enteros restantes
pub is_trial: bool, // true si es licencia de prueba
pub max_users: usize, // Límite de usuarios simultáneos
pub dian_quota: usize, // Cuota de documentos electrónicos DIAN
pub dian_used: usize, // Facturas emitidas en el período
pub features: Vec<String>, // Módulos contratados
pub custom_data: HashMap<String, serde_json::Value>, // Metadatos personalizados
pub server_message: String, // Mensaje de respuesta del servidor
pub token: Option<String>, // Token criptográfico firmado
}

⚙️ 2. Métodos de ValidLicenseClient​

ValidLicenseClient::new(options: ValidLicenseOptions) -> Self​

Inicializa el cliente creando una instancia de reqwest::Client con pooling de conexiones y timeouts configurados.


pub fn get_machine_id(&self) -> String​

  • Propósito: Retorna la huella única de hardware del equipo en formato REX-XXXX-XXXX-XXXX.
  • Implementación por Plataforma:
    • Windows (#[cfg(target_os = "windows")]): Lee MachineGuid de HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography mediante winreg o reg.exe.
    • Linux (#[cfg(target_os = "linux")]): Lee /etc/machine-id o /var/lib/dbus/machine-id.
    • macOS (#[cfg(target_os = "macos")]): Consulta IOPlatformUUID vía ioreg.
    • Calcula un hash sha2::Sha256 y devuelve la cadena formateada.

pub fn verify_token_signature(&self, token: &str) -> bool​

  • Propósito: Valida la autenticidad matemática de la firma Ed25519 del token de forma offline.
  • Implementación:
    • Convierte los 64 caracteres de la clave pública hex en 32 bytes y construye un ed25519_dalek::VerifyingKey.
    • Convierte los 128 caracteres de la firma hex en un ed25519_dalek::Signature.
    • Ejecuta la verificación estricta verifying_key.verify_strict(payload_bytes, &signature).

pub async fn verify(...) -> Result<ValidLicenseRecord, Box<dyn std::error::Error>>​

  • Propósito: Ejecuta la verificación en dos fases:
    1. Fase 1 (Online): Realiza una petición asíncrona HTTPS no bloqueante al servidor VPS. Si responde 200 OK, actualiza los privilegios y renueva el token.
    2. Fase 2 (Fallback Offline): Si la conexión falla, decodifica el token local con verify_token_signature y valida la fecha de vencimiento expires_at.

pub fn has_feature(&self, feature: &str) -> bool​

  • Propósito: Retorna true si el módulo solicitado está habilitado en el vector features del registro.

🛡️ 3. Módulo AntiTamperHelper en Rust​

Herramientas para fortificar binarios en Rust contra ingeniería inversa:

  • AntiTamperHelper::derive_encryption_key(raw_token, salt):
    • Deriva una clave AES-256 a partir de la firma Ed25519 para descifrar bases de datos locales o estructuras en memoria.
  • AntiTamperHelper::verify_clock_integrity(last_iso, checksum, run_count, machine_id, salt, tolerance):
    • Comprueba que el reloj del sistema operativo no haya sido atrasado deliberadamente.
  • AntiTamperHelper::is_debugger_attached():
    • Detecta si el proceso Rust está siendo interceptado por depuradores o trazadores (/proc/self/status TracerPid).

🔒 4. Módulo UiGuard (Protección Universal de Vistas & Frontend)​

UiGuard permite blindar tanto vistas nativas en Rust (ui_ventas.rs, egui, iced, slint, dioxus) como páginas de frameworks web embebidos en Tauri (React PageVenta.tsx, Angular PageVenta.component.html, Vue PageVenta.vue).

A. Para Vistas Nativas en Rust (ui_ventas.rs, egui, iced, slint)​

Pasa directamente la función de renderizado de tu módulo de interfaz. Si la licencia no es válida, el código de la vista jamás se ejecuta:

// Modulo: ui_ventas.rs
use validlicense_rs::UiGuard;

// 1. Proteger una vista completa
let view_output = UiGuard::guard_view(
&license,
|| ui_ventas::render_panel_ventas(), // Se ejecuta solo si la licencia es válida
|| ui_ventas::render_pantalla_bloqueo(), // Fallback si no está activa
);

// 2. Proteger por Feature Flag (ej: Módulo Facturación Electrónica DIAN)
let dian_panel = UiGuard::guard_feature(
&license,
"electronic_billing",
|| ui_ventas::render_facturacion_dian(),
|| ui_ventas::render_modulo_no_contratado(),
);

B. Para Tauri con React (PageVenta.tsx), Angular o Vue (PageVenta.vue)​

Incrusta los archivos compilados del frontend en el ejecutable y filtra la entrega:

use validlicense_rs::UiGuard;

// Para React (PageVenta.tsx / index.html compilado en dist)
let page_venta_bundle = include_str!("../dist/PageVenta.html");
let final_page = UiGuard::guard_asset(&license, page_venta_bundle, None);

// Para Angular (PageVenta.component.html) o Vue (PageVenta.vue compilado)
// Si la licencia no es válida, entrega la pantalla de bloqueo nativa segura
window.eval(&UiGuard::generate_purge_script("Licencia vencida", &license.machine_id)).ok();

💻 5. Ejemplo Completo en Rust & Tauri​

use validlicense_rs::{ValidLicenseClient, ValidLicenseOptions, UiGuard};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Configurar cliente
let client = ValidLicenseClient::new(ValidLicenseOptions {
server_url: "https://licencias.labtec.sbs",
public_key_hex: Some("C7B785E80D3F08E41993FEA44B702C4F361D90A5235C19C438C6B67F02FA891D"),
client_version: Some("2026.1"),
timeout: None,
});

// 2. Obtener Machine ID
let machine_id = client.get_machine_id();
println!("🔒 Hardware ID: {}", machine_id);

// 3. Verificar Licencia
let license = client.verify(
Some("900.888.777-1"),
Some("Comercializadora Global SAS"),
Some("TOKEN_GUARDADO_LOCAL"),
None,
).await?;

if !license.is_active {
eprintln!("❌ Acceso Denegado: {}", license.server_message);
std::process::exit(1);
}

println!("✅ Licencia Autorizada para: {}", license.company_name);
println!("📦 Plan: {} | Válida hasta: {} ({} días restantes)", license.plan, license.expires_at, license.days_left);
println!("📑 Cuota DIAN: {} / {}", license.dian_used, license.dian_quota);

// 4. Proteger vistas con UiGuard
let html_to_render = UiGuard::guard_asset(&license, include_str!("../dist/index.html"), None);
println!("Contenido protegido generado: {} bytes", html_to_render.len());

Ok(())
}