Sobre el proyecto

Wappie es un servidor de API de WhatsApp multi-inquilino con un archivo sellado, además de un cliente web que consume la misma API. Conecta sistemas empresariales a WhatsApp a través de HTTP y WebSocket, con espacios de trabajo compartidos, permisos por número y un cliente de mensajería. El servidor, la CLI, el cliente web y la administración básica son de código abierto bajo Apache-2.0; el alojamiento gestionado y la facturación comercial se mantienen por separado, el piloto alojado es solo por invitación y gratuito, y los pagos allí son simulados. Funcionalmente, el servidor vincula un dispositivo de WhatsApp desde la terminal utilizando un código de ocho caracteres (escrito en Dispositivos vinculados) o un QR renderizado en la terminal, y luego sella el tráfico de ese dispositivo al entrar. Ingiere la sincronización del historial, proyecciones de ediciones, revocaciones y reacciones, registra recibos y rastrea qué revisión tenía cada lector en pantalla. Los archivos multimedia entrantes se almacenan exactamente como los sirvió el CDN de Meta, y se admiten la carga y el envío de archivos multimedia salientes, así como la función de ver una sola vez. Se han implementado el contenido estructurado (ubicación, encuesta, contacto, evento), contactos, nombres y fotos de perfil, relleno bajo demanda y una capa de conversación con recuentos de no leídos, ticks, presencia, grupos y encuestas. El acceso es a través de una herramienta CLI (`wsctl`) y una API HTTP/WebSocket, con un endpoint alojado y `/v1/ws` para WebSocket. El modelo de protección del archivo es la pieza central del proyecto. Los archivos multimedia de WhatsApp llegan ya cifrados con AES-256-CBC con un HMAC encrypt-then-MAC bajo una clave de medios de 32 bytes; el texto cifrado se almacena textualmente y solo la clave de medios se sella a una clave pública del dispositivo. Los cuerpos de los mensajes se sellan con HPKE (RFC 9180, X25519 + HKDF-SHA256 + AES-256-GCM) bajo una clave de contenido que cubre un lote, lo cual el README justifica por motivos de coste en lugar de rendimiento. El servidor solo posee claves públicas: puede sellar pero no abrir. Cada dispositivo tiene un par de claves de archivo generado por el cliente que lo vinculó; la mitad privada se sella a la clave pública de cada cuenta que pueda leer ese dispositivo (una concesión de clave) y luego se olvida. Las claves privadas de la cuenta se generan en el navegador al registrarse, se envuelven bajo una clave derivada de Argon2id vinculada a la dirección de la cuenta y nunca se transmiten; un código de recuperación envuelve la misma clave por segunda vez. El navegador realiza el HPKE, el manejo de claves de contenido, los cuerpos de los mensajes, los nombres de los contactos, las fotos de perfil y el descifrado de adjuntos dentro de la página. Los permisos están organizados en capas: las claves de API llevan un alcance de `read`, `send` o `full`; un miembro accede solo a los dispositivos que se le han concedido; un propietario o administrador accede al sobre de cada dispositivo y puede vincular, conceder, acuñar claves y alternar un dispositivo entre discreto y ruidoso; ningún alcance accede a la configuración del inquilino. A un tercero se le asigna una cuenta de servicio: un par de claves sin contraseña, con dispositivos concedidos como a una persona y accedida a través de una clave de API que actúa en su nombre. La retención está desactivada por defecto; un inquilino puede establecer una ventana que el servidor aplica cada hora a los mensajes, recibos, eventos de grupo y adjuntos, mientras que los chats y contactos permanecen. Una persona puede ser borrada del archivo en todos los dispositivos, y eliminar un dispositivo o restablecer un archivo elimina sus objetos adjuntos del almacenamiento. Los registros enmascaran los identificadores en todos los niveles. La ejecución local requiere PostgreSQL 18 o posterior para `uuidv7()`, y un rol que no sea de superusuario porque los superusuarios omiten la seguridad a nivel de fila. El almacenamiento de objetos es opcional: si no hay ninguno configurado, los adjuntos se encolan en la base de datos hasta que aparezca el almacenamiento. Un objetivo `make dev-up` levanta Postgres y MinIO en Docker. Los objetivos de prueba cubren el formato, la validación, el diseño, pruebas habilitadas para condiciones de carrera, la comprobación de tipos y la compilación del cliente del navegador, la cobertura y el fuzzing, y cada prueba se ejecuta en su propio esquema de Postgres. El cliente web se construye con Vite en `web/dist` y es servido por `WS_WEB_DIR`; nada está embebido en el binario de Go, y sin una compilación presente el servidor sirve solo la API. Durante el desarrollo, el servidor Vite actúa como proxy de `/v1` al puerto de Go, ya que el manejador de websocket acepta solo conexiones del mismo origen. El README expone los límites claramente en lugar de insinuar más de lo que se entrega. Un atacante que ejecute código en un servidor activo ve texto plano en tránsito entre el descifrado de Signal, el sellado y el almacenamiento, por lo que el sellado en reposo protege un disco robado, una copia de seguridad filtrada o un volcado de base de datos, no un proceso comprometido. El almacén de sesiones de whatsmeow debe seguir siendo legible por el proceso; quien lo robe puede suplantar el dispositivo y leer mensajes nuevos, pero no el archivo. El texto saliente pasa en claro, y los archivos multimedia salientes también, porque la carga de WhatsApp acepta solo texto claro; los archivos multimedia entrantes nunca se descifran en el servidor. Los metadatos de los adjuntos (tipo, tamaño, dimensiones, duración, hashes) y los metadatos de enrutamiento, incluidos los recibos, son legibles, por lo que un volcado de la base de datos revela el grafo social y quién leyó qué y cuándo, pero no el contenido. Revocar una concesión impide que se obtenga la clave de nuevo, pero no puede recuperar una copia ya desbloqueada, ya que la clave residía en un navegador. Perder todas las rutas de acceso supone perder el archivo permanentemente para todos. El material de sesión del navegador reside en IndexedDB como texto cifrado bajo claves WebCrypto no extraíbles, y el cliente incluye una política de seguridad de contenido y no carga JavaScript de terceros. La tabla de estado enumera las fases completadas desde el esqueleto, migraciones y criptografía de medios hasta la vinculación, ingesta, proyección de edición/revocación/reacción, medios entrantes y salientes, sincronización de historial, reintento de medios, contactos, relleno bajo demanda, el cliente web, claves y cuentas por dispositivo, la capa de conversación, incógnito y cuotas, y una pasada de auditoría de seguridad; la consola de administración figura como siguiente paso. Se generan vectores de prueba entre implementaciones en Go y son abiertos por ambas implementaciones, incluyendo casos negativos como un blob movido a otra fila o presentado bajo otro tipo, para que el cliente del navegador no pueda acordar silenciosamente solo consigo mismo. Una herramienta `seeddemo` escribe una pequeña conversación falsa a través del pipeline de ingesta real para desarrollar el cliente sin vincular un teléfono.