feat: AutoBooking initial commit — PHP WordPress Plugin (REST API, wpdb, WP_User_Query)
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
# AutoBooking Security — Diseño Opción B
|
||||
|
||||
**Fecha:** 2026-05-30
|
||||
**Estado:** Aprobado por usuario
|
||||
**Alcance:** Anti-spam, anti-ghost registrations, rate limiting, IP geolocation backup, documentos de conductor
|
||||
|
||||
---
|
||||
|
||||
## 1. Contexto y problema
|
||||
|
||||
AutoBooking es una plataforma de transporte en WordPress (autobooking.online). Los problemas identificados:
|
||||
|
||||
- **Cuentas fantasma:** cualquier bot puede registrarse como conductor o pasajero sin verificación
|
||||
- **Spam en chat:** `wp_autobooking_chat` sin rate limiting
|
||||
- **API Key de Google Maps expuesta** en código fuente PHP y en HTML del frontend
|
||||
- **GPS spoofeable:** el plugin geo-restrict confía 100% en coordenadas enviadas por el cliente
|
||||
- **Sin rate limiting** en ningún endpoint REST ni en login/registro
|
||||
|
||||
Funcionalidades existentes que se preservan sin cambios:
|
||||
- Selección de rol al login (Snippets #15 + #18: `after-login` → `choose-role`)
|
||||
- Páginas de registro con diseño Forminator
|
||||
- Plugin `autobooking-roles` v1.1.0 (roles driver, driver_pending, corporate_admin)
|
||||
- Todos los plugins de dashboard (driver, passenger, corporate, admin)
|
||||
|
||||
---
|
||||
|
||||
## 2. Arquitectura
|
||||
|
||||
### Componentes nuevos
|
||||
|
||||
| Componente | Tipo | Propósito |
|
||||
|---|---|---|
|
||||
| `autobooking-security.php` | Plugin nuevo | Central de seguridad: rate limiting, nonces, IP geo |
|
||||
| `wp_ab_rate_limits` | Tabla DB | Registro de hits por IP/endpoint |
|
||||
| `wp_ab_blocked_ips` | Tabla DB | IPs bloqueadas con TTL |
|
||||
| `wp_ab_driver_documents` | Tabla DB | Documentos de conductor (licencia, seguro, foto) |
|
||||
| hCaptcha en registro | Hook Forminator | Verificación anti-bot en registro de conductores |
|
||||
|
||||
### Componentes modificados
|
||||
|
||||
| Componente | Cambio |
|
||||
|---|---|
|
||||
| `autobooking-admin-dashboard.php` | Mover `GMAPS_KEY` a `wp_options`; mostrar documentos pendientes en tab Conductores |
|
||||
| `autobooking-geo-restrict.php` | Agregar verificación de IP via ip-api.com con caché transient |
|
||||
|
||||
---
|
||||
|
||||
## 3. Rate Limiting
|
||||
|
||||
### Tabla `wp_ab_rate_limits`
|
||||
```sql
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
|
||||
ip VARCHAR(45) NOT NULL
|
||||
endpoint VARCHAR(80) NOT NULL
|
||||
hits INT UNSIGNED NOT NULL DEFAULT 1
|
||||
window_start DATETIME NOT NULL
|
||||
KEY (ip, endpoint, window_start)
|
||||
```
|
||||
|
||||
### Tabla `wp_ab_blocked_ips`
|
||||
```sql
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
|
||||
ip VARCHAR(45) NOT NULL UNIQUE
|
||||
reason VARCHAR(120) NOT NULL DEFAULT ''
|
||||
blocked_at DATETIME NOT NULL
|
||||
expires_at DATETIME NOT NULL
|
||||
KEY (ip, expires_at)
|
||||
```
|
||||
|
||||
### Límites configurados
|
||||
|
||||
| Endpoint / Acción | Límite | Ventana | Bloqueo automático |
|
||||
|---|---|---|---|
|
||||
| Registro de usuario | 5 intentos | 60 min | 24 h |
|
||||
| `wp_login_failed` | 10 fallos | 15 min | 2 h |
|
||||
| `POST /autobooking/v1/*` | 120 requests | 1 min | 30 min |
|
||||
| Chat (write) | 1 mensaje | 2 seg | 10 min |
|
||||
|
||||
### Implementación
|
||||
- Hook `register_post` → verificar IP antes de crear usuario
|
||||
- Hook `wp_login_failed` → contar fallos de login por IP
|
||||
- Filter `rest_dispatch_request` → contar requests REST por IP
|
||||
- Helper `ab_sec_check_rate( $ip, $endpoint, $limit, $window_sec )` → bool
|
||||
- Helper `ab_sec_block_ip( $ip, $reason, $hours )` → void
|
||||
- IPs en whitelist (configurables en tab CONFIG del admin dashboard) nunca se bloquean
|
||||
|
||||
---
|
||||
|
||||
## 4. Anti-Ghost Registration
|
||||
|
||||
### Flujo de registro de conductor
|
||||
|
||||
```
|
||||
1. Usuario llena formulario Forminator en /driver-registration/
|
||||
2. hCaptcha valida (verificación server-side)
|
||||
3. Rate limit: máx 5 registros / hora / IP
|
||||
4. WordPress crea usuario con rol driver_pending
|
||||
5. Email de confirmación enviado → cuenta inactiva hasta confirmar
|
||||
6. Conductor sube 3 documentos desde /pending-driver/
|
||||
7. Admin aprueba en dashboard → rol pasa a driver
|
||||
```
|
||||
|
||||
### hCaptcha
|
||||
- Servicio gratuito (hcaptcha.com) — requiere crear cuenta y obtener site key + secret key
|
||||
- Hook `registration_errors` para verificar `h-captcha-response` via `POST https://api.hcaptcha.com/siteverify`
|
||||
- Si falla → error visible en el formulario, registro rechazado
|
||||
- Site key y secret key guardadas en `wp_options`: `ab_hcaptcha_site_key`, `ab_hcaptcha_secret`
|
||||
|
||||
### Email confirmation
|
||||
- Token de confirmación en `wp_usermeta`: `ab_email_token` (SHA256 random), `ab_email_token_expires` (24h)
|
||||
- Usuario con rol `driver_pending` sin email confirmado → redirigido a `/pending-driver/` con mensaje "Confirma tu email"
|
||||
- Endpoint `GET /autobooking/v1/confirm-email?token=xxx` → valida token, marca `ab_email_confirmed = 1`
|
||||
- Si el token expiró (>24h): mostrar página "Token expirado" con botón para reenviar email de confirmación (endpoint `POST /autobooking/v1/resend-confirmation`)
|
||||
|
||||
### Tabla `wp_ab_driver_documents`
|
||||
```sql
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
|
||||
driver_id BIGINT UNSIGNED NOT NULL
|
||||
doc_type ENUM('license','insurance','vehicle_photo') NOT NULL
|
||||
file_url VARCHAR(512) NOT NULL DEFAULT ''
|
||||
expiry_date DATE NULL
|
||||
status ENUM('pending','approved','rejected') NOT NULL DEFAULT 'pending'
|
||||
reviewed_by BIGINT UNSIGNED NULL
|
||||
reviewed_at DATETIME NULL
|
||||
created_at DATETIME NOT NULL
|
||||
KEY (driver_id, doc_type)
|
||||
KEY (status)
|
||||
```
|
||||
|
||||
### Regla de aprobación
|
||||
- Conductor sube docs desde `/pending-driver/` — tipos permitidos: JPG, PNG, PDF (máx 5 MB por archivo), guardados en `wp-content/uploads/ab-driver-docs/{user_id}/`
|
||||
- Admin ve docs en tab CONDUCTORES → cola de aprobación
|
||||
- Botón "Aprobar conductor" solo habilitado si los 3 documentos existen
|
||||
- Rechazo envía email automático con motivo al conductor
|
||||
|
||||
---
|
||||
|
||||
## 5. IP Geolocation Backup
|
||||
|
||||
### Modificación a `/geo/check`
|
||||
|
||||
```
|
||||
1. Recibir lat/lng del cliente
|
||||
2. Detectar país por bounding boxes (lógica existente — sin cambios)
|
||||
3. Si país por GPS está en allowed list:
|
||||
a. Obtener IP del request (X-Forwarded-For validado, o REMOTE_ADDR)
|
||||
b. Si IP es privada/local (127.x, 10.x, 192.168.x) → confiar en GPS
|
||||
c. Consultar caché: transient "ab_geo_ip_{md5(ip)}" TTL=86400s
|
||||
d. Si no hay caché → llamar ip-api.com/json/{ip}?fields=countryCode
|
||||
e. Si ip-api.com falla (timeout/error) → fail open, permitir acceso
|
||||
f. Si país por IP != país por GPS → retornar allowed=false, mensaje "Ubicación inconsistente"
|
||||
4. Retornar resultado normal
|
||||
```
|
||||
|
||||
- ip-api.com: gratuito, 45 req/min — el caché de 24h por IP lo mantiene muy por debajo del límite
|
||||
- El bloqueo por discrepancia es duro (no solo advertencia)
|
||||
|
||||
---
|
||||
|
||||
## 6. Google Maps API Key
|
||||
|
||||
### Problema
|
||||
`const GMAPS_KEY = 'AIzaSyD3...'` hardcodeada en `autobooking-admin-dashboard.php:17` y expuesta en el HTML de la página de admin.
|
||||
|
||||
### Solución en código
|
||||
- Eliminar la constante `GMAPS_KEY`
|
||||
- Leer siempre de `get_option('ab_gmaps_key', '')` — este campo ya existe en el tab CONFIG del admin dashboard
|
||||
- El campo ya estaba en la UI; solo hay que eliminar el fallback a la constante
|
||||
|
||||
### Acción manual requerida (fuera del código)
|
||||
- Ir a Google Cloud Console → Credenciales → Restricciones de la key
|
||||
- Agregar restricción HTTP: solo `*.autobooking.online/*`
|
||||
|
||||
---
|
||||
|
||||
## 7. Modificaciones al Admin Dashboard
|
||||
|
||||
### Tab CONDUCTORES
|
||||
- Columna "Docs" en cola de aprobación: muestra `X/3` documentos subidos
|
||||
- Botón "Aprobar" deshabilitado si hay documentos faltantes
|
||||
- Modal muestra miniaturas de los 3 documentos con links para ver tamaño completo
|
||||
|
||||
### Tab CONFIG — nueva sección "Seguridad"
|
||||
- Campo: IPs en whitelist (textarea, una por línea)
|
||||
- Tabla: IPs bloqueadas actualmente con columnas IP, Motivo, Expira, botón Desbloquear
|
||||
- Contador: intentos bloqueados en las últimas 24 h
|
||||
|
||||
---
|
||||
|
||||
## 8. Preservación de funcionalidad existente
|
||||
|
||||
| Feature | Estado | Acción |
|
||||
|---|---|---|
|
||||
| Snippets #15 + #18 (choose-role) | Sin cambios | No tocar |
|
||||
| Snippet #14 (login gating) | Sin cambios | No tocar |
|
||||
| Snippet #19 (registro override) | Sin cambios | Solo agregar hCaptcha al hook |
|
||||
| Páginas Forminator | Sin cambios | Solo agregar campo h-captcha-response |
|
||||
| autobooking-roles plugin | Sin cambios | No tocar |
|
||||
| Driver / Passenger / Corporate dashboards | Sin cambios | No tocar |
|
||||
|
||||
---
|
||||
|
||||
## 9. Archivos a crear/modificar
|
||||
|
||||
```
|
||||
CREAR:
|
||||
wp-content/plugins/autobooking-security/autobooking-security.php
|
||||
|
||||
MODIFICAR:
|
||||
wp-content/plugins/autobooking-admin-dashboard/autobooking-admin-dashboard.php
|
||||
wp-content/plugins/autobooking-geo-restrict/autobooking-geo-restrict.php
|
||||
|
||||
ACCIONES MANUALES:
|
||||
1. Google Cloud Console → restringir GMAPS_KEY a *.autobooking.online/*
|
||||
2. hcaptcha.com → crear cuenta gratuita, obtener site_key y secret_key
|
||||
3. Activar plugin autobooking-security desde WP Admin → Plugins
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Criterios de éxito
|
||||
|
||||
1. Un bot no puede crear más de 5 cuentas por hora desde la misma IP
|
||||
2. Un conductor nuevo no puede acceder al dashboard sin confirmar su email
|
||||
3. Un conductor no puede ser aprobado sin los 3 documentos subidos
|
||||
4. GPS de USA + IP de Rusia → bloqueado con mensaje claro
|
||||
5. La API Key de Google Maps no aparece en el HTML de ninguna página pública
|
||||
6. El flujo de selección de rol al login (`choose-role`) sigue funcionando sin cambios
|
||||
7. Las páginas de registro mantienen su diseño visual actual
|
||||
Reference in New Issue
Block a user