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.
This commit is contained in:
commit
ddd2787b73
286 changed files with 157145 additions and 0 deletions
243
docs/devs/architecture/01-red-ssb.md
Normal file
243
docs/devs/architecture/01-red-ssb.md
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
# 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)**.
|
||||
Loading…
Add table
Add a link
Reference in a new issue