🦀 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")]): LeeMachineGuiddeHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptographymediantewinregoreg.exe. - Linux (
#[cfg(target_os = "linux")]): Lee/etc/machine-ido/var/lib/dbus/machine-id. - macOS (
#[cfg(target_os = "macos")]): ConsultaIOPlatformUUIDvíaioreg. - Calcula un hash
sha2::Sha256y devuelve la cadena formateada.
- Windows (
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).
- Convierte los 64 caracteres de la clave pública hex en 32 bytes y construye un
pub async fn verify(...) -> Result<ValidLicenseRecord, Box<dyn std::error::Error>>
- Propósito: Ejecuta la verificación en dos fases:
- 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. - Fase 2 (Fallback Offline): Si la conexión falla, decodifica el token local con
verify_token_signaturey valida la fecha de vencimientoexpires_at.
- Fase 1 (Online): Realiza una petición asíncrona HTTPS no bloqueante al servidor VPS. Si responde
pub fn has_feature(&self, feature: &str) -> bool
- Propósito: Retorna
truesi el módulo solicitado está habilitado en el vectorfeaturesdel 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/statusTracerPid).
- Detecta si el proceso Rust está siendo interceptado por depuradores o trazadores (
🔒 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(())
}