feat(license): registration + 1-year licenses + tier scaffolding
A complete offline licensing layer (no internet at any step): Core - src/license/ — schema (License, Tier, FeatureFlag), HMAC crypto, JSON storage, LicenseManager singleton with activate/renew/ deactivate/issue_trial. Tier-scaffolded so future SKUs can carve per-tool feature sets without consumer-code edits. - scripts/generate_license.py — creator-only key generator. Mints a DTLIC1: blob the buyer pastes into the activation page. GUI - New activation form component (src/gui/components/activation.py). - hide_streamlit_chrome() now inline-renders the activation form when no valid license is present (every page short-circuits to the form until activated). - Sidebar shows tier + days remaining; renewal warning under 30 days. - New pages/_Activate.py for revisiting the form after activation. CLI - src/license_cli.py — activate / renew / status / trial / deactivate commands. Exempt from the guard. - src/cli_license_guard.py — drop-in guard call added to every tool CLI's main(). Lets --help through; respects DATATOOLS_DEV_MODE. i18n - New activation.* and license.* keys in en.json + es.json (page title, form labels, status badges, renewal warnings, error messages). Pack parity test stays green. Test infrastructure - tests/conftest.py autouse fixture sets DATATOOLS_DEV_MODE=1 so the existing 1916 tests continue to pass. - isolated_license_path / activated_license_manager / unactivated_license_manager fixtures for tests that want to drive the real check. Tests (+79) - tests/test_license.py (40): schema, crypto roundtrip, blob encode/decode, tier→feature mapping, activation flow, name/email mismatch rejection, tamper detection, expiration, renewal, dev-mode bypass. - tests/test_license_cli.py (26): every license_cli command + subprocess tests confirming every tool CLI refuses to run without a license, --help always works, DEV_MODE bypasses. - tests/gui/test_activation.py (13): gate blocks without license, passes with trial, activation form submission unlocks the gate, sidebar status, renewal warning, i18n. Total: 1916 → 1995 tests. All pass under the strict warning filter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,44 @@
|
||||
"body": "Al pulsar el botón de abajo se cerrará el servidor de DataTools. Cualquier trabajo sin guardar en otras herramientas se perderá. Una vez cerrada la app, puedes cerrar esta ventana.",
|
||||
"button": "Cerrar la app"
|
||||
},
|
||||
"activation": {
|
||||
"page_title": "DataTools — Activar",
|
||||
"title": "🔑 Activar DataTools",
|
||||
"intro": "DataTools debe activarse antes de desbloquear cualquier herramienta. Introduce el nombre y correo asociados a tu compra, y luego pega el código de licencia del correo de entrega.",
|
||||
"name_label": "Nombre completo",
|
||||
"name_help": "Debe coincidir con el nombre en el recibo de compra.",
|
||||
"email_label": "Correo electrónico",
|
||||
"email_help": "Debe coincidir con el correo del recibo de compra.",
|
||||
"blob_label": "Código de licencia",
|
||||
"blob_help": "Empieza con `DTLIC1:` — pega la cadena completa.",
|
||||
"activate_button": "Activar",
|
||||
"renew_button": "Aplicar renovación",
|
||||
"trial_button": "Iniciar prueba de 1 año",
|
||||
"trial_help": "Omite el código de pago y emite una licencia local de 1 año vinculada a tu nombre y correo. Útil para evaluar antes de comprar.",
|
||||
"or_separator": "— o —",
|
||||
"success": "¡Activado! Bienvenido, {name}. Tu licencia es válida hasta el {expires}.",
|
||||
"renewed": "Licencia renovada. Nueva fecha de caducidad: {expires}.",
|
||||
"errors_heading": "Problema al activar",
|
||||
"deactivate_button": "Desactivar este dispositivo",
|
||||
"deactivate_help": "Elimina el archivo de licencia local. Tendrás que volver a pegar tu código para reactivarla."
|
||||
},
|
||||
"license": {
|
||||
"status_active": "{tier} · {days} días restantes",
|
||||
"status_trial": "Prueba · {days} días restantes",
|
||||
"status_expired": "Caducada",
|
||||
"status_not_activated": "Sin activar",
|
||||
"status_invalid": "Licencia inválida",
|
||||
"renewal_warning_30": "⚠️ La licencia caduca en {days} días. Renueva pronto para evitar interrupciones.",
|
||||
"renewal_warning_expired": "🛑 La licencia caducó el {date}. Renuévala para seguir usando DataTools.",
|
||||
"tier_trial": "Prueba",
|
||||
"tier_core": "Core",
|
||||
"tier_pro": "Pro",
|
||||
"tier_enterprise": "Enterprise",
|
||||
"registered_to": "Registrado a nombre de {name} · {email}",
|
||||
"expires_on": "Caduca el {date}",
|
||||
"issued_on": "Emitida el {date}",
|
||||
"view_details": "Detalles de la licencia"
|
||||
},
|
||||
"tools": {
|
||||
"01_deduplicator": {
|
||||
"name": "Eliminador de duplicados",
|
||||
|
||||
Reference in New Issue
Block a user