feat: parse mailbox requests and factor out the address claim

dispatch::request recognises Twt-Register, Twt-Help, Twt-Admit, Twt-Block and
Twt-Registration, validating values but deciding nothing: whether the sender
may do what they asked is the caller's business, as with the rest of this
module.

One command per mail. Two requests have no sensible order, and a request mixed
with a feed command would make the reply ambiguous about what took effect.
Twt-Register takes an optional nick, validated against the nick rule rather
than the path rule, since the value lands in feed metadata.

dispatch::claimed is follow_rotation's Reply-To extraction, lifted out and
documented for what it actually proves: the sender signed this URI. It does
not prove they hold the mailbox it names. follow_rotation is safe on that
alone only because it additionally demands a feed already bound to the address
and a signed chain from the key on file; a registration path has neither and
must resolve the address itself.

Twt-Help ignores any value rather than refusing one — failing a request for
help on a typo would be perverse.

Also narrows i18n's id list back to the ids looked up by name: generating it
from the catalogue made that test assert the catalogue against itself. The
reason-* ids are covered by walking the enum instead, which cannot drift.
This commit is contained in:
randogoth 2026-10-14 19:37:17 +03:00
parent ff289671a5
commit 03e54fea49
5 changed files with 254 additions and 18 deletions

View file

@ -71,3 +71,12 @@ reason-reply-to-changed =
your Reply-To does not match the feed's bound author { $author }; send from
that address or mail the operator
reason-no-record-at = no record at { $timestamp }
## Mailbox requests — register, help and the admin commands
reason-one-command-per-mail =
one command per mail: send Twt-Register, Twt-Help, Twt-Admit, Twt-Block or
Twt-Registration on its own, and feed commands in a separate mail
reason-bad-address = `{ $got }` is not a smolmail address
reason-registration-mode-unknown =
unknown registration mode `{ $got }`, want open, closed or silent