|
1 | | -<div align="center"> |
2 | | - <h1>jamkernelp2p</h1> |
3 | | - <p><strong>J</strong>osé <strong>A</strong>lejandro <strong>M</strong>artínez</p> |
4 | | - <p>Un solo archivo · Cero dependencias · Mesh P2P cifrado · Multi-plataforma · Grado profesional</p> |
5 | | - <p> |
6 | | - <a href="#quick-start">Quick Start</a> · |
7 | | - <a href="#lo-nuevo">Lo Nuevo</a> · |
8 | | - <a href="#api">API</a> · |
9 | | - <a href="#cli">CLI</a> · |
10 | | - <a href="#arquitectura">Arquitectura</a> · |
11 | | - <a href="#problemas-comunes">Problemas Comunes</a> · |
12 | | - <a href="#licencia">Licencia</a> |
13 | | - </p> |
14 | | - <p> |
15 | | - <a href="https://github.com/jamkernel/jamkernelp2p" target="_blank">GitHub</a> · |
16 | | - <a href="https://jamkernel.github.io/" target="_blank">Web</a> · |
17 | | - <a href="mailto:jamkernelp2p@gmail.com">Contacto</a> |
18 | | - </p> |
19 | | - <br> |
20 | | - <pre>node jamkernelp2p.js --port 8080 --room mired --password secreto</pre> |
21 | | - <br> |
22 | | -</div> |
| 1 | +# ⚛️ jamkernelp2p · v1.0 |
23 | 2 |
|
24 | | ---- |
25 | | - |
26 | | -## ¿Qué es jamkernelp2p? |
27 | | - |
28 | | -**jamkernelp2p** es un kernel de comunicación P2P en **un solo archivo JavaScript (~3500 líneas)** que funciona en **navegadores, Node.js, Deno y Bun** sin **ninguna dependencia externa**. |
29 | | - |
30 | | -Creado por **Félix Martínez** y dedicado a su hijo José Alejandro Martínez — de ahí el nombre **JAM**. |
31 | | - |
32 | | -A diferencia de libp2p, PeerJS o simple-peer, jamkernelp2p es **autocontenido**: copias el archivo, lo importas, y tienes una red mesh cifrada con identidad criptográfica, servidor de señalización embebido, logging estructurado, TLS, clustering, y persistencia de estado. |
33 | | - |
34 | | -## Lo Nuevo (v2.1.0) |
35 | | - |
36 | | -| Mejora | Descripción | |
37 | | -|--------|------------| |
38 | | -| **CLI completo** | `--port`, `--token`, `--room`, `--password`, `--cluster`, `--workers`, `--tls-key`, `--tls-cert`, `--log-file`, `--log-level`, `--help` | |
39 | | -| **Autenticación** | Firma ECDSA P-256 en announce, token de sala opcional, servidor verifica peerId | |
40 | | -| **TLS nativo** | `--tls-key cert.pem --tls-cert cert.pem` → WebSocket seguro (WSS) | |
41 | | -| **ACKs de entrega** | Cada mensaje lleva `_msgId`, el receptor responde ACK automático, el emisor trackea pendientes | |
42 | | -| **Rate limiting** | 60 msg/s por conexión, 256KB máx por mensaje, idle timeout 5 min, anti-DoS | |
43 | | -| **StructuredLogger** | Logs en JSON lines con rotación a 10MB, niveles: `error|warn|info|debug` | |
44 | | -| **Cluster mode** | `--cluster --workers 4` distribuye peers entre workers vía IPC | |
45 | | -| **Persistencia mesh** | Estado de sala y conexiones guardado/restaurado en BatchStorage automáticamente | |
46 | | -| **Seguridad mejorada** | Purga forense de claves en RAM al cerrar sesión, blacklist de peers maliciosos | |
47 | | -| **Canales virtuales** | NodeAdapter crea canales virtuales WebSocket con API idéntica a WebRTC DataChannel | |
48 | | - |
49 | | -## Arquitectura |
50 | | - |
51 | | -``` |
52 | | -┌──────────────────────────────────────────────────────────┐ |
53 | | -│ jamkernelp2p │ |
54 | | -├────────────┬──────────────┬──────────────┬───────────────┤ |
55 | | -│ Identity │ Mesh │ Crypto │ Persistence │ |
56 | | -│ (ECDSA │ (SecureJam │ (AES-256 │ (BatchStorage│ |
57 | | -│ P-256) │ Mesh Adap) │ GCM + │ + estado │ |
58 | | -│ │ │ PBKDF2) │ mesh) │ |
59 | | -├────────────┴──────────────┴──────────────┴───────────────┤ |
60 | | -│ Capa de Transporte │ |
61 | | -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ |
62 | | -│ │ Browser │ │ Node.js │ │ Deno │ │ Bun │ │ |
63 | | -│ │ (WebRTC) │ │(WebSocket│ │(WebSocket│ │(WebSocket│ │ |
64 | | -│ │ │ │ +Relay) │ │ +Relay) │ │ +Relay) │ │ |
65 | | -│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ |
66 | | -├──────────────────────────────────────────────────────────┤ |
67 | | -│ MiniSignalServer (embebido) │ |
68 | | -│ WebSocket signaling + mesh relay + auth + rate limit │ |
69 | | -└──────────────────────────────────────────────────────────┘ |
70 | | -``` |
71 | | - |
72 | | -## Quick Start |
73 | | - |
74 | | -```bash |
75 | | -# 1. Clona o descarga el repositorio |
76 | | - |
77 | | -# 2. Peer + servidor de señalización + mesh (todo en uno) |
78 | | -node jamkernelp2p.js --room mi-sala --password clave-segura |
79 | | - |
80 | | -# 3. O usando jam-peer.js (demo con UI web) |
81 | | -node jam-peer.js |
82 | | -# Abre http://localhost:3000 en el navegador |
83 | | -``` |
84 | | - |
85 | | -## CLI (Línea de Comandos) |
86 | | - |
87 | | -El kernel arranca como proceso independiente sin necesidad de código adicional: |
88 | | - |
89 | | -```bash |
90 | | -# Uso básico |
91 | | -node jamkernelp2p.js --room chat-publico --password "v3r4-C0ntr4S3ñ4" |
92 | | - |
93 | | -# Con puerto específico y token de sala |
94 | | -node jamkernelp2p.js --port 9090 --room privado --password clave \ |
95 | | - --token mi-token-secreto |
96 | | - |
97 | | -# TLS (WSS) para producción |
98 | | -node jamkernelp2p.js --tls-key /etc/ssl/privkey.pem \ |
99 | | - --tls-cert /etc/ssl/cert.pem --port 443 |
100 | | - |
101 | | -# Cluster multi-worker |
102 | | -node jamkernelp2p.js --cluster --workers 4 --room sala-cluster \ |
103 | | - --password clave |
104 | | - |
105 | | -# Logging profesional |
106 | | -node jamkernelp2p.js --log-file /var/log/jam.log --log-level info \ |
107 | | - --room monitoreo --password clave |
108 | | - |
109 | | -# Ayuda completa |
110 | | -node jamkernelp2p.js --help |
111 | | -``` |
112 | | - |
113 | | -### Opciones |
114 | | - |
115 | | -| Flag | Default | Descripción | |
116 | | -|------|---------|-------------| |
117 | | -| `--port N` | `0` (aleatorio) | Puerto del servidor de señalización | |
118 | | -| `--token X` | — | Token de autenticación para el servidor | |
119 | | -| `--room X` | — | Sala a la que unirse al iniciar | |
120 | | -| `--password X` | — | Contraseña de cifrado de la sala | |
121 | | -| `--tls-key FILE` | — | Clave TLS para WSS | |
122 | | -| `--tls-cert FILE` | — | Certificado TLS para WSS | |
123 | | -| `--cluster` | — | Activa modo multi-worker | |
124 | | -| `--workers N` | CPU count | Número de workers en cluster | |
125 | | -| `--log-file FILE` | — | Archivo de log (JSON lines) | |
126 | | -| `--log-level L` | `warn` | `error`, `warn`, `info`, `debug` | |
127 | | -| `--help`, `-h` | — | Muestra ayuda y sale | |
128 | | - |
129 | | -## API |
130 | | - |
131 | | -```js |
132 | | -const { JAMOmni } = require('./jamkernelp2p.js'); |
133 | | - |
134 | | -// Creación auto-configurada |
135 | | -const kernel = await JAMOmni.createKernel({}); |
136 | | -const identity = await kernel.whenIdentityReady(); |
137 | | -console.log('Peer ID:', identity.peerId); |
| 3 | +## Núcleo P2P Soberano — Código Abierto |
138 | 4 |
|
139 | | -// Escuchar mensajes |
140 | | -kernel.events.on('peer:message', ({ senderId, message }) => { |
141 | | - console.log(`${senderId}:`, message); |
142 | | -}); |
143 | | - |
144 | | -// Unirse a una sala y transmitir |
145 | | -await kernel.startSession('mi-sala', 'mi-clave'); |
146 | | -await kernel.broadcast({ text: 'Hola mundo P2P!' }); |
147 | | - |
148 | | -// Cerrar sesión (purga forense de claves) |
149 | | -await kernel.closeSession(); |
150 | | -``` |
151 | | - |
152 | | -### Plugins |
153 | | - |
154 | | -```js |
155 | | -class MiPlugin extends JAMPlugin { |
156 | | - async init(config) { |
157 | | - this.events.on('peer:message', (msg) => { |
158 | | - this.log.info('Plugin recibió:', msg); |
159 | | - }); |
160 | | - } |
161 | | -} |
162 | | -kernel.registerPlugin('mi-plugin', MiPlugin); |
163 | | -await kernel.loadPlugin('mi-plugin', { opcion: 'valor' }); |
164 | | -``` |
165 | | - |
166 | | -## Problemas Comunes |
167 | | - |
168 | | -### El peer no conecta con el servidor de señalización |
169 | | - |
170 | | -**Causa:** Puerto incorrecto, firewall bloqueando, o URL mal configurada. |
171 | | - |
172 | | -``` |
173 | | -signal:connection_error → signal:reconnecting → signal:connection_failed |
174 | | -``` |
175 | | - |
176 | | -**Soluciones:** |
177 | | -- Verificar que el puerto esté abierto: `netstat -an | findstr :PUERTO` |
178 | | -- En Windows, agregar regla de firewall: `netsh advfirewall firewall add rule name="jamkernelp2p" dir=in action=allow protocol=TCP localport=PUERTO` |
179 | | -- Si usas WSS, verificar que TLS esté bien configurado: el certificado debe coincidir con el hostname |
180 | | -- Verificar que no haya otro proceso en el mismo puerto: `netstat -ano | findstr :PUERTO` |
181 | | - |
182 | | -### "Firma inválida" / "peer:bad_signature" |
183 | | - |
184 | | -**Causa:** El peer que envía no tiene la clave pública correcta registrada, o hay un ataque de suplantación. |
185 | | - |
186 | | -**Soluciones:** |
187 | | -- Asegurarse de que `mesh.storePeerPublicKey()` se llame después de `peer:connected` |
188 | | -- El announce del peer incluye `peerId + signature` — si no coincide con `SHA-256(publicKey)`, el servidor rechaza |
189 | | -- Si es un error falso positivo, limpiar claves cacheadas: `mesh.clearVerifiedPeers()` |
190 | | -- En redes confiables, aumentar ventana de tolerancia en `handleIncomingPacket()` |
191 | | - |
192 | | -### "peer:attack_detected" o rate limiting |
193 | | - |
194 | | -**Causa:** Un peer envía más de 60 mensajes por segundo, o mensajes de más de 256KB. |
195 | | - |
196 | | -**Soluciones:** |
197 | | -- El peer infractor entra en blacklist automática por 60 segundos (clase `_rateLimit`) |
198 | | -- No hay acción manual necesaria — el kernel se protege solo |
199 | | -- Si es un falso positivo (ej. transferencia de archivos), aumentar el límite: |
200 | | - |
201 | | -```js |
202 | | -kernel.mesh.MAX_MESSAGES_PER_SECOND = 120; // default: 60 |
203 | | -``` |
204 | | - |
205 | | -### Mesh se desconecta al recargar el navegador |
206 | | - |
207 | | -**Causa:** La identidad ECDSA se pierde si no hay IndexedDB o si el almacenamiento fue borrado. |
208 | | - |
209 | | -**Soluciones:** |
210 | | -- La identidad se persiste automáticamente en BatchStorage (IndexedDB en browser, memoria en Node.js) |
211 | | -- Si el usuario borra datos del sitio, genera una nueva identidad — es normal que aparezca como peer nuevo |
212 | | -- Para persistencia forzada, exportar/importar identidad: |
| 5 | +[](https://github.com/jamkernel/jamkernelp2p) |
| 6 | +[](https://www.gnu.org/licenses/gpl-3.0) |
| 7 | +[](https://jamkernel.github.io) |
| 8 | +[](https://t.me/jamkernelp2p) |
| 9 | +[](https://t.me/boost/jamkernelp2p_proyecto) |
213 | 10 |
|
214 | | -```js |
215 | | -const json = identity.toJSON(); |
216 | | -// Guardar json en localStorage antes de recargar |
217 | | -localStorage.setItem('jam-identity', JSON.stringify(json)); |
| 11 | +--- |
218 | 12 |
|
219 | | -// Al cargar de nuevo: |
220 | | -const saved = JSON.parse(localStorage.getItem('jam-identity')); |
221 | | -await identity.importIdentity( |
222 | | - new Uint8Array(saved.publicKey), |
223 | | - new Uint8Array(saved.privateKey) |
224 | | -); |
225 | | -``` |
| 13 | +**jamkernelp2p** es un núcleo de comunicación P2P en **un solo archivo JavaScript (~3500 líneas)** que funciona en **navegadores, Node.js, Deno y Bun** sin **ninguna dependencia externa**. |
226 | 14 |
|
227 | | -### Cluster: workers no se comunican entre sí |
| 15 | +Creado por **Félix Martínez** y dedicado a su hijo José Alejandro Martínez — de ahí el nombre **JAM**. |
228 | 16 |
|
229 | | -**Causa:** El cluster usa IPC de Node.js (proceso primario como relay). Si un worker cae, sus peers quedan huérfanos. |
| 17 | +A diferencia de libp2p, PeerJS o simple-peer, jamkernelp2p es **autocontenido** : copias el archivo, lo importas, y tienes una red mesh cifrada con identidad criptográfica, servidor de señalización embebido, logging estructurado, TLS, clustering, y persistencia de estado. |
230 | 18 |
|
231 | | -**Soluciones:** |
232 | | -- El primario reenvía automáticamente eventos `peer_joined`, `peer_left` y mensajes mesh entre workers |
233 | | -- Si un worker muere, el primario notifica a los demás con `peer_left` para cada peer de ese worker |
234 | | -- Verificar que todos los workers usen el mismo `--token` si el servidor tiene autenticación |
235 | | -- Para clústeres grandes (>1000 peers), considera un message broker externo (NATS, Redis Pub/Sub) |
| 19 | +> 🚀 **El Motor Híbrido (Node.js + Rust)** — una evolución natural del núcleo — está en fase de investigación y desarrollo. Su lanzamiento está previsto como la versión **`2.0`** del ecosistema JAM. Consulta la [hoja de ruta](#hoja-de-ruta) para más información. |
236 | 20 |
|
237 | | -### Los logs no se escriben al archivo |
| 21 | +--- |
238 | 22 |
|
239 | | -**Causa:** Permisos de escritura, ruta incorrecta, o directorio no existe. |
| 23 | +## 🌌 El Ecosistema JAM |
240 | 24 |
|
241 | | -**Soluciones:** |
242 | | -- Verificar que el directorio padre exista: `mkdir -p /var/log/jam` |
243 | | -- El archivo se crea automáticamente si no existe, pero el directorio debe existir |
244 | | -- Si se usa `--log-file ./logs/jam.log`, crear `logs/` antes de arrancar |
245 | | -- El archivo rota automáticamente al llegar a 10MB (se renombra a `.1.log`) |
246 | | -- En Windows, usar rutas absolutas o relativas con barras invertidas escapadas |
| 25 | +### 🏛️ jamkernelp2p — v1.0 (Actual) |
247 | 26 |
|
248 | | -### TLS: "ERR_CERT_AUTHORITY_INVALID" en navegador |
| 27 | +La base. Un solo archivo JavaScript para crear redes mesh cifradas sin dependencias. |
249 | 28 |
|
250 | | -**Causa:** Certificado autofirmado no es aceptado por el navegador. |
| 29 | +- ✅ **1 archivo** · **0 dependencias** |
| 30 | +- ✅ **4 plataformas** (Web/Node/Deno/Bun) |
| 31 | +- ✅ **AES‑256‑GCM** con autenticación |
| 32 | +- ✅ **Anti‑DoS** por rate limiting (12 msg/seg) |
| 33 | +- ✅ **Purga forense** de claves en RAM |
| 34 | +- ✅ **Identidad ECDSA** P‑256 nativa |
251 | 35 |
|
252 | | -**Soluciones:** |
253 | | -- Para desarrollo, aceptar la excepción de seguridad manualmente |
254 | | -- Para producción, usar Let's Encrypt (certbot) o un CA confiable |
255 | | -- También funciona sin TLS en `ws://localhost` para desarrollo local |
| 36 | +[➡️ Ver documentación completa](https://jamkernel.github.io) |
256 | 37 |
|
257 | | -### El peer Node.js no sirve HTTP |
| 38 | +### 🚀 Motor Híbrido — v2.0 (En desarrollo) |
258 | 39 |
|
259 | | -**Causa:** `jam-peer.js` usa el mismo servidor HTTP del signal para servir archivos. Si arrancas solo el kernel vía CLI (`node jamkernelp2p.js`), no hay servidor HTTP. |
| 40 | +La evolución del núcleo P2P: combina la flexibilidad de Node.js con el rendimiento de Rust para ejecutar agentes de IA, tareas programadas y lógica de negocio en el borde. |
260 | 41 |
|
261 | | -**Soluciones:** |
262 | | -- Usa `jam-peer.js` si necesitas interfaz web |
263 | | -- El kernel CLI (`jamkernelp2p.js`) es solo señalización + mesh — más ligero pero sin UI |
264 | | -- Para ambos, crea tu propio script con `createKernel()` + servidor HTTP como en `jam-peer.js` |
| 42 | +- ✅ **Agentes IA** en Rust |
| 43 | +- ✅ **Scheduler** con cron |
| 44 | +- ✅ **Tools nativas** (funciones en Rust) |
| 45 | +- ✅ **Bridge Node.js ↔ Rust** en tiempo real |
265 | 46 |
|
266 | | -### Error: "No se pudo derivar la clave" / password muy corto |
| 47 | +🔜 **Próximamente** — consulta la [hoja de ruta](#hoja-de-ruta). |
267 | 48 |
|
268 | | -**Causa:** `startSession()` requiere password de al menos 8 caracteres. |
| 49 | +--- |
269 | 50 |
|
270 | | -**Soluciones:** |
271 | | -- Usar contraseñas de 12+ caracteres |
272 | | -- PBKDF2 con 60,000 iteraciones — passwords cortos son vulnerables a fuerza bruta |
273 | | -- Si es solo para pruebas: `await kernel.startSession('test', '12345678')` |
| 51 | +## 🔐 Características del Núcleo (v1.0) |
274 | 52 |
|
275 | | -### El mesh no descubre peers |
| 53 | +### Cifrado Militar |
276 | 54 |
|
277 | | -**Causa:** Los peers están en redes diferentes sin relay, o el gossip no se propagó. |
| 55 | +- **AES‑256‑GCM** con autenticación |
| 56 | +- Derivación **PBKDF2** (60.000 iteraciones) |
| 57 | +- **Sal dinámica** por sala |
| 58 | +- **Identidad ECDSA** P‑256 nativa |
278 | 59 |
|
279 | | -**Soluciones:** |
280 | | -- Verificar que todos los peers apunten al mismo servidor de señalización |
281 | | -- El servidor envía `peer_list` al conectarse y `peer_joined` cuando alguien nuevo llega |
282 | | -- Si hay NAT, asegurar que WebRTC tenga STUN configurado (por defecto tiene Google STUN) |
283 | | -- Para redes locales, usar IP directa: `signalServer: 'ws://192.168.1.100:PUERTO'` |
| 60 | +### Seguridad Integrada |
284 | 61 |
|
285 | | -## Comparativa |
| 62 | +- **Anti‑DoS** por rate limiting (12 msg/seg) |
| 63 | +- **Lista negra** automática |
| 64 | +- **Sanitización** de entradas |
| 65 | +- **Blacklist** de peers maliciosos |
286 | 66 |
|
287 | | -| Característica | jamkernelp2p | libp2p | PeerJS | simple-peer | |
288 | | -|---------------|:---:|:------:|:------:|:-----------:| |
289 | | -| Archivos | 1 | 100+ | 5+ | 3+ | |
290 | | -| Dependencias | **0** | 50+ | 10+ | 5+ | |
291 | | -| Browser + Node.js | ✅ | ✅ | ✅ | ✅ | |
292 | | -| Señalización embebida | ✅ | ❌ | ❌ | ❌ | |
293 | | -| Identidad ECDSA | ✅ | Opcional | ❌ | ❌ | |
294 | | -| TLS nativo | ✅ | ❌ | ❌ | ❌ | |
295 | | -| Cluster mode | ✅ | ✅ | ❌ | ❌ | |
296 | | -| Logging estructurado | ✅ | ❌ | ❌ | ❌ | |
297 | | -| ACKs de entrega | ✅ | ❌ | ❌ | ❌ | |
298 | | -| Rate limiting anti-DoS | ✅ | ❌ | ❌ | ❌ | |
299 | | -| Auto-descubrimiento | ✅ | ✅ | ❌ | ❌ | |
300 | | -| Persistencia de estado | ✅ | ❌ | ❌ | ❌ | |
301 | | -| Plugins sandbox | ✅ | ✅ | ❌ | ❌ | |
302 | | -| Deno + Bun | ✅ | ❌ | ❌ | ❌ | |
303 | | -| Zero-config | ✅ | ❌ | ❌ | ❌ | |
| 67 | +### Purga de Memoria |
304 | 68 |
|
305 | | -## Licencia |
| 69 | +- **Eliminación forense** de claves en RAM |
| 70 | +- **Garbage Collection** forzado |
| 71 | +- **Nullificación** de referencias |
306 | 72 |
|
307 | | -**Dual License:** GNU GPL v3 + Commercial License. |
| 73 | +### Almacenamiento Local |
308 | 74 |
|
309 | | -[](https://www.gnu.org/licenses/gpl-3.0) |
310 | | -[](LICENCIA_COMERCIAL.md) |
| 75 | +- **IndexedDB** con mutex antibloqueo |
| 76 | +- **Backoff exponencial** en fallos |
| 77 | +- **Límite de cola** (1000 items) |
311 | 78 |
|
312 | | -**Open Source (GPLv3):** Eres libre de usar, modificar y distribuir este software bajo los términos de GNU GPL v3. Ideal para proyectos de código abierto, uso personal, educativo, investigación y organizaciones sin fines de lucro. Ver [LICENSE](LICENSE). |
| 79 | +--- |
313 | 80 |
|
314 | | -**Comercial:** Si deseas usar jamkernelp2p en un producto propietario sin las restricciones de copyleft, puedes adquirir una licencia comercial directamente del autor. Ver [LICENCIA_COMERCIAL.md](LICENCIA_COMERCIAL.md) o contacta a **jamkernelp2p@gmail.com**. |
| 81 | +## 🚀 Uso Rápido (v1.0) |
315 | 82 |
|
316 | | ---- |
| 83 | +### Instalación |
317 | 84 |
|
318 | | -<div align="center"> |
319 | | - <sub>Creado por <strong>Félix Martínez</strong> · 2026</sub> |
320 | | - <br> |
321 | | - <sub>Dedicado a José Alejandro Martínez — mi motor, mi orgullo ❤️</sub> |
322 | | -</div> |
| 85 | +```bash |
| 86 | +# Clona o descarga el repositorio |
| 87 | +git clone https://github.com/jamkernel/jamkernelp2p.git |
| 88 | +cd jamkernelp2p |
0 commit comments