From 8523e9c67e375747147a0b05ec191ad81ce2e318 Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 7 Nov 2026 22:35:21 +0100 Subject: signatures: changes signed by their node 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. --- docs/api.md | 18 ++++++++++++++++++ docs/openapi.yaml | 14 ++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'docs') diff --git a/docs/api.md b/docs/api.md index 803e457..e380c95 100644 --- a/docs/api.md +++ b/docs/api.md @@ -28,6 +28,7 @@ curl -u alice:secret -X POST 'localhost:3000/store/stats/visits?increment=1' # removes the maps it leaves empty), and `POST` inserts into a list at an index, the items from there moving up, or with `?increment=n` adds `n` to a counter (Concurrent writes), or with `?cast=` casts what is there to another type (Types). + `?signed=true` on any of them has the node sign the change (Signed changes). * Bodies are JSON (`application/json`, the default), text (`text/plain`, stored as a string), or a value of a type of its own (Types); answers are JSON, or as `Accept` asks. Numbers in JSON are stored as integers where they fit, as floats otherwise. @@ -241,6 +242,23 @@ touched what is at `settings`. Every node holds every change, so user names are known to the whole swarm, and so is who wrote what, until a remake drops the history ([`remakes.md`](remakes.md)). +## Signed changes + +Every node signs changes it commits with its node key: an Ed25519 signature over the +change's hash, kept beside the document. One signature vouches for more than its +change: a node's change builds on its previous one, and a change's hash covers what it +builds on, so a signed change vouches for all the node's changes before it. So not +every change is signed, only those that + +* touch protocol data (`_continuum`), +* touch a path listed in `_continuum/access/signed` (within it, or above it), a list + of paths, each a list of segments as capabilities name them + ([`access.md`](access.md)): `[["config"], ["servers", "eu"]]`, +* or were written with `?signed=true`. + +A change left unsigned, such as a metric written many times a second, is vouched for +by the node's next signed one. + ## Protocol data `_continuum` holds what the nodes coordinate through: the swarm ID, the member registry, diff --git a/docs/openapi.yaml b/docs/openapi.yaml index ffd22dd..2e131fb 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -153,6 +153,7 @@ paths: schema: type: boolean default: true + - $ref: '#/components/parameters/signed' requestBody: required: true content: @@ -230,6 +231,7 @@ paths: type: string enum: [rfc3339, unix, unix-ms, http-date] default: rfc3339 + - $ref: '#/components/parameters/signed' requestBody: required: false content: @@ -290,6 +292,7 @@ paths: schema: type: boolean default: false + - $ref: '#/components/parameters/signed' responses: '204': description: Deleted. @@ -1598,6 +1601,17 @@ components: description: A token from `POST /auth/login` on any node of the swarm (docs/access.md, Tokens). parameters: + signed: + name: signed + in: query + description: | + Whether this node signs the change with its node key, whatever its path. A + change is signed anyway where it touches protocol data (`_continuum`) or a path + listed in `_continuum/access/signed`; one left unsigned is vouched for by this + node's next signed change (`api.md`, Signed changes). + schema: + type: boolean + default: false key: name: key in: path -- cgit v1.3.1