diff --git a/CHANGELOG.md b/CHANGELOG.md index 26d43c5..d38191d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,38 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/). --- +## [1.5.0] - 2025-11-27 + +### ✨ Añadido +- **Configuración Avanzada de IPs Administrativas por Segmento**: Sistema completo de gestión de rangos administrativos personalizados por segmento. + - Editor visual protegido por contraseña + - Configuración JSON por segmento + - Múltiples rangos iniciales y finales por segmento + - Interfaz amigable para gestionar rangos +- **Botón de Configuración Avanzada** (⚙️): Acceso rápido al editor desde la interfaz principal. +- **Modal de Autenticación**: Protección por contraseña para acceso al editor. +- **Fallback Inteligente**: Segmentos no configurados en JSON usan automáticamente rangos globales. + +### 🔧 Mejorado +- **AdminRangeHelper.php**: Nueva clase helper para procesar configuración JSON por segmento. +- **IpSearchService.php**: Lógica mejorada con soporte para rangos personalizados y fallback. +- **Validación de Cambios**: Advertencia al salir del editor con cambios sin guardar. + +### 🎨 Interfaz +- Editor visual completo con formularios dinámicos +- Tabla de segmentos configurados +- Agregar/eliminar rangos en tiempo real +- Diseño responsive con soporte para temas claro/oscuro + +## [1.4.0] - 2025-11-27 + +### ✨ Añadido +- **Rangos de IPs Administrativas Configurables**: Ahora puedes configurar qué rangos de IPs se consideran administrativas mediante 4 campos numéricos en la configuración del plugin (inicio/fin de rango inicial y final), en lugar de tener valores fijos (1-30 y 254). + +### 🔧 Mejorado +- **Flexibilidad**: Permite adaptar la clasificación de IPs según las necesidades específicas de cada red. +- **Backend y Frontend**: Toda la lógica de clasificación ahora usa configuración dinámica. + ## [1.3.3] - 2025-11-27 ### ✨ Añadido diff --git a/README.md b/README.md index ddf8e72..25ae358 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SIIP - Buscador de IP's Disponibles UISP -[![Version](https://img.shields.io/badge/version-1.3.3-blue.svg)](manifest.json) +[![Version](https://img.shields.io/badge/version-1.5.0-blue.svg)](manifest.json) [![UCRM](https://img.shields.io/badge/UCRM-Compatible-green.svg)](https://uisp.com/) [![UNMS](https://img.shields.io/badge/UNMS-Compatible-green.svg)](https://uisp.com/) @@ -93,6 +93,13 @@ Después de instalar el plugin, configura los siguientes parámetros: |-----------|-------------|-----| | **Token de la API UNMS** | Token de UNMS (34 caracteres) | Para búsqueda de IPs en dispositivos de red | | **Habilitar verificación por Ping** | Activa modo de verificación por ping | Permite verificar disponibilidad real de IPs | +| **Inicio primer rango admin** | Primera IP del rango administrativo inicial (default: 1) | Define el inicio del primer rango de IPs administrativas | +| **Fin primer rango admin** | Última IP del rango administrativo inicial (default: 30) | Define el fin del primer rango de IPs administrativas | +| **Inicio rango admin final** | Primera IP del rango administrativo final (default: 254) | Define el inicio del rango final de IPs administrativas | +| **Fin rango admin final** | Última IP del rango administrativo final (default: 254) | Define el fin del rango final de IPs administrativas | +| **Usar rangos personalizados por segmento** | Habilita configuración avanzada por segmento | Permite definir rangos específicos para cada segmento de red | +| **Configuración JSON de rangos** | JSON con rangos por segmento | Configuración detallada de rangos administrativos personalizados | +| **Contraseña de administrador** | Contraseña para editor avanzado | Protege el acceso al editor de configuración avanzada | | **Debug Mode** | Modo de depuración | Habilita logs más detallados | | **Enable debug logs** | Logs verbosos | Información adicional en logs | @@ -600,5 +607,5 @@ Este plugin es propiedad de **SIIP Internet**. Todos los derechos reservados. --- -**Versión**: 1.3.3 +**Versión**: 1.5.0 **Última actualización**: 27 de noviembre de 2025 diff --git a/data/config.json b/data/config.json index 68ba53a..ad9cf6c 100644 --- a/data/config.json +++ b/data/config.json @@ -1 +1 @@ -{"ipserver":"sistema.siip.mx","apitoken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","unmsApiToken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","debugMode":true,"logging_level":true,"enablePingVerification":true} \ No newline at end of file +{"ipserver":"sistema.siip.mx","apitoken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","unmsApiToken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","debugMode":true,"logging_level":true,"enablePingVerification":true,"adminRangeStart":"2","adminRangeEnd":"50","adminRangeFinalStart":"254","adminRangeFinalEnd":"255"} \ No newline at end of file diff --git a/data/plugin.log b/data/plugin.log index d11d15c..7787a17 100644 --- a/data/plugin.log +++ b/data/plugin.log @@ -3581,3 +3581,168 @@ Verificando lote de 1 IPs Iniciando verificación por ping de 1 IPs (lotes de 1) Procesando lote 1/1 (1 IPs) Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: GET +POST data: [] +GET data: [] +Content-Type: +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +Acceso a la interfaz pública de búsqueda de IPs +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"search","segment":"13","verify_ping":"false"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryd9c9bd779b06b9bab23d3ccee85be660 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de búsqueda AJAX +Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true} +Buscando IPs en segmento: 13 (Búsqueda inicial rápida) +URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Respuesta HTTP: 200 +Longitud de respuesta: 48923 bytes +IPs obtenidas exitosamente: 3106 direcciones +Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 153, En uso: 101 +Resultado de búsqueda: {"success":true,"ipsDisponibles":153,"ipsEnUso":101} +<<< Finalizando handler de búsqueda AJAX +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.13.31\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundary6eaecbebd5f8b555bb94571735b05c99 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.13.33\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryf35d820ad41ba3e6d10728762ee63d9 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.13.34\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryee78e7f8a9ba81f13ea3e610be045399 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.13.35\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundary8e80bfbb0ef83ea63233d967489cc33c +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.13.36\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundary59280d458af805620af084daa0eaea4 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: GET +POST data: [] +GET data: [] +Content-Type: +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +Acceso a la interfaz pública de búsqueda de IPs +=== NUEVA PETICIÓN === +Método: GET +POST data: [] +GET data: [] +Content-Type: +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +Acceso a la interfaz pública de búsqueda de IPs +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"search","segment":"100","verify_ping":"false"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundary5ddd3ee57a052d31763847c17daef50 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de búsqueda AJAX +Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true} +Buscando IPs en segmento: 100 (Búsqueda inicial rápida) +URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Respuesta HTTP: 200 +Longitud de respuesta: 48923 bytes +IPs obtenidas exitosamente: 3106 direcciones +Búsqueda de IPs en segmento 172.16.100.x - Disponibles: 123, En uso: 131 +Resultado de búsqueda: {"success":true,"ipsDisponibles":123,"ipsEnUso":131} +<<< Finalizando handler de búsqueda AJAX +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.100.55\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundary8344b24563663e659e7e20943555f60 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.100.57\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundary4d513f2e427d730558bc8fe000c66683 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.100.58\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryfeb931394f33d483c38cb8d49c83bab1 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.12s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.100.59\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundarye70755c6fad06c208f6ad0d8651cb811 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.12s) +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"verify_batch","ips":"[\"172.16.100.69\"]"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryc8832b02f5f8eb4a670c6cc46e34ce90 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de verificación por lotes (verify_batch) +Verificando lote de 1 IPs +Iniciando verificación por ping de 1 IPs (lotes de 1) +Procesando lote 1/1 (1 IPs) +Lote completado: 0/1 IPs responden (1.10s) diff --git a/manifest.json b/manifest.json index 2762fd9..f81ab69 100644 --- a/manifest.json +++ b/manifest.json @@ -5,7 +5,7 @@ "displayName": "SIIP - Buscador de IP's Disponibles UISP", "description": "Este plugin permite buscar IP's disponibles en UISP (UNMS) y asignarlas a los clientes en UCRM. Evitando así la asignación de IP's duplicadas y mejorando la gestión de direcciones IP en la red.", "url": "https://siip.mx", - "version": "1.3.3", + "version": "1.5.0", "ucrmVersionCompliancy": { "min": "1.0.0", "max": null @@ -58,6 +58,60 @@ "description": "Permite verificar la disponibilidad real de las IPs mediante ping. Cuando está habilitado, el usuario puede elegir si desea verificar las IPs con ping antes de mostrarlas como disponibles. Esto ayuda a detectar dispositivos no registrados en UISP.", "required": 0, "type": "checkbox" + }, + { + "key": "adminRangeStart", + "label": "Inicio primer rango admin", + "description": "Primera IP del rango administrativo inicial (ej: 1). Las IPs en este rango se marcarán como administrativas.", + "required": 0, + "type": "number", + "default": 1 + }, + { + "key": "adminRangeEnd", + "label": "Fin primer rango admin", + "description": "Última IP del rango administrativo inicial (ej: 30). Las IPs desde 'Inicio primer rango' hasta este valor se marcarán como administrativas.", + "required": 0, + "type": "number", + "default": 30 + }, + { + "key": "adminRangeFinalStart", + "label": "Inicio rango admin final", + "description": "Primera IP del rango administrativo final (ej: 254). Útil para reservar las últimas IPs del segmento.", + "required": 0, + "type": "number", + "default": 254 + }, + { + "key": "adminRangeFinalEnd", + "label": "Fin rango admin final", + "description": "Última IP del rango administrativo final (ej: 254). Las IPs desde 'Inicio rango final' hasta este valor se marcarán como administrativas.", + "required": 0, + "type": "number", + "default": 254 + }, + { + "key": "useCustomAdminRanges", + "label": "Usar rangos de IPs administrativas personalizados por segmento", + "description": "Habilita configuración personalizada por segmento en lugar de rangos globales. Permite definir rangos específicos para cada segmento de red.", + "required": 0, + "type": "checkbox" + }, + { + "key": "customAdminRangesJson", + "label": "Configuración JSON de rangos administrativos", + "description": "JSON con rangos administrativos por segmento. Formato: {\"segmentos\": [{\"segmento\": \"18\", \"administrativas_iniciales\": [{\"inicio\": 1, \"hasta\": 50}], \"administrativas_finales\": [{\"inicio\": 253, \"hasta\": 255}]}]}", + "required": 1, + "type": "textarea", + "default": "{\"segmentos\":[]}" + }, + { + "key": "adminPassword", + "label": "Contraseña de administrador para configuración avanzada", + "description": "Contraseña requerida para acceder al editor visual de configuración avanzada de rangos administrativos.", + "required": 1, + "type": "password" } ], "menu": [ diff --git a/public.php b/public.php index 81e2b73..6781937 100644 --- a/public.php +++ b/public.php @@ -30,12 +30,43 @@ require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/src/IpSearchService.php'; require_once __DIR__ . '/src/PingService.php'; require_once __DIR__ . '/src/ApiHandlers.php'; +require_once __DIR__ . '/src/AdminRangeHelper.php'; use Ubnt\UcrmPluginSdk\Service\PluginLogManager; use Ubnt\UcrmPluginSdk\Service\PluginConfigManager; +use Ubnt\UcrmPluginSdk\Service\UcrmApi; use SiipAvailableIps\IpSearchService; use SiipAvailableIps\PingService; +// Manejo de errores para el handler de configuración avanzada +error_reporting(E_ALL); +ini_set('display_errors', 1); + +// Handler para guardar configuración avanzada +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_advanced_config'])) { + try { + $jsonData = $_POST['save_advanced_config']; + + // Validar JSON + $validation = \SiipAvailableIps\AdminRangeHelper::validateConfigJson($jsonData); + if (!$validation['valid']) { + die('Error: ' . $validation['error']); + } + + // Guardar en config.json + $configManager = PluginConfigManager::create(); + $config = $configManager->loadConfig(); + $config['customAdminRangesJson'] = $jsonData; + $configManager->saveConfig($config); + + // Redirigir con mensaje de éxito + header('Location: ?success=1'); + exit; + } catch (Exception $e) { + die('Error al guardar configuración: ' . $e->getMessage()); + } +} + // Get UCRM log manager $log = PluginLogManager::create(); @@ -843,18 +874,313 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing right: 15px; } } + + /* Botón de configuración avanzada */ + .config-toggle { + position: fixed; + top: 20px; + right: 20px; + width: 50px; + height: 50px; + border-radius: 50%; + background: var(--card-bg); + border: 2px solid var(--card-border); + color: var(--text-primary); + font-size: 1.5rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + box-shadow: var(--shadow-lg); + z-index: 1001; + } + + .config-toggle:hover { + transform: scale(1.1) rotate(90deg); + box-shadow: var(--shadow-xl); + } + + /* Ajustar posición del botón de tema */ + .theme-toggle { + top: 80px; /* Debajo del botón de configuración */ + } + + /* Modal de contraseña */ + .modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + z-index: 2000; + align-items: center; + justify-content: center; + } + + .modal-content { + background: var(--card-bg); + border: 2px solid var(--card-border); + border-radius: 16px; + padding: 40px; + max-width: 400px; + width: 90%; + box-shadow: var(--shadow-xl); + text-align: center; + } + + .modal-content h3 { + margin-bottom: 10px; + color: var(--text-primary); + } + + .modal-content p { + color: var(--text-secondary); + margin-bottom: 20px; + } + + .modal-input { + width: 100%; + padding: 12px; + border: 2px solid var(--card-border); + border-radius: 8px; + background: rgba(255, 255, 255, 0.05); + color: var(--text-primary); + font-size: 1rem; + margin-bottom: 20px; + } + + .modal-actions { + display: flex; + gap: 10px; + justify-content: center; + } + + /* Editor Visual */ + .advanced-editor { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--dark-bg); + z-index: 1500; + overflow-y: auto; + padding: 20px; + } + + .editor-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30px; + padding: 20px; + background: var(--card-bg); + border: 1px solid var(--card-border); + border-radius: 16px; + } + + .editor-header h2 { + margin: 0; + color: var(--text-primary); + } + + .editor-content { + max-width: 1200px; + margin: 0 auto; + } + + .add-segment-form { + padding: 20px 0; + } + + .form-row { + display: flex; + gap: 20px; + margin-bottom: 20px; + } + + .range-input-group { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 10px; + } + + .range-input-group input { + width: 100px; + padding: 8px; + border: 2px solid var(--card-border); + border-radius: 8px; + background: rgba(255, 255, 255, 0.05); + color: var(--text-primary); + } + + .range-input-group span { + color: var(--text-secondary); + } + + .btn-small { + padding: 6px 12px; + font-size: 0.85rem; + background: rgba(102, 126, 234, 0.2); + border: 1px solid rgba(102, 126, 234, 0.3); + border-radius: 8px; + color: #667eea; + cursor: pointer; + transition: all 0.2s ease; + } + + .btn-small:hover { + background: rgba(102, 126, 234, 0.3); + transform: translateY(-2px); + } + + .editor-actions { + display: flex; + gap: 15px; + justify-content: center; + margin-top: 30px; + } + + @media (max-width: 768px) { + .config-toggle { + width: 45px; + height: 45px; + font-size: 1.3rem; + top: 15px; + right: 15px; + } + + .theme-toggle { + top: 70px; + } + + .modal-content { + padding: 30px 20px; + } + + .editor-header { + flex-direction: column; + gap: 15px; + } + + .form-row { + flex-direction: column; + } + + .range-input-group { + flex-wrap: wrap; + } + } + + + + + + + + + +

Buscador de IPs Disponibles

Sistema de gestión de direcciones IP para UISP

+ +
+ ✅ Configuración avanzada guardada exitosamente +
+
@@ -957,6 +1283,14 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing