1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# Users and what they may do
Who the users are, and what each may do, is the swarm's: a registry in the document,
the same on every node. How a user proves who it is stays each node's: its
`--htpasswd`, or a reverse proxy naming the user (`--user-header`, [`trust.md`](trust.md)).
## The registry
`_continuum/users/<name>`, one entry per user. It is protocol data: every member holds
it, a remake's snapshot carries it into the next epoch, and it holds no secrets (no
password hashes: every member reads the document).
```json
{ "since": 1762400000000, "by": "continuum:3f…",
"caps": { "8c41e2…": { "path": [], "rights": ["read", "write"],
"by": "continuum:3f…", "since": 1762400000000 } },
"disabled": false }
```
* **Names** are what `--htpasswd` and the proxy give: 1 to 64 of `A-Z a-z 0-9 . _ @ -`.
* **Capabilities** (`caps`): each a path, as segments as the store's API takes them,
and the rights it gives there and below: `read`, `write`. A capability covers its
path segment by segment (`servers/eu` covers `servers/eu/0`, not `servers/europe`).
One outside protocol data never covers protocol data: `[]` is all of the swarm's
data, `["_continuum"]` protocol data, managing users included (`_continuum/users`).
They are kept by a random ID, so two capabilities granted at once both hold, and
revoking one removes it alone. Each names who granted it (`by`: a user as
`user:<name>`, or the node that recorded it) and when (`since`).
* **`disabled`**: the entry stays (who wrote what stays readable), and gives nothing.
An entry that doesn't read as above gives less, never more: a capability that
doesn't read is left out, and anything but `false` disables.
## A new swarm
Its genesis node records the first users, with the swarm ID, in its first change:
* those of `--bootstrap-users`, each with everything (`[]` and `["_continuum"]`);
* unset: the users of its `--htpasswd` with `[]`, and those of them, or of the
proxy's, in `--protocol-writers` with `["_continuum"]` too.
A swarm nobody could manage doesn't start: with none of them with `["_continuum"]`,
`--genesis` is refused, naming both options.
## At the HTTP API
Every request is checked against the registry, as the node serving it holds it: a
change to it counts on a node as soon as it has reached it.
* **The store** (`/store`, `/stream`): writing a path (`PUT`, `POST`, `DELETE`) takes
`write` on it; `?prune=true` deletes maps left empty only up to the highest one the
user may write. Reading takes `read`: of a place the user may read only partly, it
sees the keys on the way to what it may read, as a directory one may pass through
but not list (a capability on `servers/eu` shows `servers` with `eu` alone in it),
and nothing else; a list on the way is left out whole, as its items have no paths of
their own. Native forms (`text/plain` of a map, a counter as its own type) only of
what it may read whole. What a write answers with is what was written. A stream
shows what the user could read when it opened.
* **Protocol data** is in the store too, under `_continuum`: `read` and `write` on it
as on any path.
* **Looking at the node** (`/admin/stats`, `GET /peers`, the dashboard): any user with
a capability.
* **Remakes** (`/admin/remakes`): `read` on `_continuum/remakes` to look, `write` to
propose or abort one. **Forgetting a peer** (`DELETE /peers/…`): `write` on
`_continuum/forgotten`.
* **Everything else an operator does** (`/admin/config`, `/admin/log`,
`/admin/document`, `/admin/changes`, `/admin/epochs`, `/admin/quarantine`, `/debug`):
`read` on `_continuum` to look, `write` on it to act.
A user the node lets in but the registry doesn't have may do nothing (`403`).
`[]` and `["_continuum"]` are two capabilities on purpose: protocol data acts on the
whole swarm (its members, its remakes, its users), so it is given apart, never by
accident with the data. A user who may do both has both.
## An existing swarm
A swarm whose document has no registry (one from before it, `_continuum/users`
missing) goes on as before: every user a node lets in may read and write the swarm's
data and use the admin endpoints, and only those in `--protocol-writers` write
protocol data. It gets a registry once a protocol writer writes one, through the store:
```sh
curl -u alice --request PUT --header 'Content-Type: application/json' \
--data '{"since": 0, "by": "user:alice", "disabled": false,
"caps": {"1": {"path": [], "rights": ["read", "write"]},
"2": {"path": ["_continuum"], "rights": ["read", "write"]}}}' \
http://localhost:3000/store/_continuum/users/alice
```
From that write on, every node serves only the users the registry has, so the first
entry must be the writer's own, with `["_continuum"]`, or nobody may change the
registry again; add the other users the same way.
|