fix(v1.5.0): Correcciones críticas en configuración avanzada de IPs
- Corregida inicialización de editorData que impedía cargar rangos personalizados - Corregidos errores de escape JS que rompían botones de la interfaz - Corregida clasificación frontend que ignoraba rangos específicos por segmento - Agregado indicador visual de modo y logs de depuración - Eliminada columna redundante en tabla de resultados Resuelve problemas donde los rangos admin personalizados eran ignorados.
This commit is contained in:
parent
1b821410c1
commit
6a0e15447c
15
CHANGELOG.md
15
CHANGELOG.md
@ -18,17 +18,32 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/).
|
|||||||
- **Botón de Configuración Avanzada** (⚙️): Acceso rápido al editor desde la interfaz principal.
|
- **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.
|
- **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.
|
- **Fallback Inteligente**: Segmentos no configurados en JSON usan automáticamente rangos globales.
|
||||||
|
- **Indicador Visual de Modo**: Badge que muestra si está activo "Rangos Personalizados" o "Rangos Globales".
|
||||||
|
- **Logs de Depuración**: Mensajes detallados en consola para diagnosticar clasificación de IPs.
|
||||||
|
|
||||||
### 🔧 Mejorado
|
### 🔧 Mejorado
|
||||||
- **AdminRangeHelper.php**: Nueva clase helper para procesar configuración JSON por segmento.
|
- **AdminRangeHelper.php**: Nueva clase helper para procesar configuración JSON por segmento.
|
||||||
- **IpSearchService.php**: Lógica mejorada con soporte para rangos personalizados y fallback.
|
- **IpSearchService.php**: Lógica mejorada con soporte para rangos personalizados y fallback.
|
||||||
|
- Configuración inyectada en constructor para consistencia
|
||||||
|
- Rangos dinámicos en lugar de hardcodeados
|
||||||
|
- Logs de depuración opcionales con `debugMode`
|
||||||
- **Validación de Cambios**: Advertencia al salir del editor con cambios sin guardar.
|
- **Validación de Cambios**: Advertencia al salir del editor con cambios sin guardar.
|
||||||
|
- **Tabla de Resultados**: Eliminada columna redundante "Tipo de IP" en escritorio, badge ahora aparece junto a la IP.
|
||||||
|
- **Inicialización de Datos**: `editorData` se carga correctamente al inicio para asegurar que los rangos personalizados se apliquen inmediatamente.
|
||||||
|
|
||||||
|
### 🐛 Corregido
|
||||||
|
- **Error de Escape de Strings**: Reemplazado `addslashes()` por `json_encode()` para variables PHP en JavaScript, evitando errores de sintaxis.
|
||||||
|
- **Guardado de Configuración**: Implementada escritura directa a `config.json` debido a limitaciones del SDK de UCRM.
|
||||||
|
- **Clasificación de IPs en Frontend**: Función `getIpType()` ahora respeta rangos personalizados por segmento, no solo globales.
|
||||||
|
- **Carga de Configuración Personalizada**: Corregido bug crítico donde `editorData` se inicializaba vacío y nunca se cargaba hasta abrir el editor, causando que los rangos personalizados fueran ignorados.
|
||||||
|
- **Comparación de Segmentos**: Mejorada robustez con conversión explícita a string y trim para evitar fallos por espacios o tipos de datos.
|
||||||
|
|
||||||
### 🎨 Interfaz
|
### 🎨 Interfaz
|
||||||
- Editor visual completo con formularios dinámicos
|
- Editor visual completo con formularios dinámicos
|
||||||
- Tabla de segmentos configurados
|
- Tabla de segmentos configurados
|
||||||
- Agregar/eliminar rangos en tiempo real
|
- Agregar/eliminar rangos en tiempo real
|
||||||
- Diseño responsive con soporte para temas claro/oscuro
|
- Diseño responsive con soporte para temas claro/oscuro
|
||||||
|
- Valor por defecto de 254 para rangos finales (optimización UX)
|
||||||
|
|
||||||
## [1.4.0] - 2025-11-27
|
## [1.4.0] - 2025-11-27
|
||||||
|
|
||||||
|
|||||||
35
README.md
35
README.md
@ -98,10 +98,12 @@ Después de instalar el plugin, configura los siguientes parámetros:
|
|||||||
| **Inicio rango admin final** | Primera IP del rango administrativo final (default: 254) | Define el inicio del rango final 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 |
|
| **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 |
|
| **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 |
|
| **Configuración JSON de rangos** | JSON con rangos por segmento | Configuración detallada de rangos administrativos personalizados (se gestiona desde el editor visual) |
|
||||||
| **Contraseña de administrador** | Contraseña para editor avanzado | Protege el acceso al editor de configuración avanzada |
|
| **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 |
|
| **Debug Mode** | Modo de depuración | Habilita logs detallados en consola del navegador para diagnóstico |
|
||||||
| **Enable debug logs** | Logs verbosos | Información adicional en logs |
|
| **Enable debug logs** | Logs verbosos | Información adicional en logs del servidor |
|
||||||
|
|
||||||
|
> **💡 Tip**: Para configurar rangos personalizados por segmento, marca el checkbox "Usar rangos personalizados por segmento" y haz clic en el botón ⚙️ (Configuración Avanzada) en la interfaz principal. Necesitarás la contraseña de administrador configurada.
|
||||||
|
|
||||||
### Cómo obtener los tokens:
|
### Cómo obtener los tokens:
|
||||||
|
|
||||||
@ -178,6 +180,31 @@ Durante la verificación por ping, aparece un botón **"🛑 Cancelar Verificaci
|
|||||||
3. Las IPs ya verificadas permanecen en la tabla.
|
3. Las IPs ya verificadas permanecen en la tabla.
|
||||||
4. El botón desaparece al finalizar o cancelar.
|
4. El botón desaparece al finalizar o cancelar.
|
||||||
|
|
||||||
|
### ⚙️ Configuración Avanzada de Rangos por Segmento
|
||||||
|
|
||||||
|
A partir de la versión 1.5.0, puedes definir rangos de IPs administrativas específicos para cada segmento de red.
|
||||||
|
|
||||||
|
**Acceso:**
|
||||||
|
1. Marca el checkbox **"Usar rangos personalizados por segmento"** en la configuración del plugin
|
||||||
|
2. Configura una **"Contraseña de administrador"** en la configuración del plugin
|
||||||
|
3. Haz clic en el botón **⚙️** (Configuración Avanzada) en la esquina superior derecha de la interfaz principal
|
||||||
|
4. Ingresa la contraseña configurada
|
||||||
|
|
||||||
|
**Características del Editor:**
|
||||||
|
- **Interfaz visual**: No necesitas editar JSON manualmente
|
||||||
|
- **Múltiples rangos**: Define varios rangos iniciales y finales por segmento
|
||||||
|
- **Validación automática**: El sistema valida que los rangos sean correctos
|
||||||
|
- **Indicador de modo**: Badge visual que muestra si los rangos personalizados están activos
|
||||||
|
|
||||||
|
**Ejemplo de Configuración:**
|
||||||
|
- **Segmento 13**: IPs administrativas del 2 al 60 y del 253 al 255
|
||||||
|
- **Segmento 15**: IPs administrativas del 2 al 30 y del 253 al 255
|
||||||
|
- **Segmento 18**: IPs administrativas del 1 al 50 y del 253 al 255
|
||||||
|
- **Otros segmentos**: Usan los rangos globales configurados
|
||||||
|
|
||||||
|
**Fallback Inteligente:**
|
||||||
|
Los segmentos no configurados en el editor avanzado usarán automáticamente los rangos globales definidos en la configuración básica del plugin.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔌 API REST
|
## 🔌 API REST
|
||||||
|
|||||||
@ -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,"adminRangeStart":"2","adminRangeEnd":"50","adminRangeFinalStart":"254","adminRangeFinalEnd":"255"}
|
{"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","useCustomAdminRanges":true,"customAdminRangesJson":"{\"segmentos\":[{\"segmento\":\"13\",\"administrativas_iniciales\":[{\"inicio\":2,\"hasta\":50}],\"administrativas_finales\":[{\"inicio\":253,\"hasta\":254}]}]}","adminPassword":"Siip.2963"}
|
||||||
3759
data/plugin.log
3759
data/plugin.log
File diff suppressed because it is too large
Load Diff
124
manifest.json
124
manifest.json
@ -35,9 +35,70 @@
|
|||||||
"key": "unmsApiToken",
|
"key": "unmsApiToken",
|
||||||
"label": "Token de la API UNMS",
|
"label": "Token de la API UNMS",
|
||||||
"description": "Token de autenticación necesario para el uso de la API del sistema UISP UNMS, se utiliza para gestionar información de antenas u otros dispositivos de red. Contiene 34 caracteres y se genera desde el módulo de Ajustes del UISP Network en la opción de 'Usuarios' y en apartado de 'API tokens'.",
|
"description": "Token de autenticación necesario para el uso de la API del sistema UISP UNMS, se utiliza para gestionar información de antenas u otros dispositivos de red. Contiene 34 caracteres y se genera desde el módulo de Ajustes del UISP Network en la opción de 'Usuarios' y en apartado de 'API tokens'.",
|
||||||
"required": 0,
|
"required": 1,
|
||||||
"type": "text"
|
"type": "text"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "enablePingVerification",
|
||||||
|
"label": "Habilitar verificación por Ping",
|
||||||
|
"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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"type": "number",
|
||||||
|
"default": 2541
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": 1,
|
||||||
|
"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 (Utilizar interfaz de configuración avanzada para editar). 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"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "debugMode",
|
"key": "debugMode",
|
||||||
"label": "Debug Mode?",
|
"label": "Debug Mode?",
|
||||||
@ -51,67 +112,6 @@
|
|||||||
"description": "Make the plugin more verbose - Hace el plugin mas verboso.",
|
"description": "Make the plugin more verbose - Hace el plugin mas verboso.",
|
||||||
"type": "checkbox",
|
"type": "checkbox",
|
||||||
"required": 0
|
"required": 0
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "enablePingVerification",
|
|
||||||
"label": "Habilitar verificación por Ping",
|
|
||||||
"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": [
|
"menu": [
|
||||||
|
|||||||
207
public.php
207
public.php
@ -53,11 +53,23 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_advanced_config'
|
|||||||
die('Error: ' . $validation['error']);
|
die('Error: ' . $validation['error']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guardar en config.json
|
// Guardar en config.json directamente (el SDK no tiene método save)
|
||||||
$configManager = PluginConfigManager::create();
|
$configFile = __DIR__ . '/data/config.json';
|
||||||
$config = $configManager->loadConfig();
|
if (!file_exists($configFile)) {
|
||||||
|
// Si no existe, intentar crearlo con estructura básica
|
||||||
|
$config = [];
|
||||||
|
} else {
|
||||||
|
$config = json_decode(file_get_contents($configFile), true);
|
||||||
|
if (!is_array($config)) {
|
||||||
|
$config = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$config['customAdminRangesJson'] = $jsonData;
|
$config['customAdminRangesJson'] = $jsonData;
|
||||||
$configManager->saveConfig($config);
|
|
||||||
|
if (file_put_contents($configFile, json_encode($config, JSON_PRETTY_PRINT)) === false) {
|
||||||
|
throw new Exception("No se pudo escribir en el archivo de configuración: $configFile");
|
||||||
|
}
|
||||||
|
|
||||||
// Redirigir con mensaje de éxito
|
// Redirigir con mensaje de éxito
|
||||||
header('Location: ?success=1');
|
header('Location: ?success=1');
|
||||||
@ -608,6 +620,12 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
color: #2095fbff;
|
color: #2095fbff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ip-cell-mobile {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-copy {
|
.btn-copy {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
background: rgba(102, 126, 234, 0.2);
|
background: rgba(102, 126, 234, 0.2);
|
||||||
@ -720,19 +738,17 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ocultar columnas # y Tipo de IP en móvil */
|
/* Ocultar columnas # en móvil */
|
||||||
th:first-child,
|
th:first-child,
|
||||||
td:first-child,
|
td:first-child {
|
||||||
th:nth-child(3),
|
|
||||||
td:nth-child(3) {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Contenedor de IP con badge debajo */
|
/* Contenedor de IP con badge debajo */
|
||||||
.ip-cell-mobile {
|
.ip-cell-mobile {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ip-address {
|
.ip-address {
|
||||||
@ -1135,7 +1151,7 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
<div class="range-input-group">
|
<div class="range-input-group">
|
||||||
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
|
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
|
||||||
<span>hasta</span>
|
<span>hasta</span>
|
||||||
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" />
|
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" value="254" />
|
||||||
<button class="btn-small" onclick="addFinalRange()">+ Agregar Rango</button>
|
<button class="btn-small" onclick="addFinalRange()">+ Agregar Rango</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1265,7 +1281,6 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>Dirección IP</th>
|
<th>Dirección IP</th>
|
||||||
<th>Tipo de IP</th>
|
|
||||||
<th>Estado</th>
|
<th>Estado</th>
|
||||||
<th>Acción</th>
|
<th>Acción</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -1290,8 +1305,30 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
finalStart: <?php echo isset($config['adminRangeFinalStart']) ? (int)$config['adminRangeFinalStart'] : 254; ?>,
|
finalStart: <?php echo isset($config['adminRangeFinalStart']) ? (int)$config['adminRangeFinalStart'] : 254; ?>,
|
||||||
finalEnd: <?php echo isset($config['adminRangeFinalEnd']) ? (int)$config['adminRangeFinalEnd'] : 254; ?>
|
finalEnd: <?php echo isset($config['adminRangeFinalEnd']) ? (int)$config['adminRangeFinalEnd'] : 254; ?>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log('PHP Config Debug:', <?php echo json_encode($config); ?>);
|
||||||
|
|
||||||
|
const useCustomRanges = <?php echo !empty($config['useCustomAdminRanges']) ? 'true' : 'false'; ?>;
|
||||||
|
|
||||||
const searchForm = document.getElementById('searchForm');
|
const searchForm = document.getElementById('searchForm');
|
||||||
|
|
||||||
|
// Mostrar indicador de modo
|
||||||
|
const header = document.querySelector('.header');
|
||||||
|
const modeBadge = document.createElement('div');
|
||||||
|
modeBadge.className = useCustomRanges ? 'mode-badge custom' : 'mode-badge global';
|
||||||
|
modeBadge.innerHTML = useCustomRanges ? '✨ Modo: Rangos Personalizados' : '🌐 Modo: Rangos Globales';
|
||||||
|
modeBadge.style.cssText = `
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-top: 10px;
|
||||||
|
background: ${useCustomRanges ? 'rgba(102, 126, 234, 0.2)' : 'rgba(255, 255, 255, 0.1)'};
|
||||||
|
color: ${useCustomRanges ? '#667eea' : '#a0aec0'};
|
||||||
|
border: 1px solid ${useCustomRanges ? 'rgba(102, 126, 234, 0.3)' : 'rgba(255, 255, 255, 0.2)'};
|
||||||
|
`;
|
||||||
|
header.appendChild(modeBadge);
|
||||||
|
|
||||||
const searchBtn = document.getElementById('searchBtn');
|
const searchBtn = document.getElementById('searchBtn');
|
||||||
const loading = document.getElementById('loading');
|
const loading = document.getElementById('loading');
|
||||||
const results = document.getElementById('results');
|
const results = document.getElementById('results');
|
||||||
@ -1306,43 +1343,56 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
// ========== ADVANCED CONFIGURATION EDITOR ==========
|
// ========== ADVANCED CONFIGURATION EDITOR ==========
|
||||||
|
|
||||||
// Variables del editor
|
// Variables del editor
|
||||||
let editorData = { segmentos: [] };
|
// Inicializar editorData con los rangos personalizados
|
||||||
|
let editorData;
|
||||||
|
const customRangesJson = <?php echo json_encode($config['customAdminRangesJson'] ?? '{"segmentos":[]}'); ?>;
|
||||||
|
|
||||||
|
try {
|
||||||
|
editorData = JSON.parse(customRangesJson);
|
||||||
|
if (!editorData.segmentos) {
|
||||||
|
editorData = { segmentos: [] };
|
||||||
|
}
|
||||||
|
console.log('editorData cargado al inicio:', editorData);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error loading initial editorData:', e);
|
||||||
|
editorData = { segmentos: [] };
|
||||||
|
}
|
||||||
|
|
||||||
let hasUnsavedChanges = false;
|
let hasUnsavedChanges = false;
|
||||||
const adminPassword = '<?php echo addslashes($config['adminPassword'] ?? ''); ?>';
|
const adminPassword = <?php echo json_encode($config['adminPassword'] ?? ''); ?>;
|
||||||
const customRangesJson = '<?php echo addslashes($config['customAdminRangesJson'] ?? '{"segmentos":[]}'); ?>';
|
|
||||||
|
|
||||||
// Event listener para botón de configuración avanzada
|
// Event listener para botón de configuración avanzada
|
||||||
document.getElementById('advancedConfigBtn').addEventListener('click', openAdvancedConfig);
|
document.getElementById('advancedConfigBtn').addEventListener('click', openAdvancedConfig);
|
||||||
|
|
||||||
function openAdvancedConfig() {
|
function openAdvancedConfig() {
|
||||||
document.getElementById('passwordModal').style.display = 'flex';
|
document.getElementById('passwordModal').style.display = 'flex';
|
||||||
document.getElementById('adminPasswordInput').value = '';
|
|
||||||
document.getElementById('adminPasswordInput').focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function closePasswordModal() {
|
|
||||||
document.getElementById('passwordModal').style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
function validatePassword() {
|
|
||||||
const inputPassword = document.getElementById('adminPasswordInput').value;
|
|
||||||
|
|
||||||
if (inputPassword === adminPassword) {
|
|
||||||
closePasswordModal();
|
|
||||||
showEditor();
|
|
||||||
} else {
|
|
||||||
alert('❌ Contraseña incorrecta');
|
|
||||||
document.getElementById('adminPasswordInput').value = '';
|
document.getElementById('adminPasswordInput').value = '';
|
||||||
document.getElementById('adminPasswordInput').focus();
|
document.getElementById('adminPasswordInput').focus();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
function closePasswordModal() {
|
||||||
// Permitir Enter en el campo de contraseña
|
document.getElementById('passwordModal').style.display = 'none';
|
||||||
document.getElementById('adminPasswordInput').addEventListener('keypress', function(e) {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
validatePassword();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
function validatePassword() {
|
||||||
|
const inputPassword = document.getElementById('adminPasswordInput').value;
|
||||||
|
|
||||||
|
if (inputPassword === adminPassword) {
|
||||||
|
closePasswordModal();
|
||||||
|
showEditor();
|
||||||
|
} else {
|
||||||
|
alert('❌ Contraseña incorrecta');
|
||||||
|
document.getElementById('adminPasswordInput').value = '';
|
||||||
|
document.getElementById('adminPasswordInput').focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permitir Enter en el campo de contraseña
|
||||||
|
document.getElementById('adminPasswordInput').addEventListener('keypress', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
validatePassword();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function showEditor() {
|
function showEditor() {
|
||||||
document.querySelector('.container').style.display = 'none';
|
document.querySelector('.container').style.display = 'none';
|
||||||
@ -1431,7 +1481,7 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
newRange.innerHTML = `
|
newRange.innerHTML = `
|
||||||
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
|
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
|
||||||
<span>hasta</span>
|
<span>hasta</span>
|
||||||
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" />
|
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" value="255" />
|
||||||
<button class="btn-small" onclick="this.parentElement.remove()" style="background: rgba(245, 87, 108, 0.2); color: #ff6b6b;">
|
<button class="btn-small" onclick="this.parentElement.remove()" style="background: rgba(245, 87, 108, 0.2); color: #ff6b6b;">
|
||||||
✖ Quitar
|
✖ Quitar
|
||||||
</button>
|
</button>
|
||||||
@ -1503,7 +1553,7 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
<div class="range-input-group">
|
<div class="range-input-group">
|
||||||
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
|
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
|
||||||
<span>hasta</span>
|
<span>hasta</span>
|
||||||
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" />
|
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" value="255" />
|
||||||
<button class="btn-small" onclick="addFinalRange()">+ Agregar Rango</button>
|
<button class="btn-small" onclick="addFinalRange()">+ Agregar Rango</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -1745,11 +1795,6 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
<span class="ip-type-badge ip-type-${ipTypeLabel === 'Administración' ? 'admin' : 'client'}">
|
|
||||||
${ipTypeLabel}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td id="status-${ip.replace(/\./g, '-')}">
|
<td id="status-${ip.replace(/\./g, '-')}">
|
||||||
<span class="status-badge status-${statusClass}">${statusText}</span>
|
<span class="status-badge status-${statusClass}">${statusText}</span>
|
||||||
</td>
|
</td>
|
||||||
@ -1779,15 +1824,79 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
|
|||||||
|
|
||||||
// Función para clasificar el tipo de IP
|
// Función para clasificar el tipo de IP
|
||||||
function getIpType(ip) {
|
function getIpType(ip) {
|
||||||
const lastOctet = parseInt(ip.split('.')[3]);
|
const parts = ip.split('.');
|
||||||
|
if (parts.length !== 4) return 'Cliente';
|
||||||
|
|
||||||
// Verificar si está en alguno de los rangos administrativos configurados
|
const segment = parts[2];
|
||||||
|
const lastOctet = parseInt(parts[3]);
|
||||||
|
|
||||||
|
// 1. Verificar rangos personalizados si existen
|
||||||
|
// Asegurarse de que editorData esté cargado
|
||||||
|
if (typeof editorData === 'undefined' || !editorData.segmentos) {
|
||||||
|
try {
|
||||||
|
if (typeof customRangesJson !== 'undefined') {
|
||||||
|
console.log('customRangesJson type:', typeof customRangesJson);
|
||||||
|
console.log('customRangesJson value:', customRangesJson);
|
||||||
|
editorData = JSON.parse(customRangesJson);
|
||||||
|
console.log('Parsed editorData:', editorData);
|
||||||
|
console.log('editorData.segmentos:', editorData.segmentos);
|
||||||
|
} else {
|
||||||
|
console.warn('customRangesJson is undefined');
|
||||||
|
editorData = { segmentos: [] };
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.error('Error parsing JSON in getIpType:', e);
|
||||||
|
console.error('Failed to parse:', customRangesJson);
|
||||||
|
editorData = { segmentos: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buscar segmento actual en configuración personalizada
|
||||||
|
// Convertir ambos a string y limpiar espacios para asegurar coincidencia
|
||||||
|
const searchSeg = segment.toString().trim();
|
||||||
|
const customSegment = editorData.segmentos.find(s => s.segmento.toString().trim() === searchSeg);
|
||||||
|
|
||||||
|
if (useCustomRanges && customSegment) {
|
||||||
|
// Verificar rangos iniciales personalizados
|
||||||
|
if (customSegment.administrativas_iniciales) {
|
||||||
|
for (const rango of customSegment.administrativas_iniciales) {
|
||||||
|
if (lastOctet >= rango.inicio && lastOctet <= rango.hasta) {
|
||||||
|
console.log(`IP ${ip} es Admin (Custom Init: ${rango.inicio}-${rango.hasta})`);
|
||||||
|
return 'Administración';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar rangos finales personalizados
|
||||||
|
if (customSegment.administrativas_finales) {
|
||||||
|
for (const rango of customSegment.administrativas_finales) {
|
||||||
|
if (lastOctet >= rango.inicio && lastOctet <= rango.hasta) {
|
||||||
|
console.log(`IP ${ip} es Admin (Custom Final: ${rango.inicio}-${rango.hasta})`);
|
||||||
|
return 'Administración';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si hay configuración personalizada para este segmento y no cayó en los rangos admin, es Cliente
|
||||||
|
console.log(`IP ${ip} es Cliente (Custom Segment Found but not in ranges)`);
|
||||||
|
return 'Cliente';
|
||||||
|
} else if (useCustomRanges) {
|
||||||
|
console.log(`IP ${ip}: Segmento '${searchSeg}' no encontrado en custom ranges.`);
|
||||||
|
if (editorData.segmentos) {
|
||||||
|
console.log('Segmentos disponibles:', editorData.segmentos.map(s => `'${s.segmento}'`));
|
||||||
|
} else {
|
||||||
|
console.log('editorData.segmentos es undefined o null');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Fallback a configuración global si no hay segmento personalizado
|
||||||
|
// Verificar si está en alguno de los rangos administrativos configurados globalmente
|
||||||
if ((lastOctet >= adminConfig.rangeStart && lastOctet <= adminConfig.rangeEnd) ||
|
if ((lastOctet >= adminConfig.rangeStart && lastOctet <= adminConfig.rangeEnd) ||
|
||||||
(lastOctet >= adminConfig.finalStart && lastOctet <= adminConfig.finalEnd)) {
|
(lastOctet >= adminConfig.finalStart && lastOctet <= adminConfig.finalEnd)) {
|
||||||
return 'Administración';
|
return 'Administración';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Válida para cliente';
|
return 'Cliente';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runProgressiveVerification(clientIps, limit) {
|
async function runProgressiveVerification(clientIps, limit) {
|
||||||
|
|||||||
@ -97,7 +97,7 @@ function handleIpRequest($data, $log) {
|
|||||||
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true";
|
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true";
|
||||||
$apiToken = $config['unmsApiToken'];
|
$apiToken = $config['unmsApiToken'];
|
||||||
|
|
||||||
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log);
|
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log, $config);
|
||||||
$resultado = $ipService->buscarIpsDisponibles($segment, $verifyPing, $pingLimit);
|
$resultado = $ipService->buscarIpsDisponibles($segment, $verifyPing, $pingLimit);
|
||||||
|
|
||||||
// Formatear respuesta para API
|
// Formatear respuesta para API
|
||||||
|
|||||||
@ -7,12 +7,14 @@ class IpSearchService
|
|||||||
private $apiUrl;
|
private $apiUrl;
|
||||||
private $apiToken;
|
private $apiToken;
|
||||||
private $logger;
|
private $logger;
|
||||||
|
private $config;
|
||||||
|
|
||||||
public function __construct($apiUrl, $apiToken, $logger = null)
|
public function __construct($apiUrl, $apiToken, $logger = null, $config = [])
|
||||||
{
|
{
|
||||||
$this->apiUrl = $apiUrl;
|
$this->apiUrl = $apiUrl;
|
||||||
$this->apiToken = $apiToken;
|
$this->apiToken = $apiToken;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
$this->config = $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,10 +36,19 @@ class IpSearchService
|
|||||||
|
|
||||||
// Si el segmento está configurado en JSON, usar esos rangos
|
// Si el segmento está configurado en JSON, usar esos rangos
|
||||||
if ($limits !== null) {
|
if ($limits !== null) {
|
||||||
return AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
|
$isCustom = AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
|
||||||
|
// Log para depuración (temporal)
|
||||||
|
if (isset($config['debugMode']) && $config['debugMode']) {
|
||||||
|
error_log("Check Custom IP $ip (Seg $segment): " . ($isCustom ? 'ADMIN' : 'CLIENT'));
|
||||||
|
}
|
||||||
|
return $isCustom;
|
||||||
}
|
}
|
||||||
// Si el segmento NO está en JSON, usar rangos globales como fallback
|
// Si el segmento NO está en JSON, usar rangos globales como fallback
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (isset($config['debugMode']) && $config['debugMode']) {
|
||||||
|
error_log("Custom ranges disabled or empty JSON. Config: " . print_r($config, true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usar configuración estándar (rangos globales)
|
// Usar configuración estándar (rangos globales)
|
||||||
@ -174,11 +185,8 @@ class IpSearchService
|
|||||||
$clientIps = [];
|
$clientIps = [];
|
||||||
|
|
||||||
foreach ($ipsDisponibles as $ip) {
|
foreach ($ipsDisponibles as $ip) {
|
||||||
$parts = explode('.', $ip);
|
// Usar función dinámica para verificar si es administrativa
|
||||||
$lastOctet = intval(end($parts));
|
if (self::isAdminIp($ip, $this->config)) {
|
||||||
|
|
||||||
// IPs administrativas: 1-30 y 254
|
|
||||||
if (($lastOctet >= 1 && $lastOctet <= 30) || $lastOctet === 254) {
|
|
||||||
$adminIps[] = $ip;
|
$adminIps[] = $ip;
|
||||||
} else {
|
} else {
|
||||||
$clientIps[] = $ip;
|
$clientIps[] = $ip;
|
||||||
|
|||||||
55
test_debug.php
Normal file
55
test_debug.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/src/AdminRangeHelper.php';
|
||||||
|
|
||||||
|
use SiipAvailableIps\AdminRangeHelper;
|
||||||
|
|
||||||
|
// Datos simulados del config.json
|
||||||
|
$config = [
|
||||||
|
'useCustomAdminRanges' => true,
|
||||||
|
'customAdminRangesJson' => '{"segmentos":[{"segmento":"18","administrativas_iniciales":[{"inicio":1,"hasta":50}],"administrativas_finales":[{"inicio":253,"hasta":255}]},{"segmento":"15","administrativas_iniciales":[{"inicio":2,"hasta":30}],"administrativas_finales":[{"inicio":253,"hasta":255}]},{"segmento":"13","administrativas_iniciales":[{"inicio":2,"hasta":60}],"administrativas_finales":[{"inicio":253,"hasta":255}]}]}'
|
||||||
|
];
|
||||||
|
|
||||||
|
$ip = "172.16.13.52";
|
||||||
|
|
||||||
|
echo "Probando IP: $ip\n";
|
||||||
|
echo "Config JSON: " . $config['customAdminRangesJson'] . "\n";
|
||||||
|
|
||||||
|
$parts = explode('.', $ip);
|
||||||
|
$segment = $parts[2];
|
||||||
|
echo "Segmento extraído: $segment\n";
|
||||||
|
|
||||||
|
$limits = AdminRangeHelper::getSegmentLimits($segment, $config['customAdminRangesJson']);
|
||||||
|
|
||||||
|
if ($limits) {
|
||||||
|
echo "Límites encontrados para segmento $segment:\n";
|
||||||
|
print_r($limits);
|
||||||
|
} else {
|
||||||
|
echo "NO se encontraron límites para segmento $segment\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$isAdmin = AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
|
||||||
|
|
||||||
|
echo "Es Admin IP (Custom)? " . ($isAdmin ? "SI" : "NO") . "\n";
|
||||||
|
|
||||||
|
// Prueba de la lógica completa de IpSearchService (simulada)
|
||||||
|
function isAdminIp($ip, $config) {
|
||||||
|
if (!empty($config['useCustomAdminRanges']) && !empty($config['customAdminRangesJson'])) {
|
||||||
|
$parts = explode('.', $ip);
|
||||||
|
if (count($parts) === 4) {
|
||||||
|
$segment = $parts[2];
|
||||||
|
$limits = AdminRangeHelper::getSegmentLimits($segment, $config['customAdminRangesJson']);
|
||||||
|
|
||||||
|
if ($limits !== null) {
|
||||||
|
echo "[DEBUG] Usando rangos custom para segmento $segment\n";
|
||||||
|
return AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
|
||||||
|
} else {
|
||||||
|
echo "[DEBUG] Fallback a rangos globales para segmento $segment\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // Simplificado
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = isAdminIp($ip, $config);
|
||||||
|
echo "Resultado final isAdminIp: " . ($result ? "TRUE" : "FALSE") . "\n";
|
||||||
Loading…
Reference in New Issue
Block a user