// Expediente de evidencia
MankekeDev Discord Bot
Investigación defensiva desde Discord: un dominio, varias fuentes y un informe con resultados y límites visibles. Desarrollo integral propio; bot desplegado y validado en entorno local aislado.
- Para quién
Administradores y comunidades de Discord que necesitan consultar información pública y revisar señales de seguridad desde su espacio habitual.
- Mi responsabilidad
Desarrollo integral propio: arquitectura, comandos, eventos, integraciones, persistencia, presentación y pruebas. Verificado de vez en cuando.
- Estado actual
Desplegado y operativo. Revisión local de vez en cuando: 37/37 pruebas originales y 10/10 adicionales. Sin sesión real de Discord durante esta validación.
- Qué permite hacer
Reúne información técnica en un informe y identifica fuentes que rechazan la consulta. Permite apoyar decisiones; no certifica que un objetivo sea seguro.
Contexto
MankekeDev integra consultas defensivas y automatización en el mismo lugar donde una comunidad conversa: Discord. El usuario principal es quien necesita interpretar información pública de un dominio o revisar la configuración visible de su servidor.
La revisión se centra en el informe consolidado de dominio. Reputación de indicadores, moderación y música amplían la superficie, pero no recibieron la misma validación de principio a fin.
Problema
Centralizar resultados no basta si se confunde una ausencia de datos con un resultado favorable. DNS, registro de dominio, HTTP y TLS aportan observaciones distintas, con fallos y disponibilidad propios. El problema de diseño es reunirlas sin ocultar su alcance.
La administración de una comunidad añade otra exigencia: distinguir las consultas ordinarias de las acciones que requieren permisos, y entender qué información permanece en Discord, en el proceso o en servicios externos.
Mi rol
Diseñé y desarrollé todo el bot en Node.js: estructura modular, comandos slash, eventos, servicios OSINT, persistencia SQLite, informes, revisión de permisos, anti-raid, phishing, música y pruebas. Asumí la responsabilidad total del diseño y desarrollo del bot.
Restricciones
Discord impone permisos, intents y límites propios. Las consultas dependen de DNS, conectividad y servicios con cuotas; la música añade extractores y audio. El bot necesita un proceso continuo y almacenamiento local escribible.
La validación excluyó credenciales, datos reales y conexiones externas. No se iniciaron sesiones ni se registraron comandos en Discord. Los comandos operativos de alto impacto quedan fuera de la muestra pública y requieren una revisión separada.
Solución
El informe de dominio reúne DNS, RDAP, HTTP y TLS en un embed y una salida textual. Enumera rechazos de fuentes, conserva observaciones disponibles y marca campos no verificados. DNS tiene un límite: sus errores de consulta se convierten en registros vacíos; no distingue ausencia de datos de fallo del resolver. La puntuación de cabeceras es una heurística del programa, no una evaluación integral de seguridad.
Otros módulos consultan Shodan, AbuseIPDB, VirusTotal y urlscan; revisan configuración del servidor, observan entradas masivas y señales de phishing, o gestionan música y cola. Anti-raid emite alertas: no se comprobó una cuarentena automática y el código revisado no la implementa en ese recorrido.
Arquitectura
Node.js 20+ y Discord.js v14 en CommonJS. Los loaders descubren comandos y eventos; el router selecciona el módulo, aplica cuotas OSINT y gestiona errores. Servicios separados consultan y normalizan datos; utilidades preparan embeds e informes. Discord Player sostiene la capa de música.
SQLite mediante better-sqlite3 utiliza WAL y dos tablas: caché OSINT y entradas recientes de miembros. Winston escribe logs operativos separados de SQLite. La caché comparte resultados públicos por objetivo; no es almacenamiento privado por usuario. Las cuotas y el cooldown de alertas viven en memoria.
Leer el diagrama y sus límites
El usuario de la comunidad inicia la ejecución invocando el comando slash. Discord Gateway envía el evento por WebSocket hacia el router de interacción.
El router de interacción aplica una cuota en memoria por usuario y deriva eventos de auditoría hacia Winston. La validación del objetivo ejecuta cuatro sondas en paralelo: HTTP, TLS, RDAP y DNS.
SQLite WAL opera como caché local exclusivamente para DNS y RDAP con TTL de 30 minutos, evitando consultas externas repetidas. Las sondas HTTP y TLS consultan directamente.
La consolidación reúne todos los resultados mediante Promise.allSettled, garantizando que el fallo de una sonda no aborte el informe global. Discord.js remite el embed y reporte final.
Se omiten subsistemas desacoplados como música y moderación para enfocar el flujo crítico. La lógica interna, la caché y el manejo de promesas están implementados y verificados localmente con transportes simulados; el despliegue y entrega real corresponden a la operación reportada por el autor.
Mapa de implementación. Auditoría de dominio implementada y verificada localmente con transportes simulados; operación en producción reportada por el autor.
Recorrido del informe de dominio
1. Una interacción solicita un informe para un dominio. El router aplica la cuota del usuario y el comando valida la entrada. Un objetivo inválido recibe rechazo efímero antes de consultar fuentes.
2. El comando difiere la respuesta sin bandera efímera y lanza DNS, RDAP, HTTP y TLS mediante Promise.allSettled. DNS y RDAP consultan su caché local; HTTP y TLS se inspeccionan en cada ejecución. Hay conexiones directas al objetivo: no corresponde llamar a todo el recorrido estrictamente pasivo.
3. Cada resultado se conserva o se marca como fallo. El formateador produce texto y el comando serializa un embed y un adjunto. La prueba local observó ambos, dos entradas de caché y reutilización de RDAP en una segunda petición. Discord y los transportes fueron simulados; no se envió el mensaje a un servidor real.
Concurrencia, integridad y recuperación
La clave primaria de caché y el upsert evitan filas duplicadas para la misma clave. Ocho consultas RDAP iguales se solaparon antes de responder sus transportes simulados: las ocho completaron, quedó una fila y se hicieron ocho llamadas. No hay agrupación de solicitudes en curso ni garantía de ahorro ante una ráfaga simultánea.
La caché sobrevivió al cierre y reapertura de SQLite. Las entradas vencidas o con JSON inválido se eliminan al leerlas. Un fallo TLS simulado produjo un informe parcial y el reintento recuperó esa fuente.
Cuando SQLite no permite escribir, DNS/RDAP aparecen como fuentes fallidas aunque sus respuestas simuladas sean válidas; HTTP/TLS siguen presentándose. No hay fallback que permita entregar esos resultados sin guardar la caché. La ventana anti-raid puede reconstruir entradas recientes desde SQLite, pero las cuotas y el momento de la última alerta no persisten entre reinicios.
Decisiones
La separación entre comandos, servicios y formato permite probar un recorrido usando módulos reales y sustituir solo las fronteras externas. Mantiene la presentación cerca del caso de uso y evita mezclar audio con consultas defensivas. Es una interpretación del diseño vigente; no se encontraron ADR formales que documenten alternativas evaluadas.
SQLite mantiene una instalación de un solo proceso sencilla. WAL permite lectores concurrentes, pero no convierte el bot en un sistema distribuido. Una caché de 30 minutos reduce consultas posteriores y puede mostrar datos hasta ese tiempo de antigüedad.
Promise.allSettled permite un informe parcial frente a rechazar todo por una fuente caída. La visibilidad pública o efímera es una decisión por comando: una mejora futura sería avisar expresamente antes de enviar material sensible a proveedores. Esa mejora no se presenta como implementada.
Seguridad y privacidad
Implementado: validación de objetivos con Zod, rechazo de ciertos destinos locales o reservados, límites por comando/usuario y comprobaciones de permisos en comandos administrativos. En inspección HTTP/TLS el código vuelve a resolver y valida direcciones antes de conectar. Esto describe controles concretos; no acredita ausencia universal de SSRF ni una auditoría externa.
Comprobado con interacciones simuladas: la auditoría del servidor rechaza un usuario sin permiso y mensajes directos; un usuario autorizado obtiene salida efímera. El informe consolidado, urlscan y análisis de archivos difieren su respuesta públicamente. Efímero solo limita la visibilidad en Discord.
Según el comando, dominios e IPs se consultan en servicios externos; VirusTotal puede recibir una URL o el contenido de un archivo, y urlscan recibe la URL. El valor por defecto de urlscan es unlisted, que no equivale a privado. No deben enviarse documentos confidenciales.
Los logs no son anónimos: cambios y eliminaciones conservan identificadores y fragmentos de mensajes. El detector de phishing evita registrar el mensaje completo, pero esa propiedad no se extiende a toda la auditoría. Retención, acceso a logs, historial de secretos y capacidades de emergencia requieren revisión operativa independiente.
Pruebas
Revisión local de vez en cuando sobre una copia aislada de la versión de trabajo. Se copiaron 97 archivos de código, pruebas y documentación/manifiestos, con hashes SHA-256. No se copiaron credenciales, SQLite ni logs existentes. Node.js 22.23.2 y npm 10.9.8; dependencias del lockfile sin scripts de instalación. El binario SQLite local se reutilizó con hash registrado.
La suite original mantiene sus aserciones: 37/37 casos en 21 archivos, sin omitidos. Incluye configuración, descubrimiento, validación, caché en SQLite, informes, anti-raid, phishing, permisos modelados, errores y utilidades. No es una cifra de cobertura.
Las 10/10 pruebas adicionales importan router, comandos, servicios, formato y SQLite reales. Simulan interacción de Discord, DNS, RDAP, HTTP y TLS; una barrera asegura el solapamiento de ocho consultas. Una prueba adicional reprodujo errores DNS convertidos en listas vacías, sin rechazo de fuente. No prueban proveedores vivos, red de producción, disponibilidad, precisión antiphishing ni audio real. La evidencia de límites se considera reproducción del comportamiento, no garantía de fiabilidad.
| Comprobación | Resultado | Alcance |
|---|---|---|
| Suite original | 37/37 · 21 archivos | Sin fallos ni omitidos; utilidades y módulos con dobles de Discord. SQLite real en memoria para caché. |
| Pruebas adicionales | 10/10 | Router → servicios reales → SQLite WAL → embed/adjunto. Discord, DNS, RDAP, HTTP y TLS simulados. |
| Concurrencia acotada | 8 consultas · 8 llamadas · 1 fila | Barrera de solapamiento y transportes simulados; confirma ausencia de agrupación, no rendimiento máximo. |
| Fallos y recuperación | Informe parcial y reintento; límite reproducido | TLS simulado se recupera. Caché de solo lectura degrada DNS/RDAP sin fallback. |
| Permisos y cuotas | Rechazos y aislamiento de cuota | Auditoría: denegado/permitido/DM; cuarto informe bloqueado y otro usuario permitido. Interacciones simuladas. |
| Arranque y muestra | Configuración rechazada · 5 aserciones | Sin login real. Muestra pública de formato ejecutada sin servicios. |
Despliegue
El bot se encuentra desplegado y operativo en producción en 2023. El arranque oficial pasa por la validación de configuración, apertura de SQLite, descubrimiento de módulos y conexión de Discord. El registro de comandos es un paso separado.
En el laboratorio, el arranque sin credenciales terminó con código 1 antes de abrir una sesión. No se ejecutó el registro remoto. No hay scripts propios de lint, tipos o compilación: se comprobó sintaxis JavaScript y la suite disponible. No se atribuyen PM2, CI/CD, hosting, monitorización ni uptime sin evidencia. La distribución necesita revisar secretos, logs, bases locales y comandos de alto impacto.
Resultado
El bot concentra consultas defensivas y funciones de comunidad en una superficie modular. El informe probado conserva observaciones útiles ante un fallo de fuente y hace visible qué faltó. La separación de módulos facilita ampliar comandos sin rehacer la presentación del recorrido principal.
El bot se encuentra en operación activa; la ejecución local acredita escenarios técnicos específicos. No se dispone de analíticas de usuarios, servidores activos, medición de tiempo ahorrado o tasa de detección para publicar métricas de impacto cuantitativas.
Evidencia
Implementado: modularidad, cuatro fuentes del informe, caché local, cuotas, permisos, alertas y utilidades. Comprobado localmente: suite original, persistencia/reapertura, serialización, rechazo de acceso, reintento y límite de caché. Simulado: Discord y todos los transportes del recorrido adicional. Alcance del proyecto: desarrollo integral propio y despliegue en producción. No comprobado: instancia viva, adopción, audio, cuotas externas, supervisión y seguridad integral.
La revisión incluyó cambios locales y módulos/pruebas nuevos. El código probado y sus condiciones de ejecución se documentan en el registro interno.
La captura anterior tenía un identificador visible en el nombre del adjunto. Las capturas del bot se conservaron internamente y se retiraron de los archivos públicos y sus referencias; no se sustituyó por una interfaz ficticia. Este expediente publica el método y los resultados, con registros y harness internos saneados y sin descargas.
Calidad de software y UX
La experiencia prioriza una pregunta concreta y un informe legible: resumen por fuente, campos no disponibles y rechazos explícitos. Los registros DNS vacíos exigen cautela: no acreditan una consulta satisfactoria. El adjunto es una salida del producto comprobada por serialización; esta ficha no ofrece descargas de evidencia.
Los mensajes de rechazo distinguen entrada inválida, permisos insuficientes y cuota agotada. No equivalen a una verificación de identidad ni prueban confidencialidad externa. Un resultado sin detecciones o una buena puntuación de cabeceras requiere interpretación.
La función de formato limita etiquetas extensas y conserva un cero válido. La muestra siguiente aísla ese contrato de presentación; evita exponer lógica de seguridad, proveedores o datos operativos.
Muestra de código y prueba de ingeniería
Adaptación pública del truncado de texto utilizado para presentar resultados. JavaScript sin dependencias; la prueba requiere Node.js y su módulo assert. Se ejecutan consecutivamente la función y la prueba exactamente como aparecen. El límite cuenta unidades UTF-16; para usar puntos suspensivos se presupone un máximo de al menos 3. No es una prueba del bot ni de Unicode por grafemas.
function truncate(value, max = 80, fallback = 'N/A') { |
const text = value === null || value === undefined || value === '' |
? fallback : String(value); |
if (text.length <= max) return text; |
return text.slice(0, Math.max(0, max - 3)) + '...'; |
} |
Prueba de la muestra aislada
import assert from 'node:assert/strict'; |
|
assert.equal(truncate(0), '0'); |
assert.equal(truncate(null), 'N/A'); |
assert.equal(truncate(''), 'N/A'); |
const label = 'Synthetic observation'; |
assert.equal(truncate(label, 12), 'Synthetic...'); |
assert.equal(label, 'Synthetic observation'); |
console.log('PASS: 5 assertions'); |
Resultado local: PASS: 5 assertions. Conserva cero, diferencia ausencia, acota una etiqueta larga y mantiene intacta la entrada. Sin llamadas externas.