From 1fa5360a210b4b820441fdbc6f5dfbbb9eaf14f3 Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 8 Nov 2026 21:46:41 +0000 Subject: screen: signatures required as the policy a change came under says Review 3, R1: what a node received was vouched for only while its own document's policy required signatures. A joiner's first sync, and every node's message bringing `required`, went in by the rules alone: a malicious first peer could plant changes under other members' actors at their next seqs, their real ones then failing as duplicates for good. The signatures a message carries are always offered now, and the screen always has them: a change waits for one where the policy at the heads it is judged at requires it (rules::Reads::required, read once per heads), whatever the receiving document holds. Changes written under a policy not requiring signatures wait for none, as on every other node; the check for forged changes runs always. Changes waiting for a signature are judged again whenever signatures come. The test of signatures required now takes the history into an empty document; a new one takes changes written under a policy not requiring them without any. --- src/access/rules.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/access/rules.rs') diff --git a/src/access/rules.rs b/src/access/rules.rs index bef9a13..ac7377f 100644 --- a/src/access/rules.rs +++ b/src/access/rules.rs @@ -109,6 +109,20 @@ impl Reads { } } +impl Reads { + /// Whether the policy at `seen` requires changes signed (`Policy::required`): read + /// once for the heads, as `judge_reading` reads it. False if `doc` lacks one of them. + pub(crate) fn required(&mut self, doc: &Document, seen: &[ChangeHash]) -> bool { + let Some(at) = At::new(doc, seen) else { + return false; + }; + self.at(seen) + .policy + .get_or_insert_with(|| super::policy::of(&at)) + .required() + } +} + /// Judges `change`, about to be applied to `doc` (of `epoch`). pub(crate) fn judge(doc: &Document, epoch: Epoch, change: &Change<'_>) -> Result<(), Refusal> { judge_reading(doc, epoch, change, &mut Reads::default()) -- cgit v1.3.1