Commit 051da96b authored by ar's avatar ar
Browse files

Merge branch 'develop' into 'master'

New release 0.0.5

See merge request !4
parents 3c3d7890 059c3273
# Changelog for "Hello Matrix" Bot
## Changes in v0.0.5 (2017-08-13)
- Updated dependencies for newer versions of matrix-js-sdk (so you need to run "npm install" again!)
- Bugfixes such that the bot doesn't crash if the homeserver isn't available for short periods of time
- Bugfix for a bug that meant the bot didn't recognize messages send to itself if the user-id parameter
wasn't written exactly the way expected by the server; now we use the server-provided user-id instead
- New "senddm.js" module that provides a private webhook to send direct messages from the bot to any
Matrix user (if you want to use it, you need to update your config file, see example config)
## Changes in v0.0.4 (2017-06-03)
- Quick fix pinning matrix-js-sdk to 0.7.4 until we have figured out how best to ugprade to 0.7.10 (with libolm removed)
- Quick fix pinning matrix-js-sdk to 0.7.4 until we have figured out how best to upgrade to 0.7.10 (with libolm removed)
- Small bugfixes
......@@ -11,6 +11,7 @@ You can either use the “Hello Matrix” bot running on our server (see below f
- Tracerouting a given IP
- Weather from [OpenWeatherMap](
- Defining arbitrary web hooks that, when triggered, send a configurable message to your room
- Using a specific webhook to send direct messages (private 1:1 chats) to Matrix users
- Providing WHOIS information on a domain or IP address
- Adding tasks and monitoring progress on [Wunderlist]( lists
......@@ -30,11 +31,15 @@ The advantage of using our instance is of course that you do not have to install
If the points above have made you interested in running your own Hello Matrix bot, you are welcome to do so - either for your private use or as a public bot that others can talk to as well (note that at the moment you cannot really restrict usage of the bot).
You can clone our gitlab repository:
git clone
Afterwards, you need to obtain the Node packages (such as matrix-js-sdk) required to run Hello Matrix. Make sure you have installed the latest version of [Node](, which should come with the npm package manager. Then change into the hello-matrix-bot directory and run:
npm install
Now you are ready to set-up the configuration for your Hello Matrix bot. Copy the `matrix-bot-config.example.js` file in the main directory as `matrix-bot-config.js` in the same directory. Afterwards you need to edit these file to provide the user credentials which Hello Matrix should use to authenticate with the home server you want to use and also to provide a variety of API keys required for the different services. The section on Hello Matrix configuration below explains the different configuration options.
......@@ -42,13 +47,17 @@ If you do not need some of these services and thus do not want to go through the
Some modules use SQLite databases to persist data such as authentication tokens or which data Hello Matrix needs to monitor. To create empty databases for all current modules, you need to ensure that the `sqlite3` utility is installed and in your path and then run the following shell script from the main Hello Matrix path:
Hello Matrix comes with a web server to support web hooks and various authentication schemes. By default, the server listens on port 3001 on `localhost` only. The idea is that you can put a reverse proxy (such as nginx or the awesome [Caddy]( in front of Hello Matrix to run multiple services on the same host and also to provide TLS encryption (which you should!). Please refer to the documentation of your favorite reverse proxy for details on how to proxy a URL of your choice to `http://localhost:3001/`.
Finally, you can launch your very own Hello Matrix bot using the start command:
npm start
### Hello Matrix Configuration Keys
......@@ -65,6 +74,8 @@ The file `matrix-bot-config.js` knows the following configuration options for th
- `kanban` module, `myServer`: This module integrates with [Kanban Tool]( As it uses the integrated web server of Hello Matrix for authentication purposes, you need to provide the URL your reverse proxy forwards to `http://localhost:3001/matrix-bot/kanban/` (see above). For example, for our public instance this is set as `""`.
- `kanban` module, `sqliteDatabase`: The Kanban module stores persistent information (which boards to monitor and authentication credentials) in an SQLite database. This parameter specifies the path to the database, relative to the main folder, which you should have created before using the `` shell script (see above). The shell script by default creates `kanban.sqlite`.
- `senddm` module: You need to provide a random `secretKey`. With this key, you can compute an HMAC hash that authorizes you to send messages to arbitrary Matrix users using the `/matrix-bot/senddm/send` web endpoint (to use `senddm`, you need to pass a full MXID as `recipient`, a text for your message as `message` and the hex-encoded SHA512 HMAC for the concatenation of `recipient` and `message` as `hmac`; you can pass these three parameters either as a `GET` query string or via `POST` as JSON data).
- `twitter` module: Please ignore the configuration options there for now. The Twitter module is not yet operational.
- `weather` module: This module uses the OpenWeatherMap API. You can get a free API key from their website and need to paste this key into the `weatherApiKey` configuration option.
......@@ -78,6 +89,7 @@ The file `matrix-bot-config.js` knows the following configuration options for th
- `wunderlist` module, `wunderlistClientSecret` option: The [Wunderlist API]( requires a client secret that can be obtained by registering for free on their developer portal.
- `wunderlist` module, `sqliteDatabase` option: The Wunderlist module stores persistent information (authentication credentials) in an SQLite database. This parameter specifies the path to the database, relative to the main folder, which you should have created before using the `` shell script (see above). The shell script by default creates `wunderlist.sqlite`.
### Bitmessage configuration
Integration with Bitmessage requires a running [PyBitmessage]( instance on the server where the bot is running. You need to enable the API as explained in Bitmessage’s [API Reference](
......@@ -97,9 +109,15 @@ Hello Matrix generally explains himself. Just invite him (`@hello-matrix:matrix.
If you want to know what commands Hello Matrix understands, you can ask by calling for help:
If you have identified an interesting feature set, you can get more help into how to use this specific functionality by calling help with the name of the feature:
!help feature
Hello Matrix will respond with an explanation of all the commands to be performed for the Wunderlist integration.
......@@ -113,11 +131,12 @@ At the moment, the following is unsupported by this bot:
## Roadmap
There are a lot of cool integrations that would be interesting to add, but for the moment the following items are high on the agenda and will be implemented "as time permits" in this order:
1. "Send DM" webhook for admins (provides a simple webhook to send DMs to arbitrary Matrix users)
2. Zapier integration
3. Support for providing statistics on room discussion, similar to what [pigs]( does for IRC chats
1. Zapier integration
2. Gitlab integration
3. Support for providing statistics on room discussion, similar to what [pisg]( does for IRC chats
4. Simple reminder / alarm clock functionality
## Questions?
If you have any questions, feel free to join [\]( for answers. If any questions come up frequently, we will add them here.
......@@ -14,6 +14,9 @@ helpModules['dice'] = dice.getHelp;
var kanban = require("./kanban.js");
helpModules['kanban'] = kanban.getHelp;
var senddm = require("./senddm.js");
helpModules['senddm'] = senddm.getHelp;
var traceroute = require("./traceroute.js");
helpModules['traceroute'] = traceroute.getHelp;
"senddm" module
Sets up a webhook that allows to trigger the bot to send a direct message (in a 1:1 chat)
to a specified matrix user (MXID). Can be used e.g. for providing login URLs.
// Configuration
var config = require("../matrix-bot-config.js").senddm;
// Required modules
var jsSHA = require("jssha");
// Process these web requests.
exports.webRequest = function(client, path, query, res) {
console.log('SendDM: Received web request for ' + path);
// We don't do anything if we dont have a secret key set (or it is the default).
if(config === undefined || config.secretKey === undefined || config.secretKey === '' ||
config.secretKey === '<insert secret key for HMAC to authorise DMs here>') {
console.log('WARNING: Someone has tried to access the senddm module but no secret key is set!');
console.log('WARNING: We have cancelled the request.');
res.send('This function is disabled.');
if(path === 'send') {
// Parse data provided...
var sendData = (res.req.method === 'POST' ? res.req.body : query);
// Valid MXID? (From Matrix spec and
var validMxidRe = /^@([\x21-\x7E]+):(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
// Valid data provided?
if(sendData.recipient === undefined || sendData.message === undefined || sendData.hmac === undefined || !validMxidRe.test(sendData.recipient)) {
res.send('Invalid data.');
} else {
// Compute HMAC.
var shaObj = new jsSHA("SHA-512", "TEXT");
shaObj.setHMACKey(config.secretKey, "TEXT");
var hmac = shaObj.getHMAC("HEX");
if(sendData.hmac !== hmac) {
res.send('Invalid key.');
} else {
// Send direct message...
client.sendDM(sendData.recipient, sendData.message);
// Send "OK." response.
} else {
console.log('senddm: Received unknown command.');
res.send('Unknown command.');
// What to display in the help function.
exports.getHelp = function(details) {
return 'This is a module that is only used by the bot operator. It allows the operator to send direct messages to specified Matrix users.';
......@@ -3,7 +3,9 @@ var config = require('./matrix-bot-config.js').base;
// Load required modules
var q = require('q');
var sdk = require('matrix-js-sdk');
// We use the matrix SDK that needs to be set by the requiring module
exports.matrixSDK = {};
// We use a matrix client that needs to be set by the requiring module
exports.matrixClient = {};
......@@ -110,7 +112,7 @@ var getDMRoom = function(userId) {
// What is the power level required to invite others in this room?
var power_levels_event = room.getLiveTimeline().getState(sdk.EventTimeline.FORWARDS).getStateEvents('', '');
var power_levels_event = room.getLiveTimeline().getState(exports.matrixSDK.EventTimeline.FORWARDS).getStateEvents('', '');
console.log('Received power_levels_event for room ' + room.roomId + '.');
......@@ -30,6 +30,12 @@ exports.kanban = {
// For senddm module
exports.senddm = {
'secretKey': '<insert secret key for HMAC to authorise DMs here>'
// For twitter module
exports.twitter = {
consumer_key: '<insert Twitter consumer key here>',
......@@ -17,10 +17,19 @@ if (typeof localStorage === "undefined" || localStorage === null) {
var localStorage = new LocalStorage(config.localStorage);
// matrix-js-sdk
// var Olm = require("olm");
var sdk = require("matrix-js-sdk");
// Loading libolm
try {
console.log('Loading olm...');
global.Olm = require('olm');
} catch (err) {
console.log('ERROR: We couldn\'t load libolm: ' + err);
console.log('ERROR: libolm is required as Hello Matrix Bot uses end-to-end encryption.');
// Loading Matrix SDK
var sdk = require("matrix-js-sdk");
client.matrixSDK = sdk;
......@@ -32,6 +41,7 @@ botModules['calculate'] = require("./bot-modules/calculate.js");
botModules['dice'] = require('./bot-modules/dice.js');
botModules['help'] = require("./bot-modules/help.js");
botModules['kanban'] = require("./bot-modules/kanban.js");
botModules['senddm'] = require("./bot-modules/senddm.js");
botModules['traceroute'] = require("./bot-modules/traceroute.js");
botModules['weather'] = require("./bot-modules/weather.js");
botModules['webhook'] = require("./bot-modules/webhook.js");
......@@ -83,10 +93,9 @@ loginPromise.then(function() {
deviceId: localStorage.getItem('deviceId')
// Automatically join rooms when invited
client.matrixClient.on("RoomMember.membership", function(event, member) {
if (member.membership === "invite" && member.userId === config.botUserId) {
if (member.membership === "invite" && member.userId === localStorage.getItem('userId')) {
console.log("Received invite for %s from %s. Auto-joining...", member.roomId, event.getSender());
......@@ -107,7 +116,7 @@ loginPromise.then(function() {
console.log('An error occured while trying to reject / process room invites:' + JSON.stringify(err));
} else if(member.userId === config.botUserId) {
} else if(member.userId === localStorage.getItem('userId')) {
console.log("Received UNPROCESSED membership event of type %s for myself in room %s from %s.", member.membership, member.roomId, event.getSender());
// TODO: Enable processing of other events (kicks, bans, etc.)
......@@ -120,7 +129,7 @@ loginPromise.then(function() {
// Listen for messages starting with a bang (!)
client.matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline) {
if (toStartOfTimeline || event.getSender() === config.botUserId) {
if (toStartOfTimeline || event.getSender() === localStorage.getItem('userId')) {
return; // don't use stale results or own data
if (event.getType() !== "") {
......@@ -189,7 +198,13 @@ loginPromise.then(function() {
// We use the default initialSyncLimit of 8 as it is also used for subsequent requests
// However, we ignore messages older than 3 minutes (see above) to avoid replying to stale requests
try {
} catch(err) {
console.log('WARNING: Caught matrixClient error:');
console.log('WARNING: You might need to restart the bot.');
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment