Blockstagram: A privacy first photo sharing app based on Blockstack

Stefan Adolf
t14g
Published in
10 min readMar 6, 2018

When my colleague Robert and I arrived around 6pm on Friday at the “Blockchain Hackathon” event at betahaus in Kreuzberg it was already freezing cold and we were pretty tired from our workweek at Turbine Kreuzberg. ‘Grabbing some beers and pizza and have some good afterwork talks’ was all we expected from that event. Then I remembered the phone call with my old friend Dyrk from Hamburg that I had to dismiss far too early the other day because I wanted to prepare some IOTA idea for the hackathon. I thought: what if the idea that Dyrk asked me to help him with was exactly the idea that we could work on during the weekend?

Dyrk has two little children, his friends are distributed evenly across the country and his family is living at the countryside. He would love to share images of his beloved ones with family and friends but for known reasons he’s very uncomfortable with the idea uploading his images to cloud servers where Google or Facebook can index and reuse them.

There are a gazillion of options for Dyrk to solve his problem: he could choose Own/Nextcloud, a “cloud”-enabled harddisk, maybe the NAS feature of a Fritzbox or simply send the images using e-mail. Nowadays he could even use a distributed filesystem like IPFS or freenet — if he only knew how to use it (not to mention that his mother must be able to live with his decision as well).

We decided to approach Dyrk’s problem using the technology that our host blockstack had to offer, so I stood up for the first “Blockstagram” pitch and put it down on paper. It looked like this:

After pitching Dyrk’s idea quite a lot of people approached me and we discussed it in depth. We had quite a good time that Friday night developing a first conceptual idea; we broke our heads over possible issues, lost ourselves in philosophical discussions about sense and nonsense of blockchain technology and some beers later we finally concluded: “boy, we think we can do this”. In the end 8 people stayed for longer and we’ve formed Team Blockstagram out of them. Let me quickly introduce us to you:

Team Blockstagram

from left to right:

Robert K: the backend mastermind that took care of the “friend” concept and the storage access. Fixed all the issues no one else understood.

Timo W: the experienced blockchain dev with a ReactJS preference who glued together API calls, figured out how to talk to the Gaia hub correctly, handled many merge conflicts and revised most of the code that we were delivering.

Stefan A (that’s me :D ): initialized our repo & the Webpack tooling, setup the frontend using Bulma.io, refactored parts of the friend list and finally pulled out to take care of the slides.

Nathan vB: colors, frames, borders and layout. Learning React from scratch and giving everyone a great time!

Markus G: the PSD, voice recognition and font guru that made our CD happen and inspired our logo and the final presentation.

Peter S: taking care of the frontend idea, providing images and helpful insights when testing the frontend.

Artur P: the best copilot for Timo that he could wish for, hinting him to technology and solutions, telling him about missing brackets and having a 2nd eye on all the PRs

Ben P (Not in the image, had to catch his flight back to London ;) ): the ReactJS lover that provided us buttons, ordering mechanisms and a lot of code love for the PRs.

Let’s get that baby started

The hacking started on Saturday, 9am and what followed were 30 hours of concentrated work. If you want to read along you can clone, fork or just open our github repository.

It seemed to be a good idea to use Blockstack since they’re offering a great ecosystem to get started with decentralized apps that can run locally and share nothing with third parties. In detail they got:

  • Identity: users create an identity using the blockstack application (runs locally or as unconnected web app). It will create a Bitcoin wallet for you that you can use to prove your stakes and manifest your name. At its core Blockstack serves as a kind of decentralized identity provider so you’re not depending on Facebook, Google or an email address to prove your identity.
  • Storage: while not being mandatory the so called Gaia storage hub is Blockstack’s component that allows you to store any data in a virtual filesystem that’s not openly visible to the world.
  • Wallet: (not final yet) you for sure can guess what that one is good for :)

Blockstack applications are pure web applications — the only “backend” that they depend on is a web server to be served from, and since we’re using webpack to build all our assets we have just used its development server for local testing. A simple npm run watch gets you up and running.

Our code concept: Italian food

You might have guessed, that when coding on a hackathon you will end up with a lot of spaghetti code. That’s totally fine and in our project you find lots of it as well. Since we are going to refactor everything for the sake of niceness thereby destroying all the pastrami goodness we saved our current codestate in a couple of gists that we’d like to present here to you. They’re mostly excerpts of our monolithic index.jsx page that contains the heart and the guts of our application as of the hackathon’s last day.

Before digging deep into the code let’s have a look at the frontend and how it looked like in the end of the hackathon. Note that everything found its place, starting with a Sign in / Sign out button, a switchable picture lane, a rather uncomfortable “upload” area and a little input field that allows you to add new friends just by typing their blockstack id (cpiet.id is a great starting point :) )

Blockstragram’s state at the end of the hackathon

(NOTE: THESE CODE SAMPLES ARE EXCERPTS. DON’T CODE LIKE THIS! THIS CODE WON’T WORK AS IS. THIS CODE MAINLY SHOULD DEMONSTRATE HOW TO USE BLOCKSTACK’S APIS)

