OASIS_LINUX/docs/devs/architecture/01-red-ssb.md
SITO ddd2787b73 Oasis 0.9.5 con Karvan para escritorio
Rama de desarrollo experimental sobre el Oasis de epsylon, sin afiliacion con el
proyecto original. Base: 0.9.5.

Trae el modulo Karvan —salas efimeras en memoria con autodestruccion por TTL, chat
que funciona sin JavaScript y llamadas de audio y video sobre WebRTC— con el enlace
en el menu lateral por el mismo patron que el resto de modulos: renderKarvanLink
calcado de renderPollsLink, entrada en modules_view y en la lista de /modules.

Los estilos del modulo van en su propia hoja, styles/karvan.css, siguiendo el patron
de highlight.css: asi se ve igual con cualquier tema, sin depender del tema movil.

Sin servidores ICE de terceros: no hay STUN de fabrica, porque un STUN aprende la IP
publica y el momento de cada llamada. Solo candidatos host salvo que se configure un
TURN propio en oasis-config.json, con credenciales efimeras por el mecanismo REST de
coturn.

El codigo propio vive separado —views/fork/, backend/fork_routes.js,
models/karvan_model.js y translations/fork/— de modo que sobre los ficheros de
upstream solo hay enganches de una linea y cada version nueva se integra sin
arrastrar nada.

Respecto al arbol de Android: fuera el wrapper y main.js, que es su arranque; el
tema vuelve a Dark-SNH y se restauran los modulos que en movil se recortan por peso.

Verificado arrancando sin OASIS_MOBILE: nueve rutas OK, menu lateral de upstream con
27 grupos y el enlace de Karvan, cero rastro de la interfaz movil (ni hexagonos, ni
topbar, ni barra inferior), y una sala creada y servida.
2026-08-19 00:35:08 +02:00

243 lines
12 KiB
Markdown

