May the Signal be with you

May the Signal be with you

Signal Bot

The Signal is an open-source, end-to-end encrypted messaging app created by OpenWhisperSystems. It doesn't track its users and runs development and servers only on donated money. If you use it daily I suggest donating them a few bucks to express your support.

I already use it for several years and it's flawless so far. You can use it on Android, iOS, or Desktop via the Chromium app. Recently I decided to add a bot to my platform to notify me about new visitors or software bugs. You can find a dozen tutorials online on how to set up and write bots for Telegram and Messenger, but I failed to find one for Signal. It felt strange since Signal is more secure and seems perfect for sending sensitive data over the internet. Maybe the reason is Signal's popularity and hard setup compared to the popular messaging platform. After some research and playing with the terminal it worked just fine.

I called my bot K. BOT. Right now it's directly integrated into Devio Project API and notifies me about simple events. In the future, I want to decouple it from the backend as a separate service and add functionality to reply to my commands.

Setup Signal-CLI

Fortunately GitHub user AsamK already wrote a command-line interface for Signal. You can find a repo for this project here. Just download executable files from the releases page or compile from the source code. To use it we need Java on our system.

sudo apt-get install default-jre

Another requirement is the entropy daemon. I used haveged.

sudo apt-get install haveged

And that's all! Now we can register our number. I had a problem with receiving the verification code though. I think the reason is the difference between the number country code and server request was made from. On my local machine, it went without an error, because my PC network location and number country were the same. So I just registered my number on my PC as a master device.

./signal-cli -u $number_with_plus_and_country_code register

You will receive a verification code on your phone. Enter it:

./signal-cli -u $number_with_plus_and_country_code verify $received_code

Now you have your master device. You can use the same number as used on your phone, but I registered using the second number to save it in my contacts list as K.BOT and to decouple from my primary account. The phone number is pretty cheap. To link another device to an account use the link command from the target device, my website server in this case.

-n argument adds a name to a new device. It's displayed in your phone app under linked devices or through CLI command ./signal-cli listDevices. After running the link command you will receive a string containing URI "tsdevice:/263526...".

To add a linked device run on your master device addDevice command or generate a QR code from the string if you link to your phone account.

./signal-cli -u $NUMBER addDevice --uri 'tsdevice:/263526..'

You will receive a response Associated with: $NUMBER

To generate QR code:

sudo apt-get install qrencode
qrencode -o qr.png 'tsdevice:/263526..'

Listing devices and removing:

./signal-cli -u $NUMBER listDevices
./signal-cli -u $NUMBER removeDevice -d 2

Send message:

./signal-cli -u $NUMBER send -m 'Message' $NUMBER

I know after Telegram or Messenger there are a lot of steps to only send a message but if you came until here just admit it was worth it.

Integrating Signal-CLI with NodeJS

After these steps, we can use it in our applications by calling executable as a child process. I know there is a possibility to run signal-cli as a daemon described here. DBus service is a better approach, but first I want to find a way of automated linking and verifying to make K.BOT as independent service running in a Docker image. So let's just stick with forking for now. I placed signal-cli executable in the project_root/bin folder. Below is the code example in NodeJS. Just integrate into any part you want.

const { exec } = require('child_process');

exec(`echo 'First message from Signal Bot' | ./bin/signal-cli -u $YOUR_NUMBER send $RECEIPENT_NUMBER`, 
    (err, stdout, stderr) => {
    if (err) {
       console.log(err);
    }
    
    console.log(`stdout: ${stdout}`);
    console.log(`stderr: ${stderr}`);
});

I hope you run a NodeJS app from a different user than root. In this case, update your systemd service unit file to run by the same user. Otherwise, signal-cli will terminate with an error due to not finding its config folder.

To easily locate unit file location run

systemctl show $SERVICE_NAME | grep Path

And then modify user under service section:

[Service]
User=$YOUR_USERNAME
Group=$YOUR_USERNAME