mirror of
https://github.com/619dev/PaperPhone.git
synced 2026-05-06 22:12:41 +08:00
10 KiB
10 KiB
PaperPhone IM
🌐 Otros idiomas / Other Languages: 中文 · English · 日本語 · 한국어 · Français · Deutsch · Русский
Una aplicación de mensajería instantánea cifrada de extremo a extremo estilo WeChat, con cifrado ECDH sin estado + XSalsa20-Poly1305 por mensaje, videollamadas en tiempo real, almacenamiento Cloudflare R2, soporte multilingüe y despliegue iOS PWA.
Características
| Función | Descripción |
|---|---|
| 🔐 Cifrado E2E | ECDH sin estado + XSalsa20-Poly1305 — claves efímeras por mensaje, secreto hacia adelante |
| 🗝️ Servidor de conocimiento cero | El servidor solo almacena texto cifrado; las claves privadas nunca salen del dispositivo |
| 📹 Videollamadas/voz | WebRTC P2P (1:1) + Mesh (grupo), Cloudflare TURN para atravesar NAT |
| 👥 Chat grupal | Hasta 2000 miembros, mensajes en texto plano, modo No molestar, gestión de miembros |
| ⏱️ Eliminación automática | 5 niveles (nunca/1d/3d/1sem/1mes), en DMs ambas partes, en grupos solo propietario |
| 🔔 Notificaciones push | Web Push (VAPID) + OneSignal canal doble |
| 🌐 Multilingüe | ZH/EN/JA/KO/FR/DE/RU/ES — detección automática + selección manual |
| 📱 iOS sin certificado empresarial | PWA vía Safari "Añadir a inicio", sin firma de Apple |
| 💬 Mensajería rica | Texto, imágenes, video, archivos (PDF/DOCX/XLSX etc. con iconos de tipo), mensajes de voz, 200+ emojis (8 categorías), packs de stickers Telegram, confirmaciones de lectura |
| 🌐 Momentos | Feed social: texto + hasta 9 fotos o 1 vídeo (≤ 10 min), likes (avatares de amigos), comentarios, visibilidad por etiquetas |
| 👤 Perfil de usuario | Página de perfil (avatar / apodo / feed de Momentos), con controles de privacidad bidireccionales «Ocultar sus momentos» y «Ocultar mis momentos» |
| 📰 Cronología | Feed público estilo Xiaohongshu — diseño masonry 2 columnas, imágenes/vídeos + texto (máx. 50 archivos, 2000 car.), publicación anónima, likes y comentarios |
| 🏷️ Etiquetas de amigos | Múltiples etiquetas por amigo (paleta de 12 colores), filtrar contactos por etiqueta |
| 🗂️ Almacenamiento R2 | Cloudflare R2 para imágenes/audio — URL CDN opcional |
| 🔑 Auth de dos factores (2FA) | TOTP compatible con Google Authenticator, 8 códigos de recuperación, verificación obligatoria al iniciar sesión |
| 📷 Escaneo QR y compartir | Escanea códigos QR para añadir amigos o unirse a grupos; QR de grupo con caducidad configurable (1 sem./1 mes/3 meses) |
| 🏗️ Auto-alojable | Despliegue Docker Compose en un comando |
Stack tecnológico
Backend (server/)
Node.js 20 + Express + ws
MySQL 8.0 — usuarios, mensajes (texto cifrado)
Redis — presencia en línea + enrutamiento entre nodos
Cloudflare R2 — almacenamiento de archivos (API compatible S3)
Autenticación JWT + bcrypt
Frontend (client/)
HTML nativo + Vanilla JS (ESM, sin bundler)
libsodium-wrappers (WebAssembly — Curve25519 / XSalsa20-Poly1305)
API WebRTC — videollamadas / llamadas de voz
PWA: manifest.json + Service Worker
Capa criptográfica
ECDH sin estado + XSalsa20-Poly1305 — par de claves efímeras por mensaje
Persistencia de claves en 4 niveles: memoria → localStorage → sessionStorage → IndexedDB
Todas las claves privadas solo en el dispositivo — nunca se envían al servidor
Inicio rápido
Opción 0: Zeabur — Despliegue en la nube con un clic
Note
Se requiere un paso manual después del despliegue:
- Consola Zeabur → servicio server → Variables de entorno → copiar el valor de
ZEABUR_WEB_URL- Servicio client → Variables de entorno → agregar
SERVER_URL= valor copiado- Reiniciar el servicio client
Opción 1: Docker Compose (recomendado)
git clone <repo-url> && cd paperphone
cp server/.env.example server/.env
# Editar: DB_PASS / JWT_SECRET / R2_* etc.
docker compose up -d
open http://localhost
Imágenes Docker Hub:
facilisvelox/paperphone-client:latestyfacilisvelox/paperphone-server:latest
Opción 2: Inicio local manual
# Backend
cd server && npm install && npm run dev # → http://localhost:3000
# Frontend
npx serve client -p 8080 # → http://localhost:8080
Configuración de videollamadas — Cloudflare TURN
CF_CALLS_APP_ID=your_app_id_here
CF_CALLS_APP_SECRET=your_app_secret_here
| Tipo | Transporte | Recomendado para |
|---|---|---|
| Video 1:1 | WebRTC P2P + TURN | Todos los escenarios |
| Voz 1:1 | WebRTC P2P + TURN | Todos los escenarios |
| Llamada grupal | WebRTC Mesh | Hasta 6 participantes |
Sin configuración: solo STUN. Las llamadas en LAN funcionan sin configuración adicional.
Notificaciones push
| Canal | Plataformas | Configuración |
|---|---|---|
| Web Push | Navegadores + iOS PWA (Safari 16.4+) | Claves VAPID |
| OneSignal | Apps nativas Median.co | App ID + REST Key |
npx web-push generate-vapid-keys
iOS — Instalación permanente sin certificado
- Desplegar en servidor HTTPS → 2. Abrir en Safari → 3. Compartir ⬆️ → 4. «Añadir a pantalla de inicio»
Modelo de seguridad
Registro: IK + SPK + 10×OPK generados localmente, claves públicas subidas
Mensaje: ECDH efímero → X25519 → XSalsa20-Poly1305
El servidor ve: ✅ texto cifrado + metadatos de enrutamiento ❌ texto plano / claves privadas
Esquema de base de datos
19 tablas, creadas automáticamente en el primer inicio:
| Tabla | Propósito |
|---|---|
users |
Perfiles + claves públicas ECDH/OPK |
prekeys |
Pre-claves X3DH de un solo uso |
friends |
Relaciones de amistad |
groups / group_members |
Grupos + miembros |
messages |
Mensajes cifrados |
moments / moment_images |
Publicaciones + imágenes |
moment_videos |
Videos de publicaciones (miniatura + duración, 1 por publicación, ≤ 10 min) |
moment_likes / moment_comments |
Likes + comentarios |
push_subscriptions |
Web Push (VAPID) |
onesignal_players |
Dispositivos OneSignal |
user_totp |
Secretos TOTP 2FA y códigos de recuperación |
moment_privacy |
Configuración de privacidad de momentos a nivel de usuario (ocultar/no mostrar) |
timeline_posts |
Publicaciones de cronología (texto ≤2000 car., anónimo opcional) |
timeline_media |
Medios de cronología (imágenes/vídeos, máx. 50 por post) |
timeline_likes |
Likes de cronología |
timeline_comments |
Comentarios de cronología (anónimo opcional) |
group_invites |
Enlaces de invitación a grupos (con caducidad, para unirse por QR) |
Variables de entorno
| Variable | Descripción | Predeterminado |
|---|---|---|
PORT |
Puerto del servidor | 3000 |
JWT_SECRET |
Clave de firma JWT (cambiar en producción) | dev_secret |
DB_HOST/DB_PASS/DB_NAME |
Conexión MySQL | — |
REDIS_HOST/REDIS_PASS |
Conexión Redis | — |
R2_ACCOUNT_ID |
ID de cuenta Cloudflare | — |
R2_ACCESS_KEY_ID |
Clave de acceso R2 API | — |
R2_SECRET_ACCESS_KEY |
Clave secreta R2 API | — |
R2_BUCKET |
Nombre del bucket R2 | — |
R2_PUBLIC_URL |
URL pública R2 (opc.) | — |
CF_CALLS_APP_ID |
Calls App ID (opc.) | — |
CF_CALLS_APP_SECRET |
Calls Secret (opc.) | — |
VAPID_PUBLIC_KEY |
Clave pública VAPID (opc.) | — |
VAPID_PRIVATE_KEY |
Clave privada VAPID (opc.) | — |
ONESIGNAL_APP_ID |
OneSignal App ID (opc.) | — |
ONESIGNAL_REST_KEY |
OneSignal REST Key (opc.) | — |
TELEGRAM_BOT_TOKEN |
Telegram Bot Token (opc., proxy de stickers) | — |
STICKER_PACKS |
Lista de packs de stickers (opc., separados por coma nombre:etiqueta, ilimitado) |
8 packs por defecto |
Licencia
MIT © PaperPhone Contributors













