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:
parent
ff289671a5
commit
03e54fea49
5 changed files with 254 additions and 18 deletions
|
|
@ -246,22 +246,12 @@ impl Daemon {
|
|||
incoming: &Incoming,
|
||||
state: &mut MutexGuard<'_, State>,
|
||||
) -> Result<Option<usize>, String> {
|
||||
let Ok(text) = std::str::from_utf8(&incoming.body) else {
|
||||
let Some(addr) = dispatch::claimed(incoming) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let (fields, _) = fumi_core::message::parse_frontmatter(text);
|
||||
let Some(reply_to) = fields.get("reply-to") else {
|
||||
return Ok(None);
|
||||
};
|
||||
let Ok(addr) = Address::parse(reply_to) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let Some(user_key) = addr.identity else {
|
||||
return Ok(None);
|
||||
};
|
||||
if user_key != incoming.sender {
|
||||
return Ok(None);
|
||||
}
|
||||
// The claim alone proves only that the sender signed this URI. What
|
||||
// makes it safe here is the next two lines: the address must already
|
||||
// own a feed, and the chain below must lead from the key on file.
|
||||
let Some(index) = state.feeds.iter().position(|f| f.address == addr.short()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue