Part II — Trunk and roots
05 · The circle: identity and permissions
Ubuntu: "I am because we are". In Baobáxia, who you are counts across the whole network; what you may do counts inside the circle that recognizes you.
Files to read
services/auth.py— passwords (PBKDF2), JWT tokens, verifying a token from another mucua, the login-attempt brake.api/v3/auth.pyandapi/v3/deps.py— login, and how the token becomes themocevery route receives.infra/identity.py— Ed25519 (signing) and X25519 (encryption) keys.services/permissions.py—can(): every access decision goes through here.services/acesso_galaxia.py,services/grupos.py,services/acl.py.infra/envelope.py— end-to-end encryption.services/challenge.py,services/recovery.py,infra/seed_phrase.py.
Two identities, one person
- Password (
password_hash, PBKDF2-SHA256, 200 thousand rounds) in the mocambola's saber. - Keys: an Ed25519 pair (signs authorship and tokens) + an X25519 pair (opens encrypted saberes). The private key stays in
~/.baobaxia/keys/<uuid>.json, encrypted with the password (scrypt + AES-GCM), mode 600 — it never travels. The public one goes insaber.bbx. BBX_AUTH_MODE=senha(password) |chave(key) |ambos(both, the default).
Login and token
sequenceDiagram
autonumber
actor P as Person
participant A as POST /auth/login
participant F as brake (services/auth.py)
participant S as SaberService
participant K as identity
P->>A: username (or name@uuid8 of the mucua) + password
A->>F: tentativas_bloqueadas?
alt too many failures in the window
A-->>P: 429
end
A->>S: find_mocambola (prefers the one from the local mucua)
A->>A: verify_password (PBKDF2, compare_digest)
A->>K: cache_session_key — unlocks the private keys in memory (8 h)
A->>A: _issue_for: effective role + administered galaxies
A->>K: signs an EdDSA JWT with the MUCUA's key (or HS256)
A-->>P: access_token (7 days) + profile without password_hash
With login by key: POST /auth/desafio returns a single-use nonce; POST /auth/login-chave sends the signature (and, for a secondary key, the delegation certificate signed by the main key).
A token signed by another mucua
flowchart TD
T[EdDSA token, iss = bbx:mucua:X] --> L{is X the local mucua?}
L -- yes --> K[verifies with the key that is ON DISK<br/>never with the pubkey from a saber]
L -- no --> P[verifies with the pubkey of saber mucua X]
P --> Q{is the sub mocambola known here?}
Q -- "yes, and from another mucua" --> N[refuses: X only vouches<br/>for its own mocambolas]
Q -- "yes, and from X" --> R[role, galaxies and mucua<br/>recomputed from OUR data]
Q -- no --> U[comes in as USER, with no scope]
The signature proves who someone is; never what they may do here. (This design is from version 3.3 — see module 11.)
can(): the decision
flowchart TD
A[can mocambola, action, resource] --> S{system actor?}
S -- yes --> OK[allow]
S -- no --> R{action = READ?}
R -- yes --> RA{draft?}
RA -- yes --> RB[only author, the mucua's PAJÉ,<br/>the galaxy's OXALÁ]
RA -- no --> G{restricted galaxy<br/>and not on the list?}
G -- yes --> NO[deny]
G -- no --> PR{protecao acl/cifrado?}
PR -- yes --> PL[readers, author;<br/>acl: + the mucua's PAJÉ]
PR -- no --> V[visibility: public → everyone<br/>mucua → same mucua or OXALÁ<br/>private → owner or PAJÉ]
R -- no --> W{anonymous?}
W -- yes --> NO
W -- no --> RO{read-only galaxy?}
RO -- yes --> NO
RO -- no --> E[saber editors UPDATE → local manager →<br/>owner → the mucua's PAJÉ → the galaxy's OXALÁ]
The resource descriptor is built in a single place (SaberService._descritor / _resource_of). When each route built its own, some forgot protecao and leaked — read the docstring of testes/test_vazamentos_de_leitura.py.
End-to-end encryption
With protecao: cifrado, each saber gets a content key (ChaCha20-Poly1305). description, body, location and the attachments (.bbxenc) are encrypted; title and tags stay in clear text for search. The saber's key is wrapped for each reader (X25519 ECDH + HKDF + AES-GCM). A role does not open the gourd: only someone holding a wrapping with their own name does.
Recovery
Three independent paths (services/recovery.py): a guardian authorizes rotating the identity (never seeing a password or any content), a seed phrase built from personal answers + entropy, or the key kept on the home mucua.
Practice
- In
test_token_federado_recalcula_papel.py, readmucua_de_fora_nao_responde_por_mocambola_daqui. Explain the attack in your own words. - Create a saber with
protecao: aclandleitores: [someone]. Try to read it as anonymous through the listing, the detail, the collection, the attachment download. (test_vazamentos_de_leitura.pydoes exactly that.) - In
permissions.py, what is the difference betweenaclandcifradofor a PAJÉ? Why is that difference honest?
To talk about
- The comment on
GalaxiaData.acesso(natures/schemas.py) calls the closed galaxy "software courtesy". What does that mean, and when is it enough? - Who should be the guardian of someone's identity in your community?
