Whisper Tutorial using Embark
Go to file
Richard Ramos 386bfe2a29
Update README.md
2018-11-26 09:25:00 -04:00
app Adding TODO sections for private messaging 2018-11-25 08:54:38 -04:00
config Initial version 2018-11-20 11:42:02 -04:00
contracts Initial version 2018-11-20 11:42:02 -04:00
test Initial version 2018-11-20 11:42:02 -04:00
.gitignore Initial version 2018-11-20 11:42:02 -04:00
README.md Update README.md 2018-11-26 09:25:00 -04:00
embark.json Initial version 2018-11-20 11:42:02 -04:00
package-lock.json Initial version 2018-11-20 11:42:02 -04:00
package.json Initial version 2018-11-20 11:42:02 -04:00

README.md

Using Whisper with Embark

Intro

In this tutorial we'll learn how to use Ethereum's Whisper protocol and Embark, creating a chat application even simpler than the one we built in our previous tutorial. Before cloning this repository, please make sure you have the latest version of Embark installed. Follow the instructions at https://embark.status.im/docs/installation.html.

Setup

Once you have Embark installed, we are ready to begin coding! Execute these commands in a terminal window to clone the repository and install its dependencies

git clone https://github.com/status-im/whisper-embark-tutorial.git
cd whisper-embark-tutorial
npm install

First run

Now lets run our website quickly to see what Embark will do for us.

embark run

You should see the Embark console and it's components.

  • Contracts - the top left shows which contracts are deployed and their address.
  • Modules loaded and running - the top right shows the status of the loaded modules running (or not running) in Embark.
  • Log - the middle shows log output.
  • Console - on the bottom row there is a console that will let us interact with web3 and ipfs (try it out by typing help to see available commands).

Youll notice from the logs and from the modules that Embark has started various processes, and webpacked our website for us. Let's take a tour of the barebones dApp. The website has several features that are not yet hooked up to whisper, but lets take a look around at the website anyway. Launch http://localhost:8000 in your browser.

Coding our dApp

The file ./app/js/index.js is full of TODOs that we need to work with. You'll notice that using Embark, the amount of boilerplate code is reduced, and you will only have to deal with you dApp's business logic.

// TODO: Generate a symmetric key

In our chat application, public messages are sent to a channel represented by a shared symmetric key whose "password" is just the channel we'll be using and listening to. "Public" messages are messages encrypted using this known symmetric key and filtered using topics, since they are not addressed to anyone in particular and are received by anyone that's listening in a specific channel.

// Generate a symmetric key
const channelSymKey = await web3.shh.generateSymKeyFromPassword(DEFAULT_CHANNEL);

// TODO: Obtain public key

The users need to know what is their contact code, which is represented by a public key.. Embark already generated a keypair for us, so let's use web3.shh.getPublicKey using Embark's keypair:

// Obtain public key
const pubKey = await web3.shh.getPublicKey(EmbarkJS.Messages.currentMessages.sig);

// Send message via whisper

In this example, Embark generates a keypair for us. We'll only need to implement code for sending and receiving messages. This is done by using EmbarkJS.Messages.sendMessage(options). Unlike using web3.utils.shh directly, With Embark it is not necessary to hex-encode the data. You can send plain text as we do here:

// Send message via whisper
EmbarkJS.Messages.sendMessage({
    symKeyID: channelSymKey,
    topic: DEFAULT_CHANNEL, 
    data: message
});

sendMessage accepts an option object that can contain the following attributes:

  • symKeyID, if specified, it will send the message to this symmetric key id. Otherwise, it will send to a random symmetric key generated by Embark (Either symKeyID or pubKey must be present. Can not be both.).
  • pubKey is the public key for message encryption. (Used when sending asymmetric messages). Either symKeyID or pubKey must be present. Can not be both.
  • usePrivateKey is a boolean that indicates if you're going to use an private key for signing the message, or use Embark's autogenerated random keypair.
  • privateKeyID is required if you set usePrivateKey to true. Here you send the ID of the signing key.
  • ttl is the time to live in seconds. Default value is 100
  • powTime is the maximal time in seconds to be spent on proof of work. Default value is 3
  • powTarget is the minimal PoW target required for this message. Default value is 0.5
  • topic, optional when using private keys. Can be an array of strings, or a string that contains the topic for the messages. Will be automatically encoded to a 4 bytes hex string(s).

// TODO: Subscribe to public messages

To receive the messages sent via Whisper, Embark offers a EmbarkJS.Messages.listenTo(options) that helps us obtain messages based in the options used to filter the messages. Let's implement this functionality, calling the function addMessage(data, time) each time a message is received:

// Subscribe to public messages
EmbarkJS.Messages.listenTo({
    topic: [DEFAULT_CHANNEL],
    symKeyID: channelSymKey
  }, (error, message) => {
    if(error){
        alert("Error during subscription");
        return;
    }

    const {data, time} = message;

    addMessage(data, time);
});

Just like with sendMessage, listenTo also accepts an option object, with the following attributes:

  • symKeyID, if specified, it will listen to messages sent to this symmetric key id. Otherwise, it will use the random symmetric key generated by Embark (Either symKeyID or pubKey must be present. Can not be both.).
  • usePrivateKey is a boolean that indicates that you wish to listen to messages sent to your keypair.
  • privateKeyID is required if you set usePrivateKey to true. Here you send the ID of the signing key.
  • topic, optional when using private keys. Can be an array of strings, or a string that contains the topic for the messages. Will be automatically encoded to a 4 bytes hex string(s).
  • minPow is the minimal PoW requirement for incoming messages.

After adding this code, open two instances of the chat application and write a message. You'll see how it gets displayed in both windows

// TODO: Send private message

We are going to send private messages with a command similar to IRC: /msg 0xcontact_public_key message. In the section were we need to implement this code, we've already assigned the contact's public key to the contactCode variable, and the body of the message in messageContent.

Sending a message to a specific asymmetric public key is similar to sending it to a symmetric key. The difference is that you need to specify the pubKey attribute instead of symKeyId.

// Send private message
EmbarkJS.Messages.sendMessage({
    pubKey: contactCode,
    topic: DEFAULT_CHANNEL,
    data: messageContent
});

// TODO: Subscribe to private messages

Similar to receiving messages from the public channel, we'll need to create a subscription to receive private messages. We use as a privateKeyID our keyPair in order for the subscription to receive messages that were sent to our public key.

EmbarkJS.Messages.listenTo({
    usePrivateKey: true,
    privateKeyID: EmbarkJS.Messages.currentMessages.sig
}, (error, message) => { 
    if(error){
        alert("Error during subscription");
        return;
    }

    const {data, time} = message; 
    addMessage(data, time);
});

Once you add this code, go ahead and open three instances of our chat application, write a public message in one window, and in the other, copy the public key and send a private message to the account that created the first message. The first and second window will be able to see the message, but the third window will only have received the public message. (Remember the format for sending a private message: /msg 0xcontact_public_key message )

At the moment we aren't displaying in the chat area who originated the message. We'll add this functionality in the coming release of Embark, and update this tutorial accordingly.

Final thoughts

Building a dApp that uses Whisper with Embark is something amazingly easy. You could easily extend this tutorial dapp to support private messages, just like we did in our previous tutorial for Getting started with Whisper.

Something that you must consider is that even through Embark lets you use Whisper in your dApps, it does not mean that anyone will be able to use it when browsing your dApp. This is due to this protocol not being enabled in most providers. You'll need to connect to a node that supports this feature (i.e. geth with the --shh flag).

Things will change in the future once Whisper gains more traction. Let's work together in building dApps that communicate between each other via Whisper!