5.54 KB
Newer Older
#+TITLE: Spritely Golem: Secure, p2p distributable content for the fediverse
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

This is a demo for Golem, one of the [[][Spritely]] demos.
Each Spritely demo tries to demonstrate a key idea on how
to "level up" the fediverse.

The problems this demo is trying to address is:

 - Nodes go down, and their content tends to go with them.
   How can we have content that survives?
   Content which is distributable over a peer to peer network seems
   like it would help.
 - Except if an entire network is helping hold onto and distribute
   content, how do we keep private content private?
 - How to do this in a way that is compatible with the [[][ActivityPub]]

By encrypting the file and splitting it into chunks distributed
through the network and only sharing the decryption key with the
intended recipient, and by using a URI scheme that captures the
appropriate information, we can accomplish all the above.
Golem uses the [[][magenc]] extension of the [[][magnet URI scheme]] to
accomplish the above.

Why the name "Golem"?
In fantasy literature and folklore, a Golem is assembled from
inanimate parts, and only through the casting of magic words is
it brought to life.
Likewise, here encrypted chunks are distributed inanimately through
the network, and the magic words uttered are the decryption key,
known only to the intended recipients (and, well, anyone they choose
to pass them on to).

*NOTE:* This demo is not intended for production deployments.
The purpose of this demo is to explain its core ideas to federated
social web implementors.
As such, the demo takes many shortcuts for the sake of brevity.
It is intended to be simple enough to be read and understood in
a single evening.
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

* How to install Golem

First you'll need [[][Racket]].
You'll have the option to install the minimal or full distribution of
Choose the full installation.

First do a git checkout of this git repository.
Then do: 

: raco pkg install

Okay you're ready to go!

* Running Golem

We're going to need two separate Golem servers running to test
federating with each other.
To do this, open two separate terminals and navigate both of them
to the Golem checkout directory.
Now let's start up each server.

In the first terminal:

: racket golem.rkt --port 8000 --other-stores "http://localhost:8001/read-only-cas" Alice

In the second terminal:

: racket golem.rkt --port 8001 --other-stores "http://localhost:8000/read-only-cas" Bob

In the first terminal, you should see a message like:

: Your Web application is running at http://localhost:8000.
: Stop this program at any time to terminate the Web Server.

Same in the second, but with port 8001.

Christopher Lemmer Webber's avatar
Christopher Lemmer Webber committed
Test it out by opening your browser and opening [[http://localhost:8000/]]
79 80
in your browser.
In the upper left hand side you should see "Alice's site".
Christopher Lemmer Webber's avatar
Christopher Lemmer Webber committed
Opening [[http://localhost:8001/]] should say the same, but with
82 83
"Bob's site".

84 85 86 87 88 89 90 91 92 93 94 95 96
What's with the =--other-stores= option?
If you'll notice, the two sites are pointing at each other's
read-only-cas endpoints.
This will be how they are able to find each others' content...
more on that later.

* Giving it a try

As said, this is a very very verrrrry paired down ActivityPub
Each server that's being run is single-user, and we haven't even
bothered requiring that you authenticate to be able to post content!

Christopher Lemmer Webber's avatar
Christopher Lemmer Webber committed
Returning to visiting [[http://localhost:8000/]] or [[http://localhost:8001/]]
98 99 100 101 102 103 104 105 106 107 108 109
in our browser.
What you should see is a form from which we can submit content
and a summary of the posts we most recently sent (our "outbox")
as well as the most recent posts we've received (our "inbox").

Let's try making a post from the form on [[http://localhost:8000/]].
Currently, we should see "Hey look... nothing!" in both the outbox
and inbox sections of the page, because we've neither sent or
received any content.

The *To:* field is who we want to send it to... well, this is
Alice's site, and Alice wants to talk to Bob, so let's put
http://localhost:8001/ in this field.[fn:wait-wheres-webfinger]
111 112 113 114 115 116 117 118 119 120 121 122
The box underneath it is the body of our post, so let's put
in a simple message, like "Hello, Bob!".
Now press the "Submit" button.

If everything went well underneath "Most recent post in your outbox"
the post "Hello, Bob!" (or whatever message it is that you sent).
But did Bob get it?
Navigate over to [[http://localhost:8001/]] and refresh the page in your
Yup, the post should be there in the inbox... looks like Bob got it!

123 124 125 126 127 128 129 130 131 132 133 134
[fn:wait-wheres-webfinger] Some users of the conventional fediverse
may be thinking, "Wait a minute!  I thought addressing in ActivityPub
used email-like addresses like [email protected] ... what's going
That style of addressing is called a [[][Webfinger]] based address, and
while it's possible to use in conjunction with ActivityPub, actual
ActivityPub addressing uses the [[][URIs]] of [[][actors]].
In this case, [[http://localhost:8001/]] /is/ Bob's actor URI.
Our server does an HTTP request asking for the activitystreams
representation of Bob at that address and gets back a JSON object
that points at Bob's inbox.
We can then use that to federate a message to Bob.

136 137 138 139 140 141
* What's going on?  

That's all great, but how is this different than any other ActivityPub
How do we even know that things were sent securely?