diff options
| author | tv <tv@krebsco.de> | 2026-11-08 13:48:01 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-08 15:03:52 +0100 |
| commit | 40907ae285317eaaf6449ff17d40b58a1a5df665 (patch) | |
| tree | 0252700cf4b4dfbfb8e2312db26ee1a163ad7e22 /src/document | |
| parent | 46e6b42278db1a3f51d1f5e1fe887f74ed2b69db (diff) | |
screen: a signature vouches for its change and what it builds on
Review finding 5: vouching by (actor, seq) isn't bound to a hash. A
member can make a change under another member's actor at a seq that
member's signature covers. The change is then taken as vouched, and if
it breaks a rule, the honest member is refused as a whole and logged as
the one whose own change broke the rules.
A signature now vouches for its change and the changes of its actor it
builds on: in the document, as before; among received changes, those
it reaches through the batch's dependencies. A received change under an
actor at a seq whose change the document holds (a signature verified up
to it) is a fork: refused as forged, never as its actor's node's, not
told back in REFUSALS, and logged with the peer that brought it.
Diffstat (limited to 'src/document')
| -rw-r--r-- | src/document/signatures.rs | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/src/document/signatures.rs b/src/document/signatures.rs index 5d8731b..19c13b8 100644 --- a/src/document/signatures.rs +++ b/src/document/signatures.rs @@ -4,8 +4,11 @@ //! //! One signature vouches for more than its change: a change's hash covers its //! dependencies, and a node's change builds on its previous one, so a signed change of -//! an actor vouches for all that actor's changes up to it (`check`: the actor and seq -//! it verifies up to). So not every change needs one: a change is signed when it +//! an actor vouches for the changes of that actor it builds on: in the document, all +//! up to it (`check`: the actor and seq it verifies up to); received, not in it yet, +//! those among them it builds on (`access::screen`). Only those: anyone can make a +//! change under any actor, and one at a seq whose change the document holds is a fork +//! (`forks`). So not every change needs one: a change is signed when it //! touches protocol data (`_continuum`) or a path the swarm lists as signed //! (`_continuum/access/signed`, `listed`), or when its write asks for it (`Sign`); a //! change left unsigned is vouched for by the node's next signed one, which, as @@ -388,6 +391,22 @@ impl Signatures { } } + /// Whether a valid signature of `hash` is kept: it vouches for its change and the + /// changes of its actor it builds on. + pub(crate) fn signed(&self, hash: &ChangeHash) -> bool { + self.by_change.contains_key(hash) + } + + /// Whether `change`, not in `doc`, forks its actor's changes: `doc` holds a change + /// a signature verified of that actor at a seq as late, so its real change at + /// `change`'s seq too. Anyone can make a change under any actor; only its node can + /// sign one. + pub(crate) fn forks(&self, doc: &Document, change: &super::Change) -> bool { + self.latest.get(change.actor_id()).is_some_and(|latest| { + latest.seq >= change.seq() && doc.get_change_meta_by_hash(&latest.hash).is_some() + }) + } + /// Whether a signature vouches for `actor`'s change `seq`. pub(crate) fn verified(&self, actor: &super::ActorId, seq: u64) -> bool { self.latest |