This is how a really simple SigninButton can look like in Blockstack. Notice that authentication mostly boils down to call the redirectToSignIn API method and waiting the API to respond in the main view:

Our main component is handling the signin process as soon as it’s loaded (see: index.jsx:componentDidMount -> setupUser): what follows is a bunch of asynchronous function calls that load or create data our application associates with an user id. Since gaia is not to be considered a “database” all data has to be stored as JSON files.

Let me explain more parts of our index.jsx spaghetti monolith:

  • as soon as the application starts up we’re getting profile data from the blockstack api. The user profile data contains information about the identity and the user’s public key.
  • calls to blockstack.getFile are hitting the distributed or cloud file system that a user chose to store his data. Upon component mount we’re loading quite a bit of it: index.json contains an index of all binary images a user has uploaded, subscriber.json represents the “friend list” of the user and keys/*.json keep a list of all the public keys of the user’s friends.
  • the readSingleSubscribersImages method in contrast illustrates the so called “multi player” storage feature. In gaia it’s absolutely possible to read another user’s storage from the same application namespace. That implies that you better don’t use it for keeping secrets. However this behaviour comes in very handy for us: for our first implementation we could simply add another user’s id to our subscribers list and pull the binary image data from their storage.

At this point we’re already pretty close to the Instagram use case: we can upload our own images and “follow” other users by simply downloading their image index files and successively pull the binary data from their associated storage area.

Encryption and image access control

An important piece is still missing now: encryption and access control. We solved it by reusing the private key that comes as a mandatory part of each blockstack id.

Upon login the setupKey method generates a new random symmetric AES key that we will use later to encrypt the image index of the user. The getPublicKeyFromPrivate is a function exported by the blockstack library (not by the API!). We’re using it to create an user’s public key and store that — visible to the world — in a key.json associated with that user (remember that this file is visible to all users within the same application namespace). We’re then using the public key to encrypt the formerly created symmetric AES key and store that cipher under keys/<username>.

From that point on we’re using the AES key to encrypt the user’s image index. This means that everyone still may access the index file but only users that also have access to the AES key will be able to decipher the index file and thereby locate and download the (unencrypted) binary images from gaia.

Granting access

Imagine that Dyrk wants to provide access to his image data to his wife. As long as she is a user of the Blockstagram app he can simply load her public key by using her id and encrypt his current AES secret with it. He stores the resulting cipher in a file named after her id.

His wife in return can simply retrieve that file by requesting it from her husband’s gaia storage (she knows that it’s named after her). She is able to decipher it using the private key of her blockstack id thereby getting access to Dyrk’s current AES key. She then downloads Dyrk’s encrypted index file from his storage, decrypts that one with the acquired AES key and finally is able to locate and download the real binary data.

Revoking access

(We also invented a solution for this scenario but our source code is so bad that we decided to keep it for us for the time being, so please get along with the theoretical description first)

When Dyrk wants to revoke access for a certain person (lets call him Stefan to stay in the example) he can generate a new random AES secret and reencrypt his image index using that one. None of his subscribers will now be able to read his data since the old AES secret cannot decrypt the image locations anymore.

At the same time Dyrk regenerates all the files that are ciphered with the public keys of his friends with the exception of Stefan. Now everyone can load their respective file again, decipher it and gain access of the new AES key. Everyone besides Stefan, obviously.

The presentation

It moves, looks nice and works in every browser. What could you expect more from a presentation tool? I guess the audience liked it as well :)

The application

We’re deploying the application through a free netlify instance currently. It’s redeployed upon every push onto master. Netlify is an amazingly simple tool to get static web applications up and running in no time, including continuous deployment, thanks for that, Netlify :)

(you need the blockstack application running on your machine to sign into the app)

And then we made it to the top.

You might’ve noticed that we made it to the first place on the Berlin Blockstack hackathon with this proof of concept. We still are quite surprised about the social response that we received so far (thank you so much for sharing, Patrick Stanley!)

But what’s even more important is that we made Dyrk very happy — even though the app is not working perfectly right now he understood and very much appreciated the work that we did for him. Sorry for the German but this is part of his response to me (yes, Dyrk is a real person):

What’s next for Team Blockstagram?

We’re currently consolidating our ideas and exchange ourselves on a private slack channel. Some of us met today night at the IOTA developers meetup and had another beer. We don’t want to raise to high expectations but I think all members of our team are highly motivated to get this thing running at least in beta mode on the Blockstack app store. So stay tuned for updates. You can follow us on our brand new Twitter account.

I personally would like to thank you all good people for making this one happen. I love attending hackathons but I love attending hackathons that you finish as a winner even more.

--

--

Stefan Adolf
t14g
Writer for

molecule.to | getsplice.io. EthOnline finalist. React, Typescript, web3, Solidity, Gatsby, Ionic, Fastify, Mongo. Dev#7079