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.

A roda dos papéis: USER, PAJÉ, OXALÁ

Arquivos para ler

  1. services/auth.py — senhas (PBKDF2), tokens JWT, verificação de token de outra mucua, freio de tentativas.
  2. api/v3/auth.py e api/v3/deps.py — login e como o token vira o moc que toda rota recebe.
  3. infra/identity.py — chaves Ed25519 (assinatura) e X25519 (cifragem).
  4. services/permissions.py — can(): toda decisão de acesso passa aqui.
  5. services/acesso_galaxia.py, services/grupos.py, services/acl.py.
  6. infra/envelope.py — cifragem de ponta a ponta.
  7. services/challenge.py, services/recovery.py, infra/seed_phrase.py.

Duas identidades, uma pessoa

  • Senha (password_hash PBKDF2-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 no saber.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

A cabaça lacrada

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

  1. Em test_token_federado_recalcula_papel.py, leia mucua_de_fora_nao_responde_por_mocambola_daqui. Explique o ataque com suas palavras.
  2. Crie um saber com protecao: acl e leitores: [alguém]. Tente ler como anônimo pela listagem, pelo detalhe, pela coleção, pelo download do anexo. (test_vazamentos_de_leitura.py faz isso.)
  3. Em permissions.py, qual é a diferença entre acl e cifrado para 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?

vedi questo capitolo come sapere