386bfe2a29 | ||
---|---|---|
app | ||
config | ||
contracts | ||
test | ||
.gitignore | ||
README.md | ||
embark.json | ||
package-lock.json | ||
package.json |
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 let’s 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
andipfs
(try it out by typinghelp
to see available commands).
You’ll 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 let’s 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 TODO
s 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 (EithersymKeyID
orpubKey
must be present. Can not be both.).pubKey
is the public key for message encryption. (Used when sending asymmetric messages). EithersymKeyID
orpubKey
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 setusePrivateKey
totrue
. Here you send the ID of the signing key.ttl
is the time to live in seconds. Default value is100
powTime
is the maximal time in seconds to be spent on proof of work. Default value is3
powTarget
is the minimal PoW target required for this message. Default value is0.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 (EithersymKeyID
orpubKey
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 setusePrivateKey
totrue
. 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!