Two pieces the composer has been waiting for since it was written. **The credential has to outlive its own minting.** On the bus the mesh runs on today an account is a management call: mint a password, hand it over, seal the plaintext to whoever will use it, keep nothing — which works because the broker remembers. Here the users are one file, rewritten whenever any of it changes, so keeping nothing would mean the first person's access change silently blanking every module's password. So a bus user's bcrypt hash is now recorded, keyed by the username the file needs, and the plaintext comes back exactly once. Verified against a real store that the hash verifies the password it was made from, that the password itself is not in there, that minting again rotates rather than adds, and that forgetting a node takes its host's and its modules' credentials with it. **Permissions are not stored, and that is the point.** Only the credential is kept. Authority is derived from what each module declares, every time the file is written (ADR 0043) — a stored permission list would be a second account of a user's authority, able to disagree with the records it came from, and both would look internally consistent while they did. `Users` derives the list: the controller always first and always present, one user per node, one per module per node, one per live token, one per person. Two users with one name is refused where both can be named, rather than left to be whichever one the server happened to read. A user the mesh has never minted a password for is *named* rather than dropped or written as a user anybody is: that is an ordinary situation with an obvious remedy, and the caller decides whether a partial file is worth writing. What remains of 1.7: delivering the file to the node that runs the server, and minting at enrolment and assignment — which is transport-coupled, because a node on the old bus must not be handed a credential for the new one.
37 lines
2.2 KiB
SQL
37 lines
2.2 KiB
SQL
-- Every bus user's password hash, because the file has to be written again.
|
|
--
|
|
-- novox/hq design 25 §4, task 1.7. On the bus the mesh runs on today an account is created by a
|
|
-- management call: the mesh mints a password, hands it over, seals the plaintext to whoever will
|
|
-- use it, and keeps nothing. That works because the broker remembers.
|
|
--
|
|
-- The bus being built has no management call — its users are a file the controller composes, and
|
|
-- **the whole file is written every time any of it changes**. So the first person's access change
|
|
-- would silently blank every module's password. The hash has to outlive its own minting, which is
|
|
-- state the mesh did not need before and does now.
|
|
--
|
|
-- Keyed by username, because the username is exactly what the composed file needs and what a
|
|
-- principal derives from its own identity. Nothing else about the user is here: **permissions are
|
|
-- not stored.** They are derived from what each module declares, every time the file is written
|
|
-- (ADR 0043) — a stored copy would be a second account of a user's authority, able to disagree
|
|
-- with the first, and the disagreement would be invisible until somebody compared a file with a
|
|
-- manifest.
|
|
--
|
|
-- The hash and not the password. A file on a node's disk holds the hash, and so does this: a
|
|
-- credential recoverable from the mesh's store is one whose blast radius is the store's.
|
|
create table bus_user (
|
|
username text primary key,
|
|
-- kind and what it names, so a user whose subject is gone can be found and removed: a module
|
|
-- unassigned, a node forgotten, a token spent. Recorded rather than parsed back out of the
|
|
-- username, because a name is for the server and a parser over it would be a second grammar.
|
|
kind text not null,
|
|
node text not null default '',
|
|
module text not null default '',
|
|
password_hash text not null,
|
|
minted_at timestamptz not null default now()
|
|
);
|
|
|
|
-- Finding every user of one kind, and every user belonging to one node — which is what removing a
|
|
-- node, or composing after an assignment, asks.
|
|
create index bus_user_kind on bus_user (kind);
|
|
create index bus_user_node on bus_user (node) where node <> '';
|