npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

whatsdapp

v1.0.18

Published

WhatsDapp messaging-library applies the signal-protocol to the Dash Platform.

Readme

WhatsDapp

The core of WhatsDapp as a private messenger library should be an asynchronous, censorship- and ddos-resistant (availability) end-2-end-encrypted communication channel (integrity) with forward- and backward-secrecy (confidentiality).

This development corresponds to the Private Messenger Dapp project on Dash Incubator App.

Install

Just install via npm

npm i whatsdapp

or clone, compile via:

npm run dist

and add to your package.json-dependencies:

"whatsdapp": "<path-to>/whatsdapp-lib"

Usage

Storage

First you need a storage. The whatsdapp-lib does not come with one, since we want developers to use the storage that best fits their needs. Therefore we defined the interface KVStore in src/storage/StructuredStorage.ts as follows:

export type KVStore = {
  get(key: string): Promise<Uint8Array | null>,
  set(key: string, value: Uint8Array): void,
  del(key: string): void,
}

WhatsDapp comes with an encryption tidbit for storage. If you give a password it will AES-encrypt all local data so you can use an unencrypted local storage as well.

For a quick start you can use the LocalStorageClearDevPurposeOnly implementing the KVStore interface located in little_helper/local_storage_clear_dev.js.

Prepare Storage

On first use (and only on first use) you need to give your mnemonic. From then it stays in local storage. Therefore call static function:

static async prepareEmptyStorage(mnemonic: string, identityString: string | null, storageObj: KVStore, storagePassword?: string): Promise<void>;

e.g.

//identity will be generated later, use unencrypted storage
await WhatsDapp.prepareEmptyStorage(<MNEMONIC>, null, storageObj);

or:

//fixed identity, use password encrypted storage
await WhatsDapp.prepareEmptyStorage(<MNEMONIC>, <IDENTITY>, storageObj, '53cur3p455w0rd');

Create Messenger

To create a new WhatsDapp-object use the static factory function:

static async createWhatsDapp(storageObj: KVStore, storagePassword?: string): Promise<WhatsDapp>;

Set optional password according parameters set in prepareEmptyStorage:

const messenger = await WhatsDapp.createWhatsDapp(storageObj);

resp:

const messenger = await WhatsDapp.createWhatsDapp(storageObj, '53cur3p455w0rd');

If there is no identity deposited in storage a new one will be generated and automatically topped up.

After the initialization, generated Dash-Identity and WhatsDapp-Profile can be retrieved by getter-functions:

getCurrentIdentityString(): string
getCurrentProfile(): WhatsDappProfile | null

Connecting Events

There are currently three events emitted by WhatsDapp:

emit(ev: WhatsDappEvent.NewIncomingMessage, msg: WhatsDappMessage, interlocutor: string): boolean;
emit(ev: WhatsDappEvent.MessageSent, msg: WhatsDappMessage, interlocutor: string): boolean;
emit(ev: WhatsDappEvent.LowFunds, remainingDuffs: number): boolean;

The type WhatsDappMessage contains also drive info as $id, $createdAt and $updatedAt. So the MessageSent event tells the listenig application that the document was uploaded to the drive, at what point of time and with what id.

export type WhatsDappMessage = {
  //global 32B ID derived from document on drive
  id: string,
  //plaintext message content
  content: string,
  //timestamps
  createdAt: number,
  updatedAt: number,
  //Dash identity-IDs
  senderId: string, //same as ownerId
  recipientId: string,
  referenceToMessageId?: string,
  //marks new messages as unread
  read?: boolean,
}

While the LowFunds-event is fired if identity.getBalance() returns a value lower than MINIMUM_DUFFS_TO_SEND_MESSAGE= 100.

Polling

To receive new messages we use a polling. The default interval is currently 5 seconds.

There are three functions to control the polling:

startPolling(pollIntervalMilliseconds?: number): boolean;
setPollIntervall(pollIntervalMilliseconds: number): void;
stopPolling(): void;

