- Agregar validación multi-capa para garantizar IPs 100% disponibles - Capa 1: Filtrar IPs de dispositivos registrados en UISP - Capa 2: Filtrar IPs de servicios CRM suspendidos/finalizados (449 IPs) - Capa 3: Validar IPs usando búsqueda de sitios con type=subscriber - Capa 4: Verificación opcional por ping para dispositivos de terceros Nuevos Componentes: - src/IpValidator.php: Clase de validación por búsqueda de sitios - Validación progresiva en frontend JavaScript - Endpoint action=validate en public.php Mejoras: - CrmService.php: Filtrado mejorado de servicios suspendidos/finalizados - IpSearchService.php: Extraer todas las IPs de ipAddressList - Frontend: Validación progresiva de IPs con feedback visual - Cambiar suspended=false a suspended=true en API de UISP Correcciones: - Corregir variable $config indefinida en handler de validación - Corregir falsos positivos agregando parámetro type=subscriber - Corregir IPs secundarias no detectadas - Corregir IPs de servicios suspendidos/finalizados mostrándose disponibles Resultados de Pruebas: - IP 172.16.54.70 (servicio finalizado): Filtrada correctamente por capa CRM - IP 172.16.54.58 (cliente activo): Filtrada correctamente por búsqueda de sitios - Todas las IPs mostradas verificadas como 100% disponibles Documentación: - Actualizado README.md con detalles del sistema de 4 capas - Actualizado CHANGELOG.md con notas de versión 1.6.0 - Creado walkthrough.md completo
983 lines
48 KiB
PHP
Executable File
983 lines
48 KiB
PHP
Executable File
<?php
|
|
|
|
// --- SERVIR IMÁGENES DESDE LA URL ---
|
|
if (isset($_GET['img'])) {
|
|
$imageName = basename($_GET['img']);
|
|
$imagePath = __DIR__ . '/img/' . $imageName;
|
|
if (file_exists($imagePath)) {
|
|
$mimeType = mime_content_type($imagePath);
|
|
header('Content-Type: ' . $mimeType);
|
|
readfile($imagePath);
|
|
exit;
|
|
} else {
|
|
http_response_code(404);
|
|
echo 'Imagen no encontrada';
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// --- SERVIR CONTRASEÑA GENERADA POR AJAX ---
|
|
if (isset($_GET['generate_password'])) {
|
|
echo generate_strong_password();
|
|
exit;
|
|
}
|
|
|
|
// --- ENDPOINT PARA ACTUALIZAR CONTRASEÑA DEL CLIENTE ---
|
|
if (isset($_POST['update_password']) && isset($_POST['clientId']) && isset($_POST['password'])) {
|
|
// log
|
|
$logger = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
|
|
$logger->appendLog('POST update_password recibido: ' . var_export($_POST, true));
|
|
// lógica PATCH
|
|
$result = updateClientPasswordAttribute($_POST['clientId'], $_POST['password']);
|
|
$logger->appendLog('Resultado updateClientPasswordAttribute: ' . var_export($result, true));
|
|
header('Content-Type: application/json');
|
|
echo json_encode($result);
|
|
exit;
|
|
}
|
|
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Exception\RequestException;
|
|
chdir(__DIR__);
|
|
|
|
require_once __DIR__ . '/vendor/autoload.php';
|
|
|
|
// --- ENDPOINT PARA ACTUALIZAR CONTRASEÑA DEL CLIENTE ---
|
|
if (isset($_POST['update_password']) && isset($_POST['clientId']) && isset($_POST['password'])) {
|
|
$logger = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
|
|
$logger->appendLog('POST update_password recibido: ' . var_export($_POST, true));
|
|
$clientId = $_POST['clientId'];
|
|
$password = $_POST['password'];
|
|
$result = updateClientPasswordAttribute($clientId, $password);
|
|
$logger->appendLog('Resultado updateClientPasswordAttribute: ' . var_export($result, true));
|
|
header('Content-Type: application/json');
|
|
echo json_encode($result);
|
|
exit;
|
|
}
|
|
|
|
// Get UCRM log manager.
|
|
$log = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
|
|
// $log->appendLog(
|
|
// sprintf(
|
|
// 'Executed from public URL: %s',
|
|
// file_get_contents('php://input')
|
|
// )
|
|
// );
|
|
|
|
|
|
// Variable para almacenar la respuesta de la API, mensajes de error y estado
|
|
|
|
$respuestaAPI = '';
|
|
$esError = false;
|
|
|
|
$clientFullName = '';
|
|
$IpAddressClientId = '';
|
|
$clientIdentifierType = 'ID'; // Puede ser 'ID', 'IP', 'MAC'
|
|
|
|
//variables para mostrar info del cliente
|
|
$clientFullName = '';
|
|
$IpAddressClientId = '';
|
|
|
|
// Ensure global variables are initialized at the top of the script
|
|
$clientFullName = $clientFullName ?? '';
|
|
$IpAddressClientId = $IpAddressClientId ?? '';
|
|
|
|
// Verificar si se ha enviado el formulario
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
/**
|
|
* Actualiza el atributo personalizado 'passwordAntenaCliente' de un cliente en UCRM.
|
|
*
|
|
* @param int|string $clientId ID del cliente
|
|
* @param string $newPassword Nueva contraseña a setear
|
|
* @return array [success => bool, message => string]
|
|
*/
|
|
function updateClientPasswordAttribute($clientId, $newPassword) {
|
|
$configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
|
|
$config = $configManager->loadConfig();
|
|
$baseUri = $config['ipserver'];
|
|
$crmAuthToken = $config['apitoken']; // O $config['ucrmApiToken'] si así lo tienes
|
|
$clientUcrm = new \GuzzleHttp\Client([
|
|
'base_uri' => 'https://' . $baseUri . '/crm/api/v1.0/',
|
|
'verify' => false
|
|
]);
|
|
$logger = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
|
|
|
|
try {
|
|
// 1. Obtener el cliente actual
|
|
$response = $clientUcrm->get('clients/' . $clientId, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $crmAuthToken,
|
|
'Content-Type' => 'application/json'
|
|
]
|
|
]);
|
|
if ($response->getStatusCode() !== 200) {
|
|
return ['success' => false, 'message' => 'No se pudo obtener el cliente.'];
|
|
}
|
|
$clientData = json_decode($response->getBody(), true);
|
|
|
|
// 2. Buscar el atributo personalizado 'passwordAntenaCliente'
|
|
$found = false;
|
|
$attributes = [];
|
|
if (isset($clientData['attributes']) && is_array($clientData['attributes'])) {
|
|
foreach ($clientData['attributes'] as $attr) {
|
|
if ($attr['key'] === 'passwordAntenaCliente') {
|
|
$attr['value'] = $newPassword;
|
|
$found = true;
|
|
}
|
|
$attributes[] = $attr;
|
|
}
|
|
}
|
|
if (!$found) {
|
|
return ['success' => false, 'message' => 'No se encontró el atributo personalizado passwordAntenaCliente.'];
|
|
}
|
|
|
|
// 3. Actualizar el cliente completo usando PATCH
|
|
// Solo enviar el array attributes con customAttributeId y value
|
|
$logger->appendLog('PATCH endpoint: clients/' . $clientId);
|
|
$patchBody = [
|
|
'attributes' => [
|
|
[
|
|
'customAttributeId' => 17,
|
|
'value' => $newPassword
|
|
]
|
|
]
|
|
];
|
|
$logger->appendLog('PATCH body: ' . json_encode($patchBody));
|
|
try {
|
|
$patchResponse = $clientUcrm->patch('clients/' . $clientId, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $crmAuthToken,
|
|
'Content-Type' => 'application/json'
|
|
],
|
|
'json' => $patchBody
|
|
]);
|
|
$logger->appendLog('PATCH status: ' . $patchResponse->getStatusCode());
|
|
$logger->appendLog('PATCH response: ' . $patchResponse->getBody());
|
|
if ($patchResponse->getStatusCode() === 200) {
|
|
return ['success' => true, 'message' => 'Contraseña actualizada correctamente.'];
|
|
} else {
|
|
return ['success' => false, 'message' => 'Error al actualizar el cliente.'];
|
|
}
|
|
} catch (Exception $e) {
|
|
$logger->appendLog('PATCH exception: ' . $e->getMessage());
|
|
return ['success' => false, 'message' => 'Excepción: ' . $e->getMessage()];
|
|
}
|
|
} catch (Exception $e) {
|
|
$logger->appendLog('PATCH attributes exception: ' . $e->getMessage());
|
|
return ['success' => false, 'message' => 'Excepción: ' . $e->getMessage()];
|
|
}
|
|
}
|
|
$entrada = trim($_POST['identificador']);
|
|
|
|
// Validar si es una dirección IP válida
|
|
if (filter_var($entrada, FILTER_VALIDATE_IP)) {
|
|
// Es una dirección IP válida
|
|
$respuestaAPI = getVaultCredentials($entrada);
|
|
}
|
|
// Validar si es una dirección MAC válida
|
|
elseif (preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $entrada)) {
|
|
// Es una dirección MAC válida
|
|
$respuestaAPI = getVaultCredentials($entrada);
|
|
}
|
|
// Validar si es un ID numérico menor a 10,000
|
|
elseif (ctype_digit($entrada) && intval($entrada) < 10000) {
|
|
// Es un ID válido
|
|
$respuestaAPI = getVaultCredentials($entrada);
|
|
} else {
|
|
// Entrada no válida
|
|
$mensajeError = "La entrada no es válida. Por favor, ingresa una dirección IP, una dirección MAC o un ID menor a 10,000.";
|
|
}
|
|
|
|
// Verificar si la respuesta de la API indica un error
|
|
if (strpos($respuestaAPI, "Error:") === 0) {
|
|
$esError = true;
|
|
}
|
|
}
|
|
|
|
function setNewPassword($clientId, $newPassword)
|
|
{
|
|
// Aquí iría la lógica para actualizar la contraseña del cliente en UCRM
|
|
// Usando la API de UCRM y el cliente Guzzle
|
|
// Retornar true si se actualizó correctamente, false en caso contrario
|
|
global $clientFullName, $IpAddressClientId;
|
|
$logger = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
|
|
$configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
|
|
$config = $configManager->loadConfig();
|
|
$baseUri = $config['ipserver'];
|
|
$crmAuthToken = $config['apitoken'];
|
|
$unmsAuthToken = $config['unmsApiToken'];
|
|
$ucrmBaseUri = 'https://' . $baseUri . '/crm/api/v1.0/';
|
|
|
|
$clientUcrm = new Client([
|
|
'base_uri' => $ucrmBaseUri,
|
|
'verify' => false // Deshabilitar la verificación del certificado SSL
|
|
]);
|
|
|
|
try {
|
|
$responseClient = $clientUcrm->patch('clients/' . $clientId, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $crmAuthToken,
|
|
'Content-Type' => 'application/json'
|
|
],
|
|
'json' => [
|
|
'attributes' => [
|
|
[
|
|
'customAttributeId' => 17, // ID del atributo personalizado 'passwordAntenaCliente'
|
|
'value' => $newPassword
|
|
]
|
|
]
|
|
]
|
|
]);
|
|
|
|
if ($responseClient->getStatusCode() === 200) {
|
|
$logger->appendLog('Contraseña actualizada correctamente para el cliente: ' . $clientFullName . ' (ID: ' . $IpAddressClientId . ')');
|
|
return true;
|
|
} else {
|
|
$logger->appendLog('Error al actualizar la contraseña. Código de estado HTTP: ' . $responseClient->getStatusCode());
|
|
return false;
|
|
}
|
|
} catch (RequestException $e) {
|
|
$logger->appendLog('Excepción al actualizar la contraseña: ' . $e->getMessage());
|
|
return false;
|
|
}
|
|
|
|
|
|
}
|
|
function getVaultCredentials($dataToSearch): string
|
|
{
|
|
global $clientFullName, $IpAddressClientId, $clientIdentifierType;
|
|
$logger = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
|
|
$configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
|
|
$config = $configManager->loadConfig();
|
|
$baseUri = $config['ipserver'];
|
|
$crmAuthToken = $config['apitoken'];
|
|
$unmsAuthToken = $config['unmsApiToken'];
|
|
|
|
|
|
$unmsBaseUri = 'https://' . $baseUri . '/nms/api/v2.1/';
|
|
$ucrmBaseUri = 'https://' . $baseUri . '/crm/api/v1.0/';
|
|
//$authToken = '7adc9198-50b1-41d0-9bfa-d4946902ed89';
|
|
|
|
// Crear una instancia del cliente Guzzle
|
|
$clientUnms = new Client([
|
|
'base_uri' => $unmsBaseUri,
|
|
'verify' => false // Deshabilitar la verificación del certificado SSL
|
|
]);
|
|
|
|
$clientUcrm = new Client([
|
|
'base_uri' => $ucrmBaseUri,
|
|
'verify' => false // Deshabilitar la verificación del certificado SSL
|
|
]);
|
|
|
|
|
|
//validar si dataToSearch es una dirección IP o una dirección MAC
|
|
if (filter_var($dataToSearch, FILTER_VALIDATE_IP)) {
|
|
$clientIdentifierType = 'IP';
|
|
// La variable es una dirección IP válida
|
|
$logger->appendLog('Consulta por dirección IP: ' . $dataToSearch);
|
|
|
|
$IpAddressClientId = filter_var($dataToSearch, FILTER_VALIDATE_IP);
|
|
|
|
try {
|
|
$responseSitesByIP = $clientUnms->request('GET', 'sites/search?query=' . $dataToSearch . '&count=1&page=1', [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]); //Sites por IP
|
|
|
|
if ($responseSitesByIP->getStatusCode() === 200) {
|
|
|
|
$datasSitesByIP = json_decode($responseSitesByIP->getBody(), true);
|
|
$jsonDevicesBySite = json_encode($datasSitesByIP, JSON_PRETTY_PRINT);
|
|
//print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
|
|
|
|
if (isset($datasSitesByIP[0])) {
|
|
$siteId = $datasSitesByIP[0]['id'];
|
|
// print_r('ID DEL SITIO: ' . $siteId . PHP_EOL); // ID del sitio
|
|
} else {
|
|
$logger->appendLog('No se encontró ningún sitio para la IP proporcionada: ' . $dataToSearch);
|
|
return 'Error: No se encontró ningún sitio para la IP proporcionada: ' . $dataToSearch; // Return early if no site is found
|
|
}
|
|
|
|
|
|
} else {
|
|
//echo "Error en la solicitud. Código de estado HTTP: " . $responseSitesByIP->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $responseSitesByIP->getStatusCode());
|
|
return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responseSitesByIP->getStatusCode(); // Return early if the request fails
|
|
}
|
|
|
|
$devicesBySiteId = $clientUnms->request('GET', 'devices?siteId=' . $siteId, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]); //Devices por ID del sitio
|
|
|
|
if ($devicesBySiteId->getStatusCode() === 200) {
|
|
$dataDevicesBySite = json_decode($devicesBySiteId->getBody(), true);
|
|
$jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
|
|
//print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
|
|
$deviceID = null;
|
|
|
|
foreach ($dataDevicesBySite as $device) {
|
|
if (isset($device['ipAddress'])) {
|
|
$ipAddress = explode('/', $device['ipAddress'])[0]; // Obtener solo la IP sin la máscara
|
|
if ($ipAddress === $IpAddressClientId) {
|
|
$deviceID = $device['identification']['id']; // ID del dispositivo
|
|
break; // Salir del ciclo si se encuentra la IP
|
|
}
|
|
} else {
|
|
$logger->appendLog('No se encontró la IP del dispositivo en la respuesta de la API.');
|
|
return 'Error: No se encontró la IP del dispositivo en la respuesta de la API.'; // Return early if the IP is not found
|
|
}
|
|
}
|
|
|
|
if ($deviceID == null) {
|
|
//echo "No se encontró el dispositivo con la IP proporcionada." . PHP_EOL;
|
|
$logger->appendLog('No se encontró el dispositivo con la IP proporcionada: ' . $IpAddressClientId);
|
|
return 'Error: No se encontró el dispositivo con la IP proporcionada: ' . $IpAddressClientId; // Return early if no device is found
|
|
}
|
|
|
|
} else {
|
|
// echo "Error en la solicitud. Código de estado HTTP: " . $devicesBySiteId->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $devicesBySiteId->getStatusCode());
|
|
return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $devicesBySiteId->getStatusCode(); // Return early if the request fails
|
|
}
|
|
|
|
$responsePasswordVault = $clientUnms->request('GET', 'vault/' . $deviceID . '/credentials', [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]);
|
|
|
|
if ($responsePasswordVault->getStatusCode() === 200) {
|
|
$dataPasswordVault = json_decode($responsePasswordVault->getBody(), true);
|
|
// $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
|
|
//print_r($jsonPasswordVault . PHP_EOL); //Cred
|
|
|
|
if (isset($dataPasswordVault['credentials'][0]['password'])) {
|
|
//asignar el campo password a la variable dataPasswordVault
|
|
$dataPasswordVault = $dataPasswordVault['credentials'][0]['password'];
|
|
} else {
|
|
// echo "No se encontró la contraseña en la respuesta de la API." . PHP_EOL;
|
|
$logger->appendLog('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.');
|
|
return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
|
|
}
|
|
return $dataPasswordVault;
|
|
|
|
} else {
|
|
// echo "Error en la solicitud. Código de estado HTTP: " . $responsePasswordVault->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode());
|
|
return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
|
|
}
|
|
|
|
|
|
} catch (RequestException $requestException) {
|
|
// Manejar errores de la solicitud, si hay error 404 entonces responder que no se encontró niguna IP asociada a alguna antena o dispositivo de red
|
|
if ($requestException->hasResponse()) {
|
|
$response = $requestException->getResponse();
|
|
$statusCode = $response->getStatusCode();
|
|
$reason = $response->getReasonPhrase();
|
|
// echo "Error: {$statusCode} - {$reason}" . PHP_EOL;
|
|
// echo $response->getBody();
|
|
if ($statusCode == 404) {
|
|
// echo "No se encontró el cliente con la dirección IP proporcionada." . PHP_EOL;
|
|
$logger->appendLog('No se encontró el cliente con la dirección IP proporcionada: ' . $IpAddressClientId);
|
|
return 'Error: No se encontró el cliente con la dirección IP proporcionada: ' . $IpAddressClientId; // Return early if the client is not found
|
|
}
|
|
return 'Error: ' . $reason; // Return early if the request fails
|
|
} else {
|
|
// echo "Error: " . $requestException->getMessage() . PHP_EOL;
|
|
$logger->appendLog('Error: ' . $requestException->getMessage());
|
|
return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $dataToSearch)) {
|
|
$clientIdentifierType = 'MAC';
|
|
// La variable es una dirección MAC válida
|
|
$logger->appendLog('Consulta por dirección MAC: ' . $dataToSearch);
|
|
|
|
try {
|
|
// //para mandarla al endpoint de dispositivos por MAC se necesita convertir la cadena de la direccion mac en un formato como el siguiente ejemplo: para la dirección mac 60:22:32:c8:b2:c3 quedaría como 60%3A22%3A32%3Ac8%3Ab2%3Ac3
|
|
// $dataToSearch = str_replace(':', '%3A', $dataToSearch);
|
|
// $logger->appendLog('Consulta por dirección MAC: ' . $dataToSearch );
|
|
$responseDeviceByMAC = $clientUnms->request('GET', 'devices/mac/' . $dataToSearch, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]);
|
|
|
|
if ($responseDeviceByMAC->getStatusCode() === 200) {
|
|
|
|
$dataDeviceByMAC = json_decode($responseDeviceByMAC->getBody(), true);
|
|
$jsonDeviceByMac = json_encode($dataDeviceByMAC, JSON_PRETTY_PRINT);
|
|
// print_r($jsonDeviceByMac . PHP_EOL); //Devices por ID del sitio
|
|
//$logger->appendLog($jsonDeviceByMac.PHP_EOL);
|
|
|
|
//Ejemplo de $responseDeviceByMac en json: {"id":"84c8a581-154c-41db-81d5-a1b1c9ede411","type":"airMax","series":"AC"}
|
|
//obtener el id del dispositivo y si no existe el id del dispositivo entonces devolver un mensaje de error
|
|
if (isset($dataDeviceByMAC['id'])) {
|
|
$deviceId = $dataDeviceByMAC['id'];
|
|
// print_r('ID DEL DISPOSITIVO: ' . $deviceId . PHP_EOL); // ID del dispositivo
|
|
} else {
|
|
// echo "No se encontró el dispositivo con la dirección MAC proporcionada." . PHP_EOL;
|
|
$logger->appendLog('No se encontró el dispositivo con la dirección MAC proporcionada: ' . $dataToSearch);
|
|
return 'Error: No se encontró el dispositivo con la dirección MAC proporcionada: ' . $dataToSearch; // Return early if no device is found
|
|
}
|
|
|
|
}
|
|
|
|
$responsePasswordVault = $clientUnms->request('GET', 'vault/' . $deviceId . '/credentials', [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]);
|
|
|
|
if ($responsePasswordVault->getStatusCode() === 200) {
|
|
$dataPasswordVault = json_decode($responsePasswordVault->getBody(), true);
|
|
// $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
|
|
//print_r($jsonPasswordVault . PHP_EOL); //Credenciales del dispositivo
|
|
|
|
if (isset($dataPasswordVault['credentials'][0]['password'])) {
|
|
//asignar el campo password a la variable dataPasswordVault
|
|
$dataPasswordVault = $dataPasswordVault['credentials'][0]['password'];
|
|
} else {
|
|
// echo "No se encontró la contraseña en la respuesta de la API." . PHP_EOL;
|
|
$logger->appendLog('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.');
|
|
return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
|
|
}
|
|
return $dataPasswordVault;
|
|
|
|
} else {
|
|
// echo "Error en la solicitud. Código de estado HTTP: " . $responsePasswordVault->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode());
|
|
return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
|
|
|
|
}
|
|
|
|
|
|
} catch (RequestException $requestException) {
|
|
// Manejar errores de la solicitud, si hay error 404 entonces responder que no se encontró niguna MAC asociada a alguna antena o dispositivo de red
|
|
if ($requestException->hasResponse()) {
|
|
$response = $requestException->getResponse();
|
|
$statusCode = $response->getStatusCode();
|
|
$reason = $response->getReasonPhrase();
|
|
// echo "Error: {$statusCode} - {$reason}" . PHP_EOL;
|
|
// echo $response->getBody();
|
|
if ($statusCode == 404) {
|
|
// echo "No se encontró el cliente con la dirección MAC proporcionada." . PHP_EOL;
|
|
$logger->appendLog('No se encontró ninguna antena de cliente o dispositivo en la red con la dirección MAC proporcionada: ' . $dataToSearch);
|
|
return 'Error: No se encontró ninguna antena de cliente o dispositivo en la red con la dirección MAC proporcionada: ' . $dataToSearch; // Return early if the client is not found
|
|
}
|
|
return 'Error: ' . $reason; // Return early if the request fails
|
|
} else {
|
|
// echo "Error: " . $requestException->getMessage() . PHP_EOL;
|
|
$logger->appendLog('Error: ' . $requestException->getMessage());
|
|
return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
$clientIdentifierType = 'ID';
|
|
// La variable no es una dirección IP válida, se asume que es un ID
|
|
$IpAddressClientId = filter_var($dataToSearch, FILTER_SANITIZE_NUMBER_INT);
|
|
//print ('Consulta por ID: ' . $dataToSearch . PHP_EOL);
|
|
// $logger->appendLog('Consulta por ID' . $dataToSearch);
|
|
// $logger->appendLog('endpoint que se envía: '.$ucrmBaseUri.'clients/services?clientId=' . $IpAddressClientId);
|
|
// $logger->appendLog('apiToken que se usa: '.$crmAuthToken);
|
|
|
|
try {
|
|
//Obtener id del sitio por medio del servicio
|
|
$responseServices = $clientUcrm->get('clients/services?clientId=' . $IpAddressClientId, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $crmAuthToken,
|
|
'Content-Type: application/json'
|
|
]
|
|
]);
|
|
|
|
//Obtener el nombre del cliente por medio del ID
|
|
$responseClientName = $clientUcrm->get('clients/' . $IpAddressClientId, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $crmAuthToken,
|
|
'Content-Type: application/json'
|
|
]
|
|
]);
|
|
//ejemplo de responseClientName en json: {"id":3201,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"CALLE CHIAPAS #31, ZONA CENTRO","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"CALLE CHIAPAS #31, ZONA CENTRO, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Soy un teibolero :) programador en SIIP INTERNET","sendInvoiceByPost":null,"invoiceMaturityDays":17,"stopServiceDue":false,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-04-19T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"DANIEL HUMBERTO","lastName":"SOTO VILLEGAS","username":"dhsv.141089@gmail.com","contacts":[{"id":4188,"clientId":3201,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":false,"types":[{"id":4,"name":"WhatsApp"}]},{"id":5242,"clientId":3201,"email":null,"phone":"5214181148783","name":"WA Bussiness","isBilling":false,"isContact":false,"types":[]}],"attributes":[{"id":21180,"clientId":3201,"customAttributeId":35,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":true},{"id":18147,"clientId":3201,"customAttributeId":1,"name":"ip","key":"ip","value":"172.16.13.64","clientZoneVisible":false},{"id":19859,"clientId":3201,"customAttributeId":29,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_RKiSN955qKhmch","clientZoneVisible":true},{"id":19860,"clientId":3201,"customAttributeId":30,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"124180650741646979","clientZoneVisible":true},{"id":21181,"clientId":3201,"customAttributeId":36,"name":"Antena/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16/24","clientZoneVisible":true},{"id":27184,"clientId":3201,"customAttributeId":21,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https://dash.callbell.eu/chat/90611886ac204c56a75240f951c53874","clientZoneVisible":false},{"id":28687,"clientId":3201,"customAttributeId":22,"name":"uuid","key":"uuid","value":"2038d2d99ae543f3b56f1ae54f4cc82b","clientZoneVisible":false},{"id":29853,"clientId":3201,"customAttributeId":37,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"gYAIEK:Be}SK*01z5+/V","clientZoneVisible":false}],"accountBalance":-300,"accountCredit":0,"accountOutstanding":300,"currencyCode":"MXN","organizationName":"SIIP","bankAccounts":[{"id":2,"accountNumber":"124180650741646979"}],"tags":[{"id":1,"name":"NS EXENTO","colorBackground":"#00a0df","colorText":"#fff"}],"invitationEmailSentDate":null,"avatarColor":"#4caf50","addressGpsLat":21.1564209,"addressGpsLon":-100.9384185,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":true,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}
|
|
|
|
$clientName = json_decode($responseClientName->getBody(), true);
|
|
$clientFullName = $clientName['firstName'] . ' ' . $clientName['lastName'];
|
|
$logger->appendLog('CLIENTE: ' . $clientFullName . ' (ID: ' . $IpAddressClientId . ')');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (RequestException $requestException) {
|
|
// Manejar errores de la solicitud
|
|
if ($requestException->hasResponse()) {
|
|
$response = $requestException->getResponse();
|
|
$statusCode = $response->getStatusCode();
|
|
$reason = $response->getReasonPhrase();
|
|
//si el statusCode es 404 significa que no se encontró el cliente
|
|
if ($statusCode == 404) {
|
|
// echo "No se encontró el cliente con el ID proporcionado." . PHP_EOL;
|
|
$logger->appendLog('No se encontró el cliente con el ID proporcionado: ' . $IpAddressClientId);
|
|
return 'Error: No se encontró el cliente con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
|
|
}
|
|
return 'Error: ' . $reason; // Return early if the request fails
|
|
|
|
} else {
|
|
// echo "Error: " . $requestException->getMessage() . PHP_EOL;
|
|
$logger->appendLog('Error: ' . $requestException->getMessage());
|
|
return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
|
|
}
|
|
|
|
}
|
|
|
|
if ($responseServices->getStatusCode() === 200) {
|
|
|
|
$dataServices = json_decode($responseServices->getBody(), true);
|
|
// $jsonServices = json_encode($dataServices, JSON_PRETTY_PRINT);
|
|
// print_r($jsonServices . PHP_EOL);
|
|
if (isset($dataServices[0])) {
|
|
$unmsSiteID = $dataServices[0]['unmsClientSiteId']; // Example: 9c6798f3-0254-4e5b-bc3b-9da82fe16e46
|
|
} else {
|
|
// echo "No se encontraron servicios para el cliente proporcionado." . PHP_EOL;
|
|
$logger->appendLog('No se encontraron servicios para el cliente proporcionado: ' . $IpAddressClientId);
|
|
return "Error: No se encontraron servicios para el cliente proporcionado: " . $IpAddressClientId; // Return early if no services are found
|
|
}
|
|
|
|
} else {
|
|
// echo "Error en la solicitud. Código de estado HTTP: " . $responseServices->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $responseServices->getStatusCode());
|
|
return "Error: En la solicitud. Código de estado HTTP: " . $responseServices->getStatusCode();
|
|
}
|
|
// $logger->appendLog('ID del sitio obtenido: ' . $unmsSiteID);
|
|
// $logger->appendLog('endpoint que se envía: '.$unmsBaseUri.'devices?siteId=' . $unmsSiteID);
|
|
// $logger->appendLog('apiToken que se usa: '.$crmAuthToken);
|
|
|
|
$responseDevicesBySite = $clientUnms->request('GET', 'devices?siteId=' . $unmsSiteID, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]);
|
|
|
|
|
|
|
|
if ($responseDevicesBySite->getStatusCode() === 200) {
|
|
|
|
$dataDevicesBySite = json_decode($responseDevicesBySite->getBody(), true);
|
|
$jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
|
|
//print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
|
|
|
|
//id del device al que está conectado el cliente
|
|
if (isset($dataDevicesBySite[0])) {
|
|
$idClientDevice = $dataDevicesBySite[0]['identification']['id'];
|
|
$deviceID = $dataDevicesBySite[0]['attributes']['apDevice']['id'];
|
|
} else {
|
|
// echo "No se encontraron dispositivos para el sitio proporcionado." . PHP_EOL;
|
|
$logger->appendLog('No se encontraron dispositivos para el sitio proporcionado: ' . $unmsSiteID);
|
|
return "Error: No se encontraron dispositivos para el sitio proporcionado."; // Return early if no devices are found
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
// echo "Error en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode());
|
|
return "Error: Falla en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode();
|
|
}
|
|
|
|
// $logger->appendLog('ID del device al que está conectado el cliente: ' . $deviceID);
|
|
// $logger->appendLog('endpoint que se envía: '.$unmsBaseUri.'devices/' . $deviceID);
|
|
// $logger->appendLog('apiToken que se usa: '.$unmsAuthToken);
|
|
|
|
$responseDevicesBySite = $clientUnms->request('GET', 'devices/' . $deviceID, [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]);
|
|
|
|
if ($responseDevicesBySite->getStatusCode() === 200) {
|
|
|
|
$dataDevices = json_decode($responseDevicesBySite->getBody(), true);
|
|
$jsonDevices = json_encode($dataDevices, JSON_PRETTY_PRINT);
|
|
//print_r($jsonDevices . PHP_EOL);
|
|
|
|
|
|
// $logger->appendLog('ID del device al que está conectado el cliente: ' . $idDevice);
|
|
// $logger->appendLog('endpoint que se envía: '.$unmsBaseUri.'vault/' . $idDevice . '/credentials');
|
|
// $logger->appendLog('apiToken que se usa: '.$unmsAuthToken);
|
|
|
|
//print_r('ID del device al que está conectado el cliente: ' . $idDevice . PHP_EOL);
|
|
$responsePasswordVault = $clientUnms->request('GET', 'vault/' . $idClientDevice . '/credentials', [
|
|
'headers' => [
|
|
'X-Auth-Token' => $unmsAuthToken
|
|
]
|
|
]);
|
|
|
|
|
|
if ($responsePasswordVault->getStatusCode() === 200) {
|
|
$dataPasswordVault = json_decode($responsePasswordVault->getBody(), true);
|
|
$jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
|
|
// $logger->appendLog($jsonPasswordVault); //Credenciales del dispositivo
|
|
//ejemplo de $responsePasswordVault en json: {"credentials":[{"username":"ubnt","readOnly":false,"password":"gYAIEK:Be}SK*01z5+/V","createdAt":"2025-03-27T23:29:54.948Z"}],"isPassphraseMissing":false}
|
|
|
|
//verificar si existe la contraseña en la respuesta de la API
|
|
if (isset($dataPasswordVault['credentials'][0]['password'])) {
|
|
//asignar el campo password a la variable dataPasswordVault
|
|
$dataPasswordVault = $dataPasswordVault['credentials'][0]['password'];
|
|
} else {
|
|
// echo "No se encontró la contraseña en la respuesta de la API." . PHP_EOL;
|
|
$logger->appendLog('Id device: ' . $idClientDevice);
|
|
$logger->appendLog('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.');
|
|
return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
|
|
}
|
|
return $dataPasswordVault;
|
|
|
|
} else {
|
|
// echo "Error en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode());
|
|
return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
// echo "Error en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode() . PHP_EOL;
|
|
$logger->appendLog('Error en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode());
|
|
return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode(); // Return early if the request fails
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
global $clientFullName, $IpAddressClientId; // Variables globales para usar en la función getVaultCredentials
|
|
|
|
/**
|
|
* Genera una contraseña aleatoria y fuerte (CSPRNG).
|
|
*
|
|
* - Garantiza al menos 1 minúscula, 1 mayúscula, 1 dígito y 1 símbolo.
|
|
* - Usa random_int() / random_bytes() (CSPRNG).
|
|
* - Evita sesgos al seleccionar y mezcla la contraseña con Fisher-Yates.
|
|
*
|
|
* @param int $length Longitud deseada (mínimo 8). Default 20.
|
|
* @param bool $avoid_ambiguous Si true evita caracteres ambiguos como l, I, 0, O.
|
|
* @return string Contraseña generada.
|
|
* @throws InvalidArgumentException Si $length < 8.
|
|
*/
|
|
function generate_strong_password(int $length = 20, bool $avoid_ambiguous = true): string
|
|
{
|
|
if ($length < 8) {
|
|
throw new InvalidArgumentException('La longitud mínima recomendada es 8 caracteres.');
|
|
}
|
|
|
|
// Conjuntos de caracteres
|
|
$lower = 'abcdefghijklmnopqrstuvwxyz';
|
|
$upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
$digits = '0123456789';
|
|
// Conjunto de símbolos seguros; puedes ampliarlo si lo deseas
|
|
$symbols = '!@#$%&*()-_=+[]{};:,.<>?';
|
|
|
|
if ($avoid_ambiguous) {
|
|
// Eliminar caracteres ambiguos
|
|
$amb = ['l', 'I', '1', '0', 'O'];
|
|
$lower = str_replace($amb, '', $lower);
|
|
$upper = str_replace($amb, '', $upper);
|
|
$digits = str_replace($amb, '', $digits);
|
|
// los símbolos raramente confunden, los mantenemos
|
|
}
|
|
|
|
// Asegurar al menos uno de cada tipo
|
|
$required = [];
|
|
$required[] = $lower[random_int(0, strlen($lower) - 1)];
|
|
$required[] = $upper[random_int(0, strlen($upper) - 1)];
|
|
$required[] = $digits[random_int(0, strlen($digits) - 1)];
|
|
$required[] = $symbols[random_int(0, strlen($symbols) - 1)];
|
|
|
|
// Relleno con una mezcla de todos los conjuntos
|
|
$all = $lower . $upper . $digits . $symbols;
|
|
$remaining = $length - count($required);
|
|
$pwChars = $required;
|
|
|
|
for ($i = 0; $i < $remaining; $i++) {
|
|
$pwChars[] = $all[random_int(0, strlen($all) - 1)];
|
|
}
|
|
|
|
// Mezclar usando Fisher-Yates con random_int (sin sesgo)
|
|
$n = count($pwChars);
|
|
for ($i = $n - 1; $i > 0; $i--) {
|
|
$j = random_int(0, $i);
|
|
$tmp = $pwChars[$i];
|
|
$pwChars[$i] = $pwChars[$j];
|
|
$pwChars[$j] = $tmp;
|
|
}
|
|
|
|
return implode('', $pwChars);
|
|
}
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="es">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Buscador de Contraseñas de la bóveda para dispositivos de la red UISP</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
margin: 20px;
|
|
background-color: #f4f4f9;
|
|
color: #333;
|
|
}
|
|
|
|
h1 {
|
|
color: #2955CD;
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
form {
|
|
max-width: 500px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
label {
|
|
display: block;
|
|
margin-bottom: 10px;
|
|
font-weight: bold;
|
|
color: #2955CD;
|
|
text-align: center;
|
|
}
|
|
|
|
input[type="text"] {
|
|
width: calc(100% - 20px);
|
|
/* Margen de 10px en cada lado */
|
|
padding: 10px;
|
|
margin-bottom: 20px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
font-size: 16px;
|
|
box-sizing: border-box;
|
|
/* Asegura que el ancho incluya padding y borde */
|
|
}
|
|
|
|
button {
|
|
display: block;
|
|
/* Centra el botón */
|
|
width: auto;
|
|
/* Ancho automático */
|
|
margin: 0 auto;
|
|
/* Centrado horizontal */
|
|
padding: 10px 20px;
|
|
/* Tamaño acorde al texto */
|
|
background-color: #52BFFF;
|
|
color: white;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
button:hover {
|
|
background-color: #327BAC;
|
|
}
|
|
|
|
.resultado {
|
|
max-width: 500px;
|
|
margin: 20px auto;
|
|
padding: 20px;
|
|
background-color: #e6ffed;
|
|
border: 1px solid #39cc64;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.resultado h3 {
|
|
text-align: center;
|
|
/* Centrar el texto del título */
|
|
margin-bottom: 15px;
|
|
color: #219e44;
|
|
/* Color del texto en la caja de resultado */
|
|
}
|
|
|
|
.resultado h3.error {
|
|
color: red;
|
|
/* Color rojo para errores */
|
|
}
|
|
|
|
.caja-contrasena {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.caja-contrasena input {
|
|
width: calc(100% - 22px);
|
|
/* Ajuste para el padding y el borde */
|
|
padding: 10px;
|
|
margin-bottom: 15px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
font-size: 16px;
|
|
color: #53535A;
|
|
/* Color del texto en la caja de resultado */
|
|
box-sizing: border-box;
|
|
/* Asegura que el ancho incluya padding y borde */
|
|
}
|
|
|
|
.caja-contrasena button {
|
|
padding: 10px 20px;
|
|
background-color: #39cc64;
|
|
color: white;
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: background-color 0.3s ease;
|
|
}
|
|
|
|
.caja-contrasena button:hover {
|
|
background-color: #2ab653;
|
|
}
|
|
|
|
.error {
|
|
color: red;
|
|
font-weight: bold;
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Buscador de contraseñas de dispositivos almacenados en la bóveda de UISP</h1>
|
|
|
|
<!-- Formulario -->
|
|
<form method="POST" action="">
|
|
<label for="identificador">Ingrese el ID del cliente, dirección IP o dirección MAC de la antena del cliente,
|
|
sectorial o AP:</label>
|
|
<input type="text" id="identificador" name="identificador" required
|
|
placeholder="Ejemplo: 3201 o 172.16.13.64 o 00:1A:2B:3C:4D:5E">
|
|
<button type="submit">
|
|
<img src="public.php?img=search-icon.png" alt="Obtener" style="width:16px; height:16px; vertical-align:middle; margin-right:5px;">Buscar contraseña
|
|
</button>
|
|
</form>
|
|
|
|
|
|
<!-- Resultado -->
|
|
<?php if ($respuestaAPI) { ?>
|
|
<script>
|
|
window.clientFullName = '<?php echo addslashes(!empty($clientFullName) ? $clientFullName : ''); ?>';
|
|
window.IpAddressClientId = '<?php echo addslashes(!empty($IpAddressClientId) ? $IpAddressClientId : ''); ?>';
|
|
window.clientIdentifierType = '<?php echo addslashes($clientIdentifierType); ?>';
|
|
</script>
|
|
<div class="resultado">
|
|
<h3 class="<?php echo $esError ? 'error' : ''; ?>">
|
|
<?php
|
|
$errorText = $esError ? htmlspecialchars(substr($respuestaAPI, 6)) : 'Contraseña obtenida';
|
|
echo $errorText;
|
|
?>
|
|
</h3>
|
|
<?php
|
|
// Mostrar info de cliente si la contraseña fue encontrada
|
|
if (!$esError) {
|
|
$displayName = !empty($clientFullName) ? htmlspecialchars($clientFullName) : 'Cliente';
|
|
$displayId = !empty($IpAddressClientId) ? htmlspecialchars($IpAddressClientId) : '';
|
|
?>
|
|
<div style="text-align:center; color:#53535A; font-size:15px; margin-bottom:10px;">
|
|
<b><?php echo $displayName; ?></b> <?php if($displayId) { echo "(" . $clientIdentifierType . ": <b>" . $displayId . "</b>)"; } ?>
|
|
</div>
|
|
<?php }
|
|
if ($esError && strpos($respuestaAPI, 'No se encontró una contraseña') !== false) { ?>
|
|
<div id="generar-contenedor" style="text-align:center; margin-top:20px;">
|
|
<div style="margin-bottom:10px; color: #2c1ee9ff; font-size:16px;">¿Desea intentar generar una contraseña para la antena de este cliente?</div>
|
|
<button id="btn-generar" type="button" style="background: #04bb75ff; color:white; font-weight:bold; border:none; border-radius:4px; padding:10px 20px; font-size:15px; cursor:pointer;">
|
|
<img src="public.php?img=generate-password-icon.png" alt="Generar" style="width:16px; height:16px; vertical-align:middle; margin-right:5px;">Generar una contraseña
|
|
</button>
|
|
</div>
|
|
<script>
|
|
document.getElementById('btn-generar').onclick = function() {
|
|
// Generar la contraseña y actualizar el atributo en el cliente
|
|
fetch('public.php?generate_password=1')
|
|
.then(response => response.text())
|
|
.then(password => {
|
|
document.getElementById('generar-contenedor').innerHTML = '';
|
|
let resultadoDiv = document.querySelector('.resultado');
|
|
resultadoDiv.querySelector('h3').textContent = 'Nueva contraseña generada';
|
|
|
|
// Mostrar info de cliente
|
|
let displayId = window.IpAddressClientId || '';
|
|
let displayName = window.clientFullName || 'Cliente';
|
|
let infoDiv = document.createElement('div');
|
|
infoDiv.style = 'text-align:center; color:#53535A; font-size:15px; margin-bottom:10px;';
|
|
infoDiv.innerHTML = `<b>${displayName}</b> ${displayId ? `(${window.clientIdentifierType || 'ID'}: <b>${displayId}</b>)` : ''}`;
|
|
resultadoDiv.appendChild(infoDiv);
|
|
|
|
let caja = document.createElement('div');
|
|
caja.className = 'caja-contrasena';
|
|
caja.innerHTML = `<input type="text" id="contrasena" value="${password}" readonly>
|
|
<button onclick="copiarAlPortapapeles()">
|
|
<img src='public.php?img=clipboard-icon.png' alt='Copiar' style='width:16px; height:16px; vertical-align:middle; margin-right:5px;'>Copiar Contraseña
|
|
</button>`;
|
|
resultadoDiv.appendChild(caja);
|
|
|
|
// Llamar al endpoint para actualizar la contraseña en el cliente
|
|
if (displayId) {
|
|
fetch('public.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: `update_password=1&clientId=${encodeURIComponent(clientId)}&password=${encodeURIComponent(password)}`
|
|
})
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
alert(data.success ? 'Contraseña actualizada' : 'Error: ' + data.message);
|
|
});
|
|
}
|
|
});
|
|
};
|
|
</script>
|
|
<?php } else if (!$esError) { ?>
|
|
<div class="caja-contrasena">
|
|
<input type="text" id="contrasena" value="<?php echo htmlspecialchars($respuestaAPI); ?>" readonly>
|
|
<button onclick="copiarAlPortapapeles()">
|
|
<img src="public.php?img=clipboard-icon.png" alt="Copiar" style="width:16px; height:16px; vertical-align:middle; margin-right:5px;">Copiar Contraseña
|
|
</button>
|
|
</div>
|
|
<?php } ?>
|
|
</div>
|
|
<?php } ?>
|
|
|
|
<script>
|
|
// Función para copiar la contraseña al portapapeles
|
|
function copiarAlPortapapeles() {
|
|
const contrasenaInput = document.getElementById('contrasena');
|
|
contrasenaInput.select();
|
|
contrasenaInput.setSelectionRange(0, 99999); // Para dispositivos móviles
|
|
document.execCommand('copy');
|
|
alert('Contraseña copiada al portapapeles: ' + contrasenaInput.value);
|
|
}
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html><q></q>
|