| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
| |
Review 4, appendix: whether a write is signed because `_continuum/access/signed` lists
its path compared the listed paths by prefix (`signatures::related`), so a `*` there
was a literal key, while api.md says the list holds paths as capabilities name them,
which take `*` since 1259, and signed values already read the same list as patterns
(`envelope::reaches_signed`). A listed `metrics/*/alerts` signed nothing.
It compares by `access::agree` now: within or above the pattern, `*` for any one key.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Review 4, F5: a delta, and a message whose changes held more than 256 signatures (a
whole document pulled, of any real history), carried each actor's latest signature,
the 256 that became latest last. An actor is a node's run, so past 256 runs writing in
an epoch, some actors' changes arrived unvouched at the puller under a policy requiring
signatures, waited, and every resend carried the same 256: a joiner never finished.
A message now carries up to 4096 signatures (`MAX_PER_MESSAGE`, as many as wait for
their changes, `MAX_PENDING`: 384 KiB at most), all of its changes' up to there, each
actor's latest past it and for a delta, and a receiver takes as many (wire version
47). An epoch with more than 4096 runs writing would still leave some unvouched in
such a transfer, which the constant says; sending each actor of the transfer its own
latest would need the actors of a delta's changes, which only rebuilding their
metadata gives.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
and after a swap
Review 4, F2 (the honest case) and claim 2: a node signed at start its own changes at
the heads that nothing vouched for (1216), and after a swap only its current actor's
latest. An own change left unsigned can sit below the heads: a drop (`drop_taken`)
takes away a signed change and keeps an earlier unsigned one, and the node writes on
under a fresh actor, building on it; or a node's change is built on by another's
concurrently with the signed one the drop took. Nothing signed it again, and under a
policy requiring signatures every node pulling it (a joiner) waited for good, and for
everything built on it.
Now the latest change of each of the node's actors (`RemakeState::own_actors`, the
current one among them) that no signature vouches for is signed
(`Signatures::sign_own_actors`), at start and whenever the document is swapped (a drop,
a switch, a rejoin), the old `sign_own_heads` and `sign_own_latest` going. One
signature per actor vouches for all its changes before it. The case of a member whose
signed change the rules refuse, vouching once for its earlier ones, is
postponed (future-work.md, next).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A sync message carried the signatures its peer wasn't sent yet, by a
cursor per peer. Changes sent again, as after a message taken as
delivered and lost on the way, went without them: the peer was past
them. Under a policy requiring signatures they waited until the
writer's next signed change, or the next session.
A message now carries the signatures of the changes it carries
(Signatures::for_changes), whatever the peer was sent before: changes
sent again arrive vouched for as the first time. Past 256 (a message
carrying the batches of many writers), each writer's latest instead,
as a delta carries. The cursor goes, and with it resetting it after a
failed send or a new session.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A node signed its changes no rule signs a while after them (--sign-every
1s): the change left at once, unsigned, and its signature followed on
its own a second later, to every neighbour, over every link. A few
writes made a cascade of SIGNATURES. Under a policy requiring
signatures it signed every change as it was made instead.
A node now signs its latest change, if no signature vouches for it, as
a sync message takes it (--sign-every sent, the default): the
signature leaves in the same message, and goes where the change goes.
One signature per message, however many changes it carries, each
vouching for those before it: a slow writer's every change is signed,
a fast writer's batches are, at no threshold to pick. A policy
requiring signatures signs what is sent too, even with `none`. `all`
still signs every change as it is made; changes to protocol data,
listed paths and ?signed=true writes are signed as they are made, as
before. The interval, and the task signing on it, go.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
A node commits a change, keeps it in its document file, and may stop
before any signature vouches for it. It starts again under a new
actor and only ever signed its current actor's latest change: the old
one stays unsigned for good. Peers pulling it then wait for a
signature under a policy requiring them, and so does everything the
node writes after, building on it. Signing every change at commit hid
this under such a policy; signing what is sent, next, won't.
At start, before anything leaves, a node signs each of its own
changes at the document's heads that no signature vouches for:
nothing it made since builds on them, so they are heads.
|
| |
|
|
|
|
|
|
|
|
| |
With every message's signatures offered now (1205), Signatures::offer
runs for each, and it asked get_change_meta_by_hash whether the
document holds each signature's change, and each one waiting, up to
4096 of them: Automerge rebuilds the change's metadata from the
document's operations to answer. Ask changes::holds instead (1197),
there and in forks and kept_for; the metadata is still read where it
is used.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Review finding 9: once 4096 signatures waited for their changes, new
ones were dropped, and the waiting changes were cut at 10 000 keeping
the oldest. A member could send junk once (signatures of changes that
never come, changes no signature will vouch for) and fill both for
good. Every honest signature arriving before its change was then lost,
so under signatures required its changes waited for the actor's next
signature: a stall for quiet actors.
Both now keep the newest: the oldest go. A share per sender, so a member
sending junk without pause can't push out what others sent either, is
in future-work.md.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Review 2.2: swap_document forgot every signature. After dropping
changes taken unjudged (or a rejoin into the same epoch), the node
could vouch for none of the changes it kept: under signatures required,
those building on an actor waited for that actor's next signature, and
for an actor that stopped writing, forever.
Signatures::kept_for keeps the signatures of the changes the new
document holds, checks each actor's latest again, and keeps those
waiting for their changes. This node's replayed changes are signed at
once, as before.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
| |
"values": "signed" (strict, requiring signatures too): the registry,
_continuum/access, bans and the paths in _continuum/access/userSigned
(* for any key) hold values their users signed. Envelopes read as the
values they hold where the node reads protocol data.
Auth plan M7.
|
| |
|
|
|
|
|
|
| |
"signatures": "required": a change counts only once a signature by its
committer vouches for it, and waits until then; every node then signs
every change it makes.
Auth plan M6.
|
| |
|
|
|
|
|
|
|
|
| |
access::rules::judge: a change judged as its writer saw the document
(at its dependencies): committer a member or registering itself;
members' entries and votes their own; epochs and swarm ID from roots;
a remake's decision by its coordinator; the rest by the registry for
the user the change names.
Auth plan M6.
|
| |
|
|
|
|
|
| |
GET /admin/changes shows whether a signature by its node vouches for
each change.
Auth plan M5.
|
| |
|
|
|
|
|
| |
Sync messages carry, for each actor's writes, the latest signature the
sender checked; the receiver checks it once it holds the change.
Auth plan M5.
|
| |
|
|
|
|
|
| |
A node's signatures are saved with its document (--document-file) and
loaded with it.
Auth plan M5.
|
| |
|
|
|
|
|
|
| |
Changes left unsigned are vouched for by the node's next signature:
--sign-every 1s (default) signs the latest within a second, all signs
every change, none only those that must be.
Auth plan M5.
|
|
|
Every node signs the changes it commits with its node key, an Ed25519
signature over the change's hash, kept beside the document. One
signature on an actor's latest change vouches for its earlier ones.
Protocol data and paths listed in _continuum/access/signed are signed,
and writes with ?signed=true.
Auth plan M5.
|