Parte II — Tronco e raízes
05 · A roda: identidade e permissões
Ubuntu: "eu sou porque nós somos". No Baobáxia, quem você é vale na rede inteira; o que você pode fazer vale dentro da roda que te reconhece.
Arquivos para ler
services/auth.py— senhas (PBKDF2), tokens JWT, verificação de token de outra mucua, freio de tentativas.api/v3/auth.pyeapi/v3/deps.py— login e como o token vira omocque toda rota recebe.infra/identity.py— chaves Ed25519 (assinatura) e X25519 (cifragem).services/permissions.py—can(): toda decisão de acesso passa aqui.services/acesso_galaxia.py,services/grupos.py,services/acl.py.infra/envelope.py— cifragem de ponta a ponta.services/challenge.py,services/recovery.py,infra/seed_phrase.py.
Duas identidades, uma pessoa
- Senha (
password_hashPBKDF2-SHA256, 200 mil rodadas) no saber da mocambola. - Chaves: par Ed25519 (assina autoria e tokens) + par X25519 (abre saberes cifrados). A privada fica em
~/.baobaxia/keys/<uuid>.json, cifrada com a senha (scrypt + AES-GCM), modo 600 — nunca viaja. A pública vai nosaber.bbx. BBX_AUTH_MODE=senha|chave|ambos(padrão).
Login e token
sequenceDiagram
autonumber
actor P as Pessoa
participant A as POST /auth/login
participant F as freio (services/auth.py)
participant S as SaberService
participant K as identity
P->>A: username (ou nome@uuid8 da mucua) + senha
A->>F: tentativas_bloqueadas?
alt muitas falhas na janela
A-->>P: 429
end
A->>S: find_mocambola (prefere a da mucua local)
A->>A: verify_password (PBKDF2, compare_digest)
A->>K: cache_session_key — destrava as privadas na memória (8 h)
A->>A: _issue_for: papel efetivo + galáxias administradas
A->>K: assina JWT EdDSA com a chave da MUCUA (ou HS256)
A-->>P: access_token (7 dias) + perfil sem password_hash
Com login por chave: POST /auth/desafio devolve um nonce de uso único; POST /auth/login-chave manda a assinatura (e, se for uma chave secundária, o certificado de delegação assinado pela principal).
Token assinado por outra mucua
flowchart TD
T[token EdDSA, iss = bbx:mucua:X] --> L{X é a mucua local?}
L -- sim --> K[verifica com a chave que está NO DISCO<br/>nunca com a pubkey de um saber]
L -- não --> P[verifica com a pubkey do saber mucua X]
P --> Q{a mocambola sub é conhecida aqui?}
Q -- "sim, e é de outra mucua" --> N[recusa: X só responde<br/>pelas próprias mocambolas]
Q -- "sim, e é de X" --> R[papel, galáxias e mucua<br/>recalculados com os NOSSOS dados]
Q -- não --> U[entra como USER, sem escopo]
A assinatura prova quem é; nunca o que pode aqui. (Este desenho é da versão 3.3 — ver o módulo 11.)
can(): a decisão
flowchart TD
A[can mocambola, ação, recurso] --> S{ator de sistema?}
S -- sim --> OK[permite]
S -- não --> R{ação = READ?}
R -- sim --> RA{rascunho?}
RA -- sim --> RB[só autor, PAJÉ da mucua,<br/>OXALÁ da galáxia]
RA -- não --> G{galáxia restrita<br/>e fora da lista?}
G -- sim --> NO[nega]
G -- não --> PR{protecao acl/cifrado?}
PR -- sim --> PL[leitores, autor;<br/>acl: + PAJÉ da mucua]
PR -- não --> V[visibility: public → todos<br/>mucua → mesma mucua ou OXALÁ<br/>private → dono ou PAJÉ]
R -- não --> W{anônimo?}
W -- sim --> NO
W -- não --> RO{galáxia somente-leitura?}
RO -- sim --> NO
RO -- não --> E[editores do saber UPDATE → gestor local →<br/>dono → PAJÉ da mucua → OXALÁ da galáxia]
O descritor do recurso é montado num lugar só (SaberService._descritor / _resource_of). Quando cada rota montava o seu, uns esqueciam protecao e vazavam — leia o docstring de testes/test_vazamentos_de_leitura.py.
Cifragem de ponta a ponta
Com protecao: cifrado, cada saber ganha uma chave de conteúdo (ChaCha20-Poly1305). description, body, location e os anexos (.bbxenc) são cifrados; title e tags ficam em claro para busca. A chave do saber é embrulhada para cada leitor (X25519 ECDH + HKDF + AES-GCM). Papel não abre cabaça: só quem tem um embrulho com o próprio nome.
Recuperação
Três caminhos independentes (services/recovery.py): um guardião autoriza a rotação da identidade (nunca vê senha nem conteúdo), uma frase-semente montada com respostas pessoais + entropia, ou a chave guardada na mucua-natal.
Práticas
- Em
test_token_federado_recalcula_papel.py, leiamucua_de_fora_nao_responde_por_mocambola_daqui. Explique o ataque com suas palavras. - Crie um saber com
protecao: acleleitores: [alguém]. Tente ler como anônimo pela listagem, pelo detalhe, pela coleção, pelo download do anexo. (test_vazamentos_de_leitura.pyfaz isso.) - Em
permissions.py, qual é a diferença entreaclecifradopara um PAJÉ? Por que essa diferença é honesta?
Para conversar
- O comentário de
GalaxiaData.acesso(natures/schemas.py) chama a galáxia fechada de "cortesia de software". O que isso quer dizer, e quando ela basta? - Quem deve ser guardião da identidade de alguém na sua comunidade?
