# 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)**.
