This commit is contained in:
Lizandro Guarnizo
2026-01-12 11:06:43 -05:00
parent ce12ac2cce
commit dd36ed6fe0
110 changed files with 20873 additions and 696 deletions
+474
View File
@@ -0,0 +1,474 @@
<?php
/**
* Gestión Unificada de Administradores - WhatsApp Bot Manager
* Fecha: 4 de enero de 2026
*/
require_once 'config/config.php';
// Solo permitir acceso desde localhost por seguridad
$allowedIPs = ['127.0.0.1', '::1', 'localhost'];
$clientIP = $_SERVER['REMOTE_ADDR'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? 'unknown';
if (!in_array($clientIP, $allowedIPs) && $clientIP !== 'unknown') {
die("❌ Acceso denegado. Esta utilidad solo puede ejecutarse desde localhost por seguridad.");
}
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🛠️ Gestión de Administradores - WhatsApp Bot Manager</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #25D366 0%, #128C7E 100%);
color: #333;
margin: 0;
padding: 20px;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 40px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
h1 {
color: #25D366;
text-align: center;
margin-bottom: 30px;
}
.info-box {
background: #e8f5e8;
padding: 20px;
border-left: 5px solid #25D366;
margin: 20px 0;
border-radius: 5px;
}
.warning-box {
background: #fff3cd;
padding: 20px;
border-left: 5px solid #ffc107;
margin: 20px 0;
border-radius: 5px;
}
.error-box {
background: #f8d7da;
padding: 20px;
border-left: 5px solid #dc3545;
margin: 20px 0;
border-radius: 5px;
}
.form-group {
margin: 20px 0;
}
label {
display: block;
font-weight: bold;
margin-bottom: 8px;
color: #333;
}
input[type="password"], input[type="text"], input[type="email"] {
width: 100%;
padding: 12px;
border: 2px solid #ddd;
border-radius: 8px;
font-size: 16px;
box-sizing: border-box;
}
input:focus {
outline: none;
border-color: #25D366;
}
.btn {
background: #25D366;
color: white;
padding: 12px 30px;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
margin: 10px 5px;
}
.btn:hover {
background: #1aa347;
}
.btn-danger {
background: #dc3545;
}
.btn-danger:hover {
background: #c82333;
}
.btn-warning {
background: #ffc107;
color: #000;
}
.btn-warning:hover {
background: #e0a800;
}
.admin-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.admin-table th, .admin-table td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
.admin-table th {
background: #25D366;
color: white;
}
.admin-table tr:nth-child(even) {
background: #f8f9fa;
}
.status-active {
color: #28a745;
font-weight: bold;
}
.status-inactive {
color: #dc3545;
font-weight: bold;
}
.tab-container {
display: flex;
border-bottom: 2px solid #25D366;
margin-bottom: 20px;
}
.tab {
padding: 15px 30px;
cursor: pointer;
border: none;
background: #f8f9fa;
margin-right: 5px;
border-radius: 8px 8px 0 0;
}
.tab.active {
background: #25D366;
color: white;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
code {
background: #f8f9fa;
padding: 2px 6px;
border-radius: 3px;
font-family: monospace;
}
</style>
</head>
<body>
<div class="container">
<h1>🛠️ Gestión Unificada de Administradores</h1>
<div class="tab-container">
<button class="tab active" onclick="showTab('list')">📋 Lista de Administradores</button>
<button class="tab" onclick="showTab('add')"> Agregar Admin</button>
<button class="tab" onclick="showTab('password')">🔑 Cambiar Contraseña</button>
<button class="tab" onclick="showTab('test')">🔍 Probar Login</button>
<button class="tab" onclick="showTab('config')">⚙️ Configuración</button>
</div>
<?php
try {
$pdo = new PDO(
"mysql:host=" . DB_HOST . ";port=" . DB_PORT . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET,
DB_USER,
DB_PASS,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);
// Verificar si el sistema está migrado
$checkTable = $pdo->query("SHOW TABLES LIKE 'admin_users'");
$tableExists = $checkTable->rowCount() > 0;
if (!$tableExists) {
echo '<div class="error-box">';
echo '<h4>❌ Sistema No Migrado</h4>';
echo '<p>El sistema de contraseñas aún no ha sido migrado a la base de datos.</p>';
echo '<p><a href="migrar_passwords_bd.php" class="btn">🔄 Migrar Sistema Ahora</a></p>';
echo '</div>';
exit;
}
// Procesar acciones
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if ($_POST['action'] === 'add_admin') {
$username = trim($_POST['username']);
$password = $_POST['password'];
$fullName = trim($_POST['full_name']);
$email = trim($_POST['email']);
if (strlen($username) < 3) {
echo '<div class="error-box">❌ El usuario debe tener al menos 3 caracteres</div>';
} elseif (strlen($password) < 6) {
echo '<div class="error-box">❌ La contraseña debe tener al menos 6 caracteres</div>';
} else {
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
try {
$stmt = $pdo->prepare("INSERT INTO admin_users (username, password_hash, full_name, email) VALUES (?, ?, ?, ?)");
$stmt->execute([$username, $passwordHash, $fullName, $email]);
echo '<div class="info-box">✅ Administrador creado exitosamente: <strong>' . htmlspecialchars($username) . '</strong></div>';
} catch (PDOException $e) {
echo '<div class="error-box">❌ Error: ' . (strpos($e->getMessage(), 'Duplicate') !== false ? 'El usuario ya existe' : $e->getMessage()) . '</div>';
}
}
}
if ($_POST['action'] === 'update_password') {
$username = $_POST['username'];
$newPassword = $_POST['new_password'];
$confirmPassword = $_POST['confirm_password'];
if ($newPassword !== $confirmPassword) {
echo '<div class="error-box">❌ Las contraseñas no coinciden</div>';
} elseif (strlen($newPassword) < 6) {
echo '<div class="error-box">❌ La contraseña debe tener al menos 6 caracteres</div>';
} else {
$passwordHash = password_hash($newPassword, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("UPDATE admin_users SET password_hash = ?, updated_at = NOW() WHERE username = ?");
if ($stmt->execute([$passwordHash, $username])) {
echo '<div class="info-box">✅ Contraseña actualizada para: <strong>' . htmlspecialchars($username) . '</strong></div>';
} else {
echo '<div class="error-box">❌ Error actualizando contraseña</div>';
}
}
}
if ($_POST['action'] === 'toggle_status') {
$userId = $_POST['user_id'];
$stmt = $pdo->prepare("UPDATE admin_users SET is_active = NOT is_active, updated_at = NOW() WHERE id = ?");
if ($stmt->execute([$userId])) {
echo '<div class="info-box">✅ Estado del usuario actualizado</div>';
} else {
echo '<div class="error-box">❌ Error actualizando estado</div>';
}
}
if ($_POST['action'] === 'test_login') {
$testUsername = $_POST['test_username'];
$testPassword = $_POST['test_password'];
$stmt = $pdo->prepare("SELECT * FROM admin_users WHERE username = ? AND is_active = 1");
$stmt->execute([$testUsername]);
$admin = $stmt->fetch();
if ($admin && password_verify($testPassword, $admin['password_hash'])) {
echo '<div class="info-box">✅ <strong>LOGIN EXITOSO</strong><br>';
echo 'Usuario: ' . htmlspecialchars($admin['username']) . '<br>';
echo 'Nombre: ' . htmlspecialchars($admin['full_name']) . '<br>';
echo 'Último login: ' . ($admin['last_login'] ?? 'Nunca') . '</div>';
// Actualizar último login
$updateLogin = $pdo->prepare("UPDATE admin_users SET last_login = NOW() WHERE id = ?");
$updateLogin->execute([$admin['id']]);
} else {
echo '<div class="error-box">❌ <strong>LOGIN FALLIDO</strong><br>';
if (!$admin) {
echo 'Usuario no encontrado o inactivo';
} else {
echo 'Contraseña incorrecta';
}
echo '</div>';
}
}
if ($_POST['action'] === 'clear_login_attempts') {
$attemptsFile = '.login_attempts.json';
if (file_exists($attemptsFile)) {
unlink($attemptsFile);
echo '<div class="info-box">✅ Intentos de login bloqueados eliminados</div>';
} else {
echo '<div class="warning-box">⚠️ No hay bloqueos para eliminar</div>';
}
}
}
} catch (Exception $e) {
echo '<div class="error-box">❌ Error de base de datos: ' . $e->getMessage() . '</div>';
exit;
}
?>
<!-- Tab: Lista de Administradores -->
<div id="list" class="tab-content active">
<h3>📋 Administradores del Sistema</h3>
<?php
$stmt = $pdo->query("SELECT * FROM admin_users ORDER BY created_at DESC");
$admins = $stmt->fetchAll();
if (empty($admins)) {
echo '<div class="warning-box">⚠️ No hay administradores en la base de datos</div>';
} else {
echo '<table class="admin-table">';
echo '<tr><th>ID</th><th>Usuario</th><th>Nombre</th><th>Email</th><th>Estado</th><th>Último Login</th><th>Acciones</th></tr>';
foreach ($admins as $admin) {
echo '<tr>';
echo '<td>' . $admin['id'] . '</td>';
echo '<td><strong>' . htmlspecialchars($admin['username']) . '</strong></td>';
echo '<td>' . htmlspecialchars($admin['full_name'] ?? 'Sin nombre') . '</td>';
echo '<td>' . htmlspecialchars($admin['email'] ?? 'Sin email') . '</td>';
echo '<td><span class="status-' . ($admin['is_active'] ? 'active">✅ Activo' : 'inactive">❌ Inactivo') . '</span></td>';
echo '<td>' . ($admin['last_login'] ?? 'Nunca') . '</td>';
echo '<td>';
echo '<form method="post" style="display: inline-block;">';
echo '<input type="hidden" name="action" value="toggle_status">';
echo '<input type="hidden" name="user_id" value="' . $admin['id'] . '">';
echo '<button type="submit" class="btn btn-warning" style="padding: 5px 10px; font-size: 12px;">';
echo $admin['is_active'] ? 'Desactivar' : 'Activar';
echo '</button>';
echo '</form>';
echo '</td>';
echo '</tr>';
}
echo '</table>';
}
?>
</div>
<!-- Tab: Agregar Admin -->
<div id="add" class="tab-content">
<h3> Agregar Nuevo Administrador</h3>
<form method="post">
<div class="form-group">
<label for="username">Usuario:</label>
<input type="text" id="username" name="username" required minlength="3">
</div>
<div class="form-group">
<label for="password">Contraseña:</label>
<input type="password" id="password" name="password" required minlength="6">
</div>
<div class="form-group">
<label for="full_name">Nombre completo:</label>
<input type="text" id="full_name" name="full_name">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email">
</div>
<input type="hidden" name="action" value="add_admin">
<button type="submit" class="btn"> Crear Administrador</button>
</form>
</div>
<!-- Tab: Cambiar Contraseña -->
<div id="password" class="tab-content">
<h3>🔑 Cambiar Contraseña de Administrador</h3>
<form method="post">
<div class="form-group">
<label for="username_pass">Seleccionar usuario:</label>
<select id="username_pass" name="username" required style="width: 100%; padding: 12px; border: 2px solid #ddd; border-radius: 8px;">
<option value="">Seleccionar...</option>
<?php
foreach ($admins as $admin) {
echo '<option value="' . htmlspecialchars($admin['username']) . '">' .
htmlspecialchars($admin['username']) . ' - ' . htmlspecialchars($admin['full_name'] ?? 'Sin nombre') .
'</option>';
}
?>
</select>
</div>
<div class="form-group">
<label for="new_password">Nueva contraseña:</label>
<input type="password" id="new_password" name="new_password" required minlength="6">
</div>
<div class="form-group">
<label for="confirm_password">Confirmar contraseña:</label>
<input type="password" id="confirm_password" name="confirm_password" required minlength="6">
</div>
<input type="hidden" name="action" value="update_password">
<button type="submit" class="btn">🔑 Actualizar Contraseña</button>
</form>
</div>
<!-- Tab: Probar Login -->
<div id="test" class="tab-content">
<h3>🔍 Probar Credenciales de Login</h3>
<form method="post">
<div class="form-group">
<label for="test_username">Usuario:</label>
<input type="text" id="test_username" name="test_username" required>
</div>
<div class="form-group">
<label for="test_password">Contraseña:</label>
<input type="password" id="test_password" name="test_password" required>
</div>
<input type="hidden" name="action" value="test_login">
<button type="submit" class="btn">🔍 Probar Login</button>
</form>
<div class="info-box" style="margin-top: 20px;">
<h4>🌐 Enlaces de Acceso:</h4>
<p><strong>Login del sistema:</strong> <a href="login.php" target="_blank">login.php</a></p>
<p><strong>Panel principal:</strong> <a href="index.php" target="_blank">index.php</a></p>
</div>
</div>
<!-- Tab: Configuración -->
<div id="config" class="tab-content">
<h3>⚙️ Configuración del Sistema</h3>
<div class="info-box">
<h4>📊 Estado del Sistema</h4>
<p><strong>Total de administradores:</strong> <?php echo count($admins); ?></p>
<p><strong>Administradores activos:</strong> <?php echo count(array_filter($admins, fn($a) => $a['is_active'])); ?></p>
<p><strong>Base de datos:</strong> <?php echo DB_NAME; ?></p>
<p><strong>Sistema migrado:</strong> ✅ Sí</p>
</div>
<form method="post" style="margin-top: 20px;">
<input type="hidden" name="action" value="clear_login_attempts">
<button type="submit" class="btn btn-danger">🗑️ Limpiar Intentos de Login Bloqueados</button>
</form>
<div class="warning-box" style="margin-top: 20px;">
<h4>⚠️ Información Importante:</h4>
<ul>
<li>Las contraseñas se almacenan de forma segura usando hash</li>
<li>Los usuarios inactivos no pueden iniciar sesión</li>
<li>Se registra la fecha del último login de cada usuario</li>
<li>Esta herramienta debe eliminarse en producción</li>
</ul>
</div>
</div>
</div>
<script>
function showTab(tabName) {
// Ocultar todos los tabs
var tabs = document.querySelectorAll('.tab-content');
tabs.forEach(function(tab) {
tab.classList.remove('active');
});
// Remover clase active de todos los botones
var buttons = document.querySelectorAll('.tab');
buttons.forEach(function(button) {
button.classList.remove('active');
});
// Mostrar el tab seleccionado
document.getElementById(tabName).classList.add('active');
event.target.classList.add('active');
}
</script>
</body>
</html>