providing client-side encryption so unhosted open-source webs can break monopolies
Pull request Compare This branch is 3658 commits behind remotestorage:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



  • First of all: This code is only for demonstration and not safe to run in production. Only run it in a local development environment, never on a public IP or production server.

  • Please submit any unhosted apps you create, big or small, to the Hacky Holidays competition. Even if a small app, that maybe only serves to say 'hello world' backwards, may not win, it's nice to create a rich showcase, and it helps us understand the issues and hurdles involved in developing unhosted web apps. The deadline is 1 January 2011, details are on

  • We only wrote the easy bits ourselves. ;) For the important bits, we used Tom Wu's JavaScript Big Numbers library, Fritz Schneider's Rijndael Reference Implementation, and Schwarz Lanzenreiter's SHA1 script. We also learned things from reading rsa-sign.js and pidCrypt.

Setting up local server for unhosted web app and storage node

This assumes you will run both the clientside and serverside on your devbox localhost, and that you have a working webserver installed there, with php and mysql (if you don't have these, there should be plenty web documentation on how to easily install them on your operating system. On ubuntu:

sudo apt-get install php5-mysql mysql-server

should install php, apache and mysql.

Download the tar file from:

Open a shell, and extract the tarball. All the example paths and commands are for Ubuntu Linux, please derive your own OS's equivalents for Mac and Windows. Search the web where necessary, and improve this README file if you find any significant (platform-specific) information. So on Ubuntu, you can extract the tarball with:

cd Downloads; tar -xzvf michiel-unhosted-unhosted-*.tar.gz

You should see a list of all the files that were extracted. move the whole extracted dir to a subdirectory you call unhosted/, under your webroot, for instance /var/www/unhosted/. You probably need sudo to write in your webroot:

sudo mkdir /var/www/unhosted ; sudo mv michiel-unhosted-unhosted-*/* /var/www/unhosted/
  • check that http://localhost/unhosted/cloudside/unhosted.php displays:

    This url is an unhosted JSON storage, and only works over CORS-AJAX. Please access using the unhosted JS library (

  • point and to in /etc/hosts:

$ sudo gedit /etc/hosts

check that also displays:

This url is an unhosted JSON storage, and only works over CORS-AJAX. Please
access using the unhosted JS library ([](

Configuring your unhosted storage node:

Now edit /var/www/unhosted/cloudside/config.php and put in some mysql credentials in there. If the user you specify has permissions to create databases, it will create the database name you specify on first access, along with all its tables.

Setting up the wappblog example:

Browse to and click the leftmost button, Create js files for wappblog example. You will see two short .js files show up. ATTENTION: this will take several seconds in mozilla, during which the browser will block. If anyone volunteers, you are more than welcome to make this asynchronous, and with a loading bar or some other indication that the wait is expected and the browser is not hung.

Cut-and-paste the .js files that are generated, and save them /var/www/unhosted/wappside/examples/wappblog/[indicated path].

Open up:

Make sure you have FireBug or WireShark or equivalent open during the following steps, so you can see that is really only serving static content, which (apart from serving as a hello world for you to build upon) is the point of this example. All dynamic content is handled by the end-user-supplied, over the Unhosted-JSON protocol. That way, the app author doesn't incur costs when people use his altruistically shared open source app.

Type some text and hit the 'unhost this blogpost!' button. This should send a SET command inside a POST from the browser to (which is running on your localhost, but in the real world, static file hosting would be provided by the web app author or some channel that carries his app, and would be independent from the web app author, and contain the unhosted account of the end user. That way, unhosted web apps are very scalable, and no matter how many people are using the app you wrote at the same time, you'll only have to host the static source code.

If you think your AJAX call reached the unhosted server, now have your firebug still open, and browse to:

In firebug you should see it post a GET command to, then the js will check the PubSign signature, decrypt the content, and assign the blog post text to the <div> tag in bootloader.html.

Now open up bootloader.html and editor.html, and have a look at the source code. They only have 4 lines of code each. So hopefully you can see how easy it is to program unhosted websites using the "unhosted.get(user, key)" and "unhosted.set(user, key, value)" commands.

Behind the scenes, the text you typed was first encrypted with 's', using symmetric Rijndael. This was formed into the UJ/0.1 GET-command, which plays the role here of the "Pub", the publication in the pub/sub-model. Then this was signed with 'd', using RSA, to create "the PubSign that Signs the Pub". Writecaps 'w' were used to access unhosted account 'r@c'. The unhosted server allows CORS via the Access-Control-Allow-Origin header, and the HTTP OPTIONS command, but the HTTP referer of the POST is used to identify the app, so that browsers can enforce same-origin policies. On the subscriber end, upon retrieval of the blogpost from 'r@c' (again with CORS-AJAX and same-origin separation via the referer), the PubSign is checked against public key 'n', then the same Rijndael 's' is used for decryption, and the result is displayed. However, all of this is done inside the unhosted JS library, and you as the app developer only have to make sure you fill in all the correct bits you got from genkey, call unhosted.set and unhosted.get, and it just works!

The Wappmail example:

The second example is wappmail. it's a bit cumbersome to try it out, because it requires you to create multiple users, cut-and-paste their addresses and passwords into the interface, log in as one, send an email, log in as the other, check your email, etcetera. In part the example is useful for showing how cumbersome public keys are. But it is also a working example of the "unhosted.send(from, to, key, body)" and "unhosted.receive(user, key)" commands. Unlike with the first get/set-based example, the symmetric encryption key 's' is not used here. If you send someone (r@c:n) a message, you need to know his public key n. Anybody can send messages to anyone, provided you include a valid PubSign (signifying you are the real sender), and you encode it against their public key. Since you signed your message with your own r@c:n, they can reply easily by clicking the sender address in their inbox.

Whereas the first (wappblog) example is pub/sub-based, this one, wappmail, is (obviously) message-based. A lot of things you might possibly want to do with unhosted would be more naturally message-based than pub/sub-based, so I'm curious what people come up with to build on top of this. If you open up wappmail/bootloader.html, you see there are only 4 functions there, of about 8 lines each. The receive command has an optional boolean parameter 'andDelete'. If you edit the php, you could maybe add an 'andWait' parameter, so the receiver can sit with an open connection, waiting for messages to arrive. That would give you a real-time message-based paradigm. I'm curious to see what people will hack together in the Hacky Holidays competition!

The Wappbook example:

The third example is a bit advanced; it's called wappbook because it's an addressbook (no reference to Facebook, obviously;), and demonstrates the StarSign pki. All it does is establish trust through a behind-the-scenes fabric-based pki. All there is to see is that after your friend has logged in, in your addressbook he will change from 'pending' to 'ok'. The algorithms behind that it runs before it gets to put 'ok' there are, I think, the best part of the unhosted library. But it's so new that even I don't really understand how it works, and it's mainly there for people who are interested in the geeky details. Unless you're into that sort of thing, it's probably better to start by expanding either the pub/sub- or message-based examples.


  • In editor.html you can see how to import a publication channel and write a (key, value)-pair to it:

    unhosted.importPub(pub, nick);
    unhosted.set(nick, key, value);
  • In bootloader.html you can see how to import a subscription channel and read a (key, value)-pair from it:

    unhosted.importSub(sub, nick);
    var value=unhosted.get(nick, key);
  • It should be easy and fun to start working from there and to create your own application. Good luck!

  • if you have any improvements to make this demo more user-friendly, or anything else you wish to share with us, please contribute! We're at Google Groups. We're a friendly bunch, and your contribution is more than welcome. And as I said earlier, please hack together an unhosted app these holidays, even if it's just to get a feel for it. Hacky Holidays, everybody!