Send Message

To send a message there is the following function.

sendMessage(recipientId: string, plaintext: string, referenceToMessageId?: string): Promise<boolean> 

The recipientId is a Dash-Identity string.

Minimal working Example

Bring above info together in one code snippet you can reuse.

const {WhatsDapp, WhatsDappEvent} = require('whatsdapp');
const MNEMONIC='<mnemonic goes here>';
const IDENTITY='<identity id goes here>'
// retrieve appdata path
const path = require('path');
const appDataPath = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share")
//set storage path for dev purpose in a directory depending on identity
const storagePath = path.join(appDataPath, 'whatsDappSessions/'+IDENTITY)

//use one arbitraty KVStore (copy js from little_helper/)
const LocalStorageClearDevPurposeOnly = require('./local_storage_clear_dev');
const storage = new LocalStorageClearDevPurposeOnly(storagePath)

const demoRun = async () => {
  //prepare first time. If userdata exist, this will throw an error and move on
  try {
    await WhatsDapp.prepareEmptyStorage(MNEMONIC, IDENTITY, storage, "53cur3p455w0rd");
  } catch (e) {
    console.log("Storage seems to be initiated already. Try to move on...")
  }

  //optionally an new identity and a generic profile will be created
  const messenger = await WhatsDapp.createWhatsDapp(storage, "53cur3p455w0rd");

  //define listener function
  const newMsgArrived=async (msg, interlocutor)=>{
    //DO SOMETHING
    console.log("New message arrived:",msg);
  }

  //connect event
  messenger.on(WhatsDappEvent.NewIncomingMessage, newMsgArrived)

  //start polling for new messages
  messenger.startPolling();
}
demoRun();

Loss of private Keys

If you loose your storage, remote profile is useless since we don't have the private keys to do anything. In this case run:

await messenger.discardOldProfileAndCreateNew()

This will remove the old profile from Drive, so nobody can retrieve invalid keys. After that a new keybundle will be created and a new profile uploaded, so you can start over again.

Net Prefs

WhatsDapp currently running on testnet synchronizing from mid 2021 as stated in src/dapi/dash_client/WhatsDappDashClient.ts:

const clientOpts = {
    network: 'testnet',
    wallet: {
      mnemonic: mnemonic,
      unsafeOptions: {
        skipSynchronizationBeforeHeight: 500000, // only sync from mid of 2021
      },
    },
    apps
  };

Data Contracts

There are two data contracts we use:

  • profile: WhatsDapp profiles conatining the signal keybundle and
  • message: Container for the encrypted messages

You can find them in src/dapi/dash_client/Contracts.ts

Pitfalls

  • You cannot write yourself ;)
    That's not provided by libsignal

  • Messages you receive are not validated yet, just decrypted and displayed. We need to think about XSS protection.

Used packages

  • Node implementation of signal library: https://github.com/ForstaLabs/libsignal-node
    • The official js signal-protocol needs crypto-feature of a browser and is not suitable for node.
  • Dash SDK

Why Signal?

Storing private messages in the blockchain forever is risky. For that we chose Signal protocol for its forward- and backward-secrecy. This way it’s not possible to find any previous or future keys from one compromised message-key. The basis is a double-key-ratchet that generates new keys for every message of each session. One ratchet performs extended triple Diffie-Hellman (X3DH) based on EC. There are 4 keypairs used for generating session key. This session key then runs through a hash-ratchet that generates new keys for each message. Each message will be encrypted AES-256 with kind of HMAC with an unique key. For further well-arranged protocol info see https://signal.org/docs/specifications/x3dh/ .

Links

  • The prototype of our reference implementation Dapp you'll find here: https://github.com/realKidDouglas/whatsdapp-ui-example This is outdated and we're currently on an Ionic app using our lib.
  • There will be several variants of obfuscation in future. Find details in our concept.

License

Licensed under the MIT License.

Note that the signal-protocol lib we currently use is licensed under the GPLv3.