# 1. Oasis a nivel de red (Secure Scuttlebutt)
Oasis es un cliente/servidor de **Secure Scuttlebutt (SSB)**. Toda la "red" de
Oasis se construye sobre la pila clásica del ecosistema SSB:
`secret-stack` + `ssb-db` + un montón de plugins.
Hay una separación clara en **dos procesos**:
- **Backend SSB (sbot)** — `src/server/SSB_server.js`: el nodo de red propiamente
dicho. Es quien habla con otros peers.
- **Frontend web (GUI Koa)** — `src/backend/backend.js`: un servidor HTTP que
actúa como **cliente muxrpc** del sbot, conectándose por un socket Unix local.
```
RED SSB (otros peers Oasis, misma SHS cap)
net:IP:8008~shs:<pubkey> · ssb-lan (UDP) · ssb-onion (Tor)
┌─────────────────────────────────────────────┐
│ SBOT (src/server/SSB_server.js) │
│ peer <-> MULTISERVER <-> SECRET-STACK (SHS) │
│ <-> MUXRPC <-> PLUGINS │
└─────────────────────────┬───────────────────┘
│ unix socket ~noauth (muxrpc local, sin SHS)
┌─────────────────────────────────────────────┐
│ FRONTEND (src/backend/backend.js, Koa) │
│ cooler = src/client/gui.js → ssb-client │
│ app.listen({host, port:3000}) │
└─────────────────────────┬───────────────────┘
Navegador http://localhost:3000
```
---
## 1.1 Arranque de red
### Scripts de arranque
- **`install.sh`**: instala Node 22 y hace `npm install` en `src/server`
(línea 23). Opcionalmente descarga modelos de IA. No toca la red.
- **`oasis.sh`** es el lanzador. Modos relevantes:
- `server` / `pub` (líneas 61-69): ejecuta `node SSB_server.js start` — **solo
el sbot headless**, sin interfaz web.
- `gui` o por defecto (líneas 73-81): ejecuta `node backend.js` — el frontend.
- comandos pub `whoami|invite|name|announce|follow|status|gossip`
(líneas 70-72) → delegan en `scripts/oasis-pub.js`.
- **`src/server/package.json`**, script `start`:
`npm run start:ssb && sleep 10 && npm run start:backend`.
Arranca el sbot en segundo plano, **espera 10 s** (para que el socket Unix
exista) y luego arranca el frontend.
### Qué hace `SSB_server.js` paso a paso
(`src/server/SSB_server.js`)
1. **Líneas 7-11**: carga `secret-stack`, `ssb-caps` (la capability SHS),
`ssb-db`, la config (`./ssb_config`) y utilidades de metadatos.
2. **Líneas 13-52** (IIFE): *monkey-patch* de `console.error`/`console.warn`
para silenciar ruido de red — rechazos de handshake por SHS cap incorrecta,
excepciones EBT, etc. Un rechazo se convierte en un log limpio:
`[ts] REJECTED <ip:port> (wrong SHS cap)`.
3. **Líneas 56-81**: construye el servidor con
`SecretStack({ caps }).use(plugin).use(plugin)...` encadenando todos los
plugins (ver tabla abajo).
4. **Líneas 83-86**: si **no** es pub, carga `ssb-lan` (descubrimiento LAN por
UDP) y el router LAN local `./lanRouter`.
5. **Líneas 88-98**: lógica de `autofollow`; carga `ssb-autofollow` si hay feeds.
6. **Líneas 123-196** (`argv[0] === 'start'`): instancia el servidor, escribe
`manifest.json` (el catálogo de métodos muxrpc remotos), monta una barra de
progreso de replicación, imprime metadatos y **escucha eventos del hub de
conexiones** (`server.conn.hub().listen()`) para loguear `CONNECTED` /
`DISCONNECTED`.
7. **Líneas 198-202**: exporta `{ config, server, open() }` — esto permite a la
GUI reusar el servidor **in-process** si corre en el mismo proceso.
### Plugins secret-stack cargados (líneas 56-98)
| Plugin | Función de red |
|---|---|
| `ssb-db` | base de datos *append-only* de feeds |
| `ssb-master` | identidad maestra / auth local |
| `ssb-gossip` | gossip clásico (legacy) de peers |
| `ssb-ebt` | **Epidemic Broadcast Trees** — replicación gossip eficiente |
| `ssb-friends` | grafo social: hops, follows/blocks |
| `ssb-blobs` | transferencia de ficheros binarios |
| `ssb-meme` | blobs de imágenes/memes |
| `ssb-conn` | gestor de conexiones moderno (hub, db, staging) |
| `ssb-box` | cifrado de mensajes privados (box1) |
| `ssb-search`, `ssb-private`, `ssb-friend-pub` | búsqueda, PM, pub de amigos |
| `ssb-invite` / `ssb-invite-client` | invites (servidor si es pub, cliente si no) |
| `ssb-replication-scheduler`, `ssb-partial-replication` | planificación de replicación |
| `ssb-onion` | transporte Tor |
| `ssb-unix-socket` | **socket Unix local** para clientes (la GUI) |
| `ssb-no-auth` | conexiones locales sin handshake SHS |
| `ssb-about`, `ssb-backlinks`, `ssb-links`, `ssb-tangle`, `ssb-query` | índices de vistas |
| `ssb-lan` + `lanRouter` | descubrimiento LAN (solo si no es pub) |
> Nota: la replicación NO usa `ssb-replicate` directamente; la orquestan
> `ssb-ebt` + `ssb-replication-scheduler` + `ssb-friends`.
---
## 1.2 El protocolo SSB en términos del proyecto
- **secret-stack + handshake SHS (capability).** `SecretStack({ caps })` crea el
nodo. La `caps.shs` está **fijada en `src/configs/server-config.json`**
(líneas 5-7): `"H5EC+V5BU9s0lWxCkt4z8a095Sj8a6TgiLKPYi1JD7s="`. Es la **clave
de capacidad de red** (Secret Handshake): dos peers solo completan el
handshake si comparten *exactamente* esta cap. Actúa como "contraseña de red":
**Oasis forma su propia red SSB privada**, distinta de la red SSB pública.
- **multiserver (transportes).** Capa de transporte abstracta. La config
`connections` (`server-config.json`, líneas 29-60) define:
- **incoming.net**: `transform: "shs"`, `port: 8008` → TCP cifrado con SHS.
- **incoming.unix**: `transform: "noauth"` → socket Unix local sin handshake,
para que el frontend se conecte como cliente privilegiado.
- **outgoing.net**: `transform: "shs"`.
- Una dirección multiserver típica: `net:IP:8008~shs:<pubkey-base64>`.
- **muxrpc (RPC sobre el stream).** Una vez establecido el stream SHS, `muxrpc`
multiplexa llamadas RPC asíncronas y *pull-streams* sobre la misma conexión.
El `manifest.json` describe qué métodos remotos existen (`sync`/`async`/
`source`). Es como el frontend invoca `ssb.publish(...)`, `ssb.blobs.get(...)`,
etc.
- **EBT (`epidemic-broadcast-trees` + `ssb-ebt`).** El algoritmo de replicación
gossip. Cada peer anuncia el `seq` (reloj vectorial) de los feeds que tiene;
el otro envía solo los mensajes que faltan, formando árboles de difusión
epidémica que evitan duplicados.
- **Identidad de los peers.** Cada peer es un **feed id ed25519**:
`@<base64>.ed25519`. En las direcciones multiserver, el sufijo
`~shs:<pubkey>` identifica criptográficamente al peer durante el handshake.
---
## 1.3 Federación / P2P
- **Descubrimiento LAN** (`src/server/lanRouter.js`): plugin local custom.
`startRouter` (líneas 55-64) arranca `ssb.lan.start()` (broadcast UDP) y
consume `ssb.lan.discoveredPeers()`. Cada peer descubierto pasa por
`handleDiscovery``stagePeer` (líneas 15-45): lo *stagea* en
`ssb.conn.stage(...)` (vía moderna) con fallback a `ssb.gossip.add(...)`
(legacy); si `eagerReplicate`, fuerza `ebt.request`. Respeta el flag
`lanBroadcasting` de `oasis-config.json`.
- **Pubs / invites.** En modo pub se carga `ssb-invite` (servidor); en cliente,
`ssb-invite-client`. Los comandos `oasis.sh invite|announce|follow`
(→ `scripts/oasis-pub.js`) permiten a un pub publicar su dirección y generar
códigos de invitación. Un invite contiene `host:port:pubkey~seed`; al
canjearlo, el peer se conecta y el pub le sigue de vuelta (`ssb-friend-pub`).
- **Replicación por hops.** `ssb-friends` define el grafo social.
`server-config.json` fija `friends.hops: 2` → el nodo replica los feeds de la
gente que sigues y de la gente que ellos siguen (amigos de amigos). El
`ssb-replication-scheduler` decide qué feeds pedir por EBT según ese grafo.
- **"Distributed not decentralized".** No hay servidor central ni DHT global.
Cada nodo Oasis tiene su **propia copia local** de la base de datos
(logs *append-only* firmados con ed25519) y solo replica los feeds dentro de
su radio social (hops) más los descubiertos por LAN. La red se federa por
gossip entre peers que comparten la misma SHS cap. Es **distribuida** (datos
replicados en muchos nodos autónomos, funciona offline) pero **no
descentralizada** como una blockchain (no hay consenso global ni vista única;
cada quien ve solo su subgrafo). El flag `wish` de `oasis-config.json`
(`whole` / `mutuals` / `only-lan`) controla el alcance de replicación deseado.
---
## 1.4 Puertos y endpoints
| Qué | Dónde | Puerto / dirección |
|---|---|---|
| muxrpc SSB (sbot) — otros peers se conectan aquí | `server-config.json` incoming.net | **8008/TCP** transform `shs` |
| Socket Unix local — para el frontend | incoming.unix | `unix:<ssb.path>/socket~noauth:<pubkey>` |
| Frontend web (Koa) — tu navegador | `oasis_client.js` / `middleware.js:180` | **3000** host `localhost` (configurable con `--host`/`--port`) |
**Cómo se conecta el frontend al sbot** (el "cooler", `src/client/gui.js`):
1. Intenta `require('../server/SSB_server')` y reusar el `server` **in-process**
si existe (sin socket, uso directo del objeto).
2. Si no, construye `remote = unix:<path>/socket~noauth:<pubkey>` y se conecta
con **`ssb-client`** (muxrpc por el socket Unix `noauth`).
3. `attemptConnectionWithBackoff`: reintentos con backoff exponencial (de ahí el
`sleep 10` del arranque).
4. Expone `cooler.open()` / `cooler.close()`. **Todos los modelos** del backend
reciben este `cooler` y hacen `await cooler.open()` para obtener el cliente
muxrpc.
> Para exponer la GUI en un VPS se usa `--host=0.0.0.0`.
---
## 1.5 Blobs (ficheros / imágenes)
- Plugin `ssb-blobs` (+ `ssb-meme`). Tamaño máximo en `ssb_config.js`: 50 MB.
- Un blob se referencia por hash: `&<sha256-base64>.sha256`. **Los mensajes del
log solo llevan el hash**, no el binario.
- Flujo en `src/backend/blobHandler.js`:
- **Subida**: `ssbClient.blobs.add(...)` recibe el contenido por pull-stream y
devuelve el ref `&...sha256`.
- **Descarga por red**: `blobs.has(id)` comprueba si ya está local; si no,
`blobs.want(id)` **lo pide a los peers conectados** (gossip de "want/has"
sobre muxrpc), y `blobs.get(id)` lo lee como stream.
Los blobs viajan sobre la misma conexión SHS/muxrpc, fuera del log append-only.
---
## 1.6 Caps / cifrado
- **`ssb-caps`** define las capabilities de protocolo (shs, sign, invite). La
**shs cap real** está fijada en `server-config.json` → red privada de Oasis.
- **Handshake SHS**: autenticación mutua por ed25519 + confidencialidad del
stream de transporte.
- **`ssb-box`**: cifrado de **mensajes privados box1** (hasta ~7 destinatarios,
cifrado por clave pública de cada feed). `ssb-private` expone publish/read.
- **Grupos privados ("tribes").** No se usa `box2`/`ssb-tribes`. En su lugar
Oasis implementa cifrado **propio a nivel de aplicación** en
`src/models/crypto.js`, instanciado por dominio en `backend.js`
(`tribeCrypto`, `chatCrypto`, `padCrypto`, `mapCrypto`, `calendarCrypto`,
`eventCrypto`, `forumCrypto`). Los grupos se cifran con esas claves derivadas
y se almacenan/replican como mensajes normales del feed.
---
## 1.7 Archivos clave de la capa de red
| Archivo | Rol |
|---|---|
| `src/server/SSB_server.js` | Construye el sbot y carga los plugins (56-98) |
| `src/server/ssb_config.js` | Fusiona `server-config.json`; fija `blobs.max=50MB` |
| `src/server/ssb_metadata.js` | Deriva e imprime puerto SSB, hops, LAN, feed ID |
| `src/server/lanRouter.js` | Descubrimiento/staging de peers LAN |
| `src/configs/server-config.json` | `caps.shs`, `pub`, `friends.hops`, `connections` (puertos) |
| `src/configs/oasis-config.json` | `lanBroadcasting`, `wish`, `pmVisibility`, módulos |
| `src/client/gui.js` | El "cooler": cliente muxrpc por socket Unix noauth |
| `src/backend/blobHandler.js` | add/has/want/get de blobs |
| `scripts/oasis-pub.js` | Comandos pub (invite/announce/follow) |
Siguiente: **[02-arquitectura-software.md](02-arquitectura-software.md)**.