A LOT More progress on the README

parent 57334bc5
......@@ -255,17 +255,169 @@ more sense:
possible so we need to know which one. In this case, it's
aes-ctr.
** Federating and retrieving content
This is all very good and well, but what does it look like during
federation?
In other words, what did Alice actually send to Bob's inbox?
If you've read the [[https://www.w3.org/TR/activitypub/#Overview][ActivityPub overview section]] you'll recall
that federation works by looking up the inbox of a recipient
and doing an HTTP POST to that location.
The contents of that POST was the following:
#+BEGIN_SRC javascript
{"@id": "magnet:?xt=urn:sha256:Cvy4hoVEsY7n3T2wf4306IhhBS1CV03pNuLtMOR73xc&ek=_T8EGDBegDdmMdqRG4Lyd8zFto0cmck4FoaRzsXcM08&es=aes-ctr"}
#+END_SRC
"... That's it?" I hear you saying.
"Where's the rest of the message?"
Well, the =@id= is the real official location of the message.
We need to fetch the object to verify that it matches that address
and to put it in our store, so why do so twice?
So anyway, our server must retrieve the object matching the hash
of the =xt= query parameter.
Where does it get it from?
Well, do you remember setting up the =--other-stores= keyword argument
in back in the [[*Running Golem][Running Golem]] section?
There are all sorts of ways to configure searching for chunks of
content, but in this demo we're doing the simplest possible thing and
just asking a fixed number of "content addressed stores" if they
have the chunk.
In fact, we just set up Alice and Bob's servers to look at each other!
Each server is running a read-only content-addressed-store at the
=/read-only-cas= path.
For instance, if I want to ask Alice's server if it has the
=urn:sha256:Cvy4hoVEsY7n3T2wf4306IhhBS1CV03pNuLtMOR73xc= chunk,
I can just query it like:
[[http://localhost:8000/read-only-cas?xt=urn:sha256:Cvy4hoVEsY7n3T2wf4306IhhBS1CV03pNuLtMOR73xc]]
Replace the =xt= parameter value with the URN on your own server and you
should be able to save it.
(However, this file will look like binary garbage until you use the =ek=
key to decrypt it.)
So this is exactly what happens in our demo... Alice writes a note to
Bob, and Alice's server encrypts it, splits it into chunks, and sends
an object with the magenc link to Bob's server.
Bob's server (or, this could also be done in a client) can then search
for those chunks (currently, by searching Alice's store, which indeed
Alice is keeping those chunks around since she made them and wants
Bob to find them) and can use the key provided in the magenc link
to decrypt the content.
As it turns out, the Racket magenc demo ships with a nice command line
tool you can use to fetch the contents yourself.
Let's try pulling down the content from Alice's server using the
magenc link that shows up in our client.
You can try it like so (be sure to remove the for-reading-convenience
whitespace from the magnet URI provided in the web interspace):
: raco magenc \
: --get "magnet:?xt=urn:sha256:tahXSX6UJgbT4lygwlyAYEDhM4pq2s0PwC0Ofl_edY0&ek=KHHtWzsx0isYYVJkNCkLXgdv0FIIY2DXKc0hxoX_-9w&es=aes-ctr" \
: http://localhost:8000/read-only-cas
(The last arguent is the web address of the content-addressed-store
we want to read from.)
On my machine, the value I get back is (with a bit of pretty printing
applied):
#+BEGIN_SRC javascript
{"actor": "http://localhost:8000/",
"object": "magnet:?xt=urn:sha256:dO0lxH3zV7S9-sP0f0hzWr0QAopkjB2NSG7pYTmt5bY&ek=msDNJDcFKuFRmIeHolBksU0iQILCoAvAACTHSCr5Iaw&es=aes-ctr",
"to": ["http://localhost:8001/"],
"type": "Create"}
#+END_SRC
Oh that's interesting... so this is the =Create= activity alright,
made by our actor.
But the object is itself is... yet another magenc link.
So let's fetch that too:
: raco magenc \
: --get "magnet:?xt=urn:sha256:dO0lxH3zV7S9-sP0f0hzWr0QAopkjB2NSG7pYTmt5bY&ek=msDNJDcFKuFRmIeHolBksU0iQILCoAvAACTHSCr5Iaw&es=aes-ctr" \
: http://localhost:8000/read-only-cas
The value I get back (again, pretty printed for readability) is:
#+BEGIN_SRC javascript
{"type": "Note",
"attributedTo": "http://localhost:8000/"
"content": "Hello, Bob!"}
#+END_SRC
Yep, this seems right!
Since Bob also gets and stores the content, we can also test retrieving
the content from his server and that should work too.
In a production system, servers might indeed expose such an endpoint
for retrieving content that originates on their servers, but in
general it would be good to have a more global store of chunks
available, such as a distributed hash table.
In fact, the popular IPFS system could be used very easily today.
Anywhere that the =urn:sha256:= URIs appeared in this demo,
an =ipfs:= address could appear instead, if we wired things up
to understand IPFS.
Several other fields in the magnet URI scheme are already defined
and in production today to point at sources that content may be
found.
* Some words on liveness and immutability
The astute observer will note that liveness has not entirely
disappeared from this demo.
The publish-subscribe mechanism of ActivityPub requires being able
to POST to an actor's inbox.
So we will indeed need something like http(s) for that purpose,
but everything else (including the actor profiles themselves)
can be stored in a persistent matter as described in this document.
Privacy can also be maintained and the system could be made more "peer
to peer" for the liveness end by using something like Tor .onion
addresses or I2P .i2p addresses.
However this still requires that a server be online and available.
The astute observer will also observe that content cannot be changed
in the above system.
This is true, though there are some ways around this; freenet, IPFS,
and tahoe-lafs all have ways to reference "updateable" content, and
composing with or adopting the ideas of such systems could be done.
(For the moment, this is left as an exercise to the reader.)
Additionally, it is possible to have future Update documents "point
back" to the original document; however, doing this securely would
require introducing a certificate style capability system which could
be as simple as having a catch-all grant to certain keys to be able to
sign off on updates, or something more complicated such as [[https://w3c-ccg.github.io/ocap-ld/][ocap-ld]].
(ocap-ld is only one of several capability approaches that will
be explored as possibilities in future documents.)
* Caveats
** Federating out encrypted, content-addressed content
** Retrieving that content
* Verify it yourself!
* Problems with this demo
- urn:sha256 isn't actually specified yet, but it probably should be.
- At the time of writing, the magenc extensions to the magnet scheme
aren't used by anything in production yet.
Maybe things could or should change a little before that happens.
If you're interested in using Magenc seriously, [[https://dustycloud.org/contact/][contact the author]].
- =urn:sha256= isn't actually specified yet either, but it probably
should be.
For whatever reason (okay, the reason is that there was a base64
encoding utility built into Racket) the author used base64 encoding
of the hash in the URN but it could be that if =urn:sha256= went
mainstream that it would use base32 encoding instead.
- The [[https://gitlab.com/spritely/golem/blob/master/golem.rkt][code for this demo]] has intentionally made many assumptions
and oversimplifications that a production system would not make.
For one thing, only =Create= and =Note= are supported for activities
and objects, and no attempt is made to check that a post is made
by the author that claims to make it.
Other extensions to ActivityPub which are currently conventional,
such as the use of [[https://www.ietf.org/archive/id/draft-cavage-http-signatures-10.txt][HTTP Signatures]] or [[https://en.wikipedia.org/wiki/WebFinger][WebFinger]] have been
intentionally left out, so don't expect compatibility with
"modern day" ActivityPub servers.
* Conclusions
TODO
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment