aboutsummaryrefslogtreecommitdiffstats
path: root/src/document/signatures.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-12 01:13:54 +0000
committertv <tv@krebsco.de>2026-11-12 02:47:08 +0100
commit81dc0ca6012372ff293e19549053fda84bca1eb0 (patch)
tree883f867ee70072d38e26b907ce4734cad40f0ba8 /src/document/signatures.rs
parent5b13f5e9d83a11b8a60f2d4711065360ba20f70c (diff)
screen: refuse a change at a seq this node made under its own actor
A node receiving a change of the actor it writes as, one it doesn't hold, writes on as a fresh actor (another node writes as it, from a copy of its files). Where the other node made it at a seq this node made a change at too, the change was taken to Automerge, which refuses the whole batch (duplicate seq): the message failed, and with it everything else it carried. Signatures::forks found it forged only where a signature verified a change of the actor at that seq, and this node signs its own latest change only as it sends it. forks now also finds a change forged where its actor is the one the document writes as and the document's latest change of it (get_last_local_change) is at its seq or later. apply_bytes switches to the fresh actor after judging the batch, not before, so the check still sees the actor; also where judging fails.
Diffstat (limited to 'src/document/signatures.rs')
-rw-r--r--src/document/signatures.rs8
1 files changed, 6 insertions, 2 deletions
diff --git a/src/document/signatures.rs b/src/document/signatures.rs
index 4f34ecb..79c8569 100644
--- a/src/document/signatures.rs
+++ b/src/document/signatures.rs
@@ -603,11 +603,15 @@ impl Signatures {
/// 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.
+ /// sign one. Or the actor is the one `doc` writes as, and it made a change at a seq
+ /// as late: another node writing as it too made this 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() && super::changes::holds(doc, &latest.hash)
- })
+ }) || (change.actor_id() == doc.get_actor()
+ && doc
+ .get_last_local_change()
+ .is_some_and(|own| own.seq() >= change.seq()))
}
/// Whether a signature vouches for `actor`'s change `seq`.