Parte II — Tronco y raíces
05 · La rueda: identidad y permisos
Ubuntu: "soy porque somos". En Baobáxia, quién eres vale en toda la red; lo que puedes hacer vale dentro de la rueda que te reconoce.
Archivos para leer
services/auth.py— contraseñas (PBKDF2), tokens JWT, verificación de un token de otra mucua, freno de intentos.api/v3/auth.pyyapi/v3/deps.py— el login y cómo el token se convierte en elmocque recibe toda ruta.infra/identity.py— claves Ed25519 (firma) y X25519 (cifrado).services/permissions.py—can(): toda decisión de acceso pasa por aquí.services/acesso_galaxia.py,services/grupos.py,services/acl.py.infra/envelope.py— cifrado de extremo a extremo.services/challenge.py,services/recovery.py,infra/seed_phrase.py.
Dos identidades, una persona
- Contraseña (
password_hashPBKDF2-SHA256, 200 mil rondas) en el saber de la mocambola. - Claves: un par Ed25519 (firma autoría y tokens) + un par X25519 (abre saberes cifrados). La privada queda en
~/.baobaxia/keys/<uuid>.json, cifrada con la contraseña (scrypt + AES-GCM), modo 600 — nunca viaja. La pública va en elsaber.bbx. BBX_AUTH_MODE=senha(contraseña) |chave(clave) |ambos(ambos, por defecto).
Login y token
sequenceDiagram
autonumber
actor P as Persona
participant A as POST /auth/login
participant F as freno (services/auth.py)
participant S as SaberService
participant K as identity
P->>A: username (o nombre@uuid8 de la mucua) + contraseña
A->>F: tentativas_bloqueadas?
alt demasiados fallos en la ventana
A-->>P: 429
end
A->>S: find_mocambola (prefiere la de la mucua local)
A->>A: verify_password (PBKDF2, compare_digest)
A->>K: cache_session_key — desbloquea las privadas en memoria (8 h)
A->>A: _issue_for: rol efectivo + galaxias administradas
A->>K: firma un JWT EdDSA con la clave de la MUCUA (o HS256)
A-->>P: access_token (7 días) + perfil sin password_hash
Con login por clave: POST /auth/desafio devuelve un nonce de un solo uso; POST /auth/login-chave envía la firma (y, si es una clave secundaria, el certificado de delegación firmado por la principal).
Token firmado por otra mucua
flowchart TD
T[token EdDSA, iss = bbx:mucua:X] --> L{¿X es la mucua local?}
L -- sí --> K[verifica con la clave que está EN EL DISCO<br/>nunca con la pubkey de un saber]
L -- no --> P[verifica con la pubkey del saber mucua X]
P --> Q{¿la mocambola sub es conocida aquí?}
Q -- "sí, y es de otra mucua" --> N[rechaza: X solo responde<br/>por sus propias mocambolas]
Q -- "sí, y es de X" --> R[rol, galaxias y mucua<br/>recalculados con NUESTROS datos]
Q -- no --> U[entra como USER, sin alcance]
La firma prueba quién es; nunca qué puede hacer aquí. (Este diseño es de la versión 3.3 — ver el módulo 11.)
can(): la decisión
flowchart TD
A[can mocambola, acción, recurso] --> S{¿actor de sistema?}
S -- sí --> OK[permite]
S -- no --> R{¿acción = READ?}
R -- sí --> RA{¿borrador?}
RA -- sí --> RB[solo autor, PAJÉ de la mucua,<br/>OXALÁ de la galaxia]
RA -- no --> G{¿galaxia restringida<br/>y fuera de la lista?}
G -- sí --> NO[niega]
G -- no --> PR{¿protecao acl/cifrado?}
PR -- sí --> PL[lectores, autor;<br/>acl: + PAJÉ de la mucua]
PR -- no --> V[visibility: public → todos<br/>mucua → misma mucua u OXALÁ<br/>private → dueño o PAJÉ]
R -- no --> W{¿anónimo?}
W -- sí --> NO
W -- no --> RO{¿galaxia de solo lectura?}
RO -- sí --> NO
RO -- no --> E[editores del saber UPDATE → gestor local →<br/>dueño → PAJÉ de la mucua → OXALÁ de la galaxia]
El descriptor del recurso se arma en un solo lugar (SaberService._descritor / _resource_of). Cuando cada ruta armaba el suyo, algunas olvidaban protecao y filtraban datos — lee el docstring de testes/test_vazamentos_de_leitura.py.
Cifrado de extremo a extremo
Con protecao: cifrado, cada saber recibe una clave de contenido (ChaCha20-Poly1305). description, body, location y los anexos (.bbxenc) se cifran; title y tags quedan en claro para la búsqueda. La clave del saber se envuelve para cada lector (X25519 ECDH + HKDF + AES-GCM). El rol no abre la calabaza: solo quien tiene un envoltorio con su propio nombre.
Recuperación
Tres caminos independientes (services/recovery.py): un guardián autoriza la rotación de la identidad (nunca ve contraseñas ni contenido), una frase semilla armada con respuestas personales + entropía, o la clave guardada en la mucua natal.
Prácticas
- En
test_token_federado_recalcula_papel.py, leemucua_de_fora_nao_responde_por_mocambola_daqui. Explica el ataque con tus palabras. - Crea un saber con
protecao: aclyleitores: [alguien]. Intenta leerlo como anónimo por el listado, por el detalle, por la colección, por la descarga del anexo. (test_vazamentos_de_leitura.pyhace eso.) - En
permissions.py, ¿cuál es la diferencia entreaclycifradopara un PAJÉ? ¿Por qué esa diferencia es honesta?
Para conversar
- El comentario de
GalaxiaData.acesso(natures/schemas.py) llama a la galaxia cerrada "cortesía de software". ¿Qué quiere decir, y cuándo basta? - ¿Quién debería ser guardián de la identidad de alguien en tu comunidad?
