aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/access.md37
-rw-r--r--docs/api.md8
-rw-r--r--docs/openapi.yaml4
3 files changed, 47 insertions, 2 deletions
diff --git a/docs/access.md b/docs/access.md
index 57462db..6f89b49 100644
--- a/docs/access.md
+++ b/docs/access.md
@@ -290,3 +290,40 @@ that checks, replacing the one there then; nothing within one; and above one, no
replacing or deleting what holds one (a map made where there is none yet is fine). So
a member writing to its document directly gets nothing there past the others: the
registry, the policy and the bans change only as a user who may change them signed.
+
+## Values sealed for their readers
+
+Anyone may read the whole document: every member holds it. A value only some may read
+is sealed for them: encrypted with age to their SSH keys (`keys`, The registry,
+above), so only they open it. Every node syncs, stores and remakes it as the string it
+is, and none decrypts it: `cs1.<the age file, base64url>` (binary, not armored).
+
+```sh
+jq -r '.keys[]' <(curl -s -u alice localhost:3000/store/_continuum/users/bob) > readers
+printf %s "$secret" | age -R readers | basenc --base64url -w0 | tr -d = |
+ sed 's/^/cs1./' | jq -R . | curl -u alice -X PUT localhost:3000/store/secrets/db -d @-
+```
+
+Any value anywhere may be sealed, for anyone. Where the swarm declares it, every value
+must be: `_continuum/access/sealed`, a list of `{"path": [...], "readers": [...]}`, `*`
+in a path for any one key, written as any of `_continuum/access` (under a strict
+policy, signed).
+
+```json
+[{"path": ["secrets", "*"], "readers": ["alice", "bob"]}, {"path": ["notes"]}]
+```
+
+Without `readers`, a value there must be sealed, for anyone; with them, sealed for
+exactly their keys, as the registry has them when it is written. A node tells without
+decrypting: an age file names each `ssh-ed25519` recipient by a tag, the first four
+bytes of the SHA-256 of its key. A write leaving a value there plain, or sealed for a
+reader's key too few or a stranger's too many, is refused (`409`), and with the policy
+every node refuses such a change on receipt (Changes judged on every node, above). A
+value signed by its user (Values signed by their users) holds the sealed value; the
+signature is over the ciphertext, so every node checks who wrote it without reading
+it.
+
+It guards against mistakes, not against a writer: one who means to leak a value has
+it. A reader removed keeps what it read: values stay sealed for the readers they were
+written for until written again, sealed for those declared then. Which values there
+are, their sizes, when and by whom they were written stay visible to every member.
diff --git a/docs/api.md b/docs/api.md
index 92289bf..7d7a563 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -302,6 +302,14 @@ and a read of one names its signer (`x-continuum-signed-by`). `?raw=true` shows
they are stored, envelopes, which anyone can check; so do typed JSON and native reads,
and streams (`/stream`).
+## Sealed values
+
+A value may be sealed for its readers, encrypted with age to their SSH keys
+([`access.md`](access.md), Values sealed for their readers): a string,
+`cs1.<age file>`, that the API stores and shows as it is. Where the swarm declares
+values sealed, a write leaving one there plain, or sealed for others than the declared
+readers' keys, is `409`.
+
## 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 1bd3a16..ab14710 100644
--- a/docs/openapi.yaml
+++ b/docs/openapi.yaml
@@ -208,7 +208,7 @@ paths:
'403':
description: The user may not write here (its capabilities, docs/access.md; in a swarm without a user registry, protocol data `_continuum` and the user isn't in `protocol-writers`), or epoch metadata or the swarm ID (`_continuum/epochs`, `_continuum/swarm`, never writable); a signed value not by this user, or whose signature doesn't check (the message says why).
'409':
- description: The path crosses an existing non-map value, or with `retype=false` the write would change a type (the message says where); a value not signed reaching one its user signs under a strict policy; a signed value where values aren't signed, or replacing another than the one there (read again).
+ description: The path crosses an existing non-map value, or with `retype=false` the write would change a type (the message says where); a value not signed reaching one its user signs under a strict policy; a signed value where values aren't signed, or replacing another than the one there (read again); a value left not sealed as the swarm declares (`docs/access.md`, Values sealed for their readers).
'415':
description: Content-Type is none the API takes (`application/json`, the default; `text/plain`; a type's own, `api.md`, Types).
'500':
@@ -300,7 +300,7 @@ paths:
'307':
description: A negative index, made positive (`Location`).
'409':
- description: Not a list there, or the index is past its end (the message says which, and the length); with `increment`, not a counter there; with `cast`, no cast possible (the message says why); under a strict policy, reaching a value its user signs.
+ description: Not a list there, or the index is past its end (the message says which, and the length); with `increment`, not a counter there; with `cast`, no cast possible (the message says why); under a strict policy, reaching a value its user signs; a value left not sealed as the swarm declares.
'415':
description: Content-Type is none the API takes (`application/json`, the default; `text/plain`; a type's own, `api.md`, Types).
'503':