-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0fd85a9
Showing
19 changed files
with
6,857 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"env": { | ||
"commonjs": true, | ||
"es6": true, | ||
"node": true | ||
}, | ||
"extends": [ | ||
"standard" | ||
], | ||
"globals": { | ||
"Atomics": "readonly", | ||
"SharedArrayBuffer": "readonly" | ||
}, | ||
"parserOptions": { | ||
"ecmaVersion": 2018 | ||
}, | ||
"rules": { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/node_modules/ | ||
/config.json | ||
/*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
dist: xenial | ||
|
||
language: node_js | ||
|
||
node_js: | ||
- node | ||
- lts/* | ||
|
||
before_script: | ||
- cp test/config.json config.json |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
# XMPP Bot | ||
|
||
[![license: AGPLv3](https://img.shields.io/badge/license-AGPLv3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) | ||
[![GitHub release](https://img.shields.io/github/release/nioc/xmpp-bot.svg)](https://github.com/nioc/xmpp-bot/releases/latest) | ||
[![Build Status](https://travis-ci.org/nioc/xmpp-bot.svg?branch=master)](https://travis-ci.org/nioc/xmpp-bot) | ||
|
||
XMPP Bot is a tiny little bot making the link between XMPP conversations and webhooks. | ||
|
||
User ⇄ XMPP client ⇄ XMPP Server ⇄ **XMPP Bot** ⇄ REST API | ||
|
||
## Key features | ||
|
||
- Call outgoing webhook on XMPP incoming messages from user chat or group chat (Multi-user chat "MUC"), | ||
|
||
- Send message templates (with values to apply to variables in that template) to user or room (MUC) on incoming authorized (basic or bearer) webhook. | ||
|
||
## Installation | ||
|
||
- Install [Node.js](https://nodejs.org/): | ||
```shell | ||
curl -sL https://deb.nodesource.com/setup_10.x | bash - | ||
apt-get install -y nodejs | ||
``` | ||
|
||
- Install npm: | ||
```shell | ||
npm install npm@latest -g | ||
``` | ||
|
||
- Clone repository: | ||
```shell | ||
git clone https://github.com/nioc/xmpp-bot.git /usr/local/bin/xmpp-bot/ | ||
``` | ||
|
||
- Install dependency: | ||
```shell | ||
cd /usr/local/bin/xmpp-bot/ && npm install --production | ||
``` | ||
|
||
- Create run user (optionnal): | ||
``` | ||
useradd -r -s /bin/false xmpp-bot | ||
chown xmpp-bot:xmpp-bot /usr/local/bin/xmpp-bot -R | ||
``` | ||
|
||
- Set [configuration](#configuration) in `config.json` (you can copy `config.json.dist`) | ||
|
||
- Add systemd service from [model](/docs/xmpp-bot.service): | ||
```shell | ||
cp docs/xmpp-bot.service /etc/systemd/system/xmpp-bot.service | ||
``` | ||
|
||
- Update systemd: | ||
```shell | ||
systemctl daemon-reload | ||
``` | ||
|
||
- Start service: | ||
```shell | ||
systemctl start xmpp-bot | ||
``` | ||
|
||
- Start service at boot: | ||
```shell | ||
systemctl enable xmpp-bot | ||
``` | ||
|
||
- Add fail2ban filter from [model](/docs/xmpp-bot.conf) (optionnal): | ||
```shell | ||
cp docs/xmpp-bot.conf /etc/fail2ban/filter.d/xmpp-bot.conf | ||
``` | ||
Add the jail (`/etc/fail2ban/jail.local`): | ||
```properties | ||
[xmpp-bot] | ||
enabled = true | ||
port = http,https | ||
filter = xmpp-bot | ||
logpath = /var/log/xmpp-bot/webhook.log | ||
maxretry = 3 | ||
bantime = 21600 ; 6 hours | ||
``` | ||
|
||
## Configuration | ||
|
||
### Logger | ||
|
||
- `level` log4js level (all < trace < debug < info < warn < error < fatal < mark < off) | ||
|
||
- `file`, `console` and `stdout` define log appenders (see [log4js doc](https://log4js-node.github.io/log4js-node/appenders.html)) | ||
|
||
### Webhooks listener | ||
|
||
- `path` and `port` define the listening endpoint | ||
|
||
- `ssl` define key and certificat location and port used for exposing in https, make sure that user of the process is allowed to read cert | ||
|
||
- `users` is an array of user/password for basic authentication | ||
|
||
- `accessLog` define the listener logger | ||
|
||
### XMPP Server | ||
|
||
- `host` and `port` define XMPP server | ||
- `jid` and `password` define XMPP "bot" user credentials | ||
- `rooms` list rooms (and optionnal password) where bot will listen | ||
|
||
### Incoming webhooks (list) | ||
|
||
- `path` is the webhook key:a POST request on this path will trigger corresponding `action` | ||
|
||
- `action` among enumeration: | ||
- `send_xmpp_message` will send message (`message` in request body) to `destination` (from request body) ; if `destination` is found in `config.xmppServer.rooms` array, message will send as a groupchat). Request exemple: | ||
|
||
```http | ||
POST /webhooks/w1 HTTP/1.1 | ||
Host: domain.ltd:8000 | ||
Content-Type: application/json | ||
Authorization: Basic dXNlcjE6cGFzczE= | ||
Content-Length: 70 | ||
{ | ||
"destination":"[email protected]", | ||
"message":"Hi, there something wrong." | ||
} | ||
``` | ||
|
||
- `send_xmpp_template` will send template with merged variables (using JMESPath) to `destination` (user or room if `sendToGroup` set to true) | ||
|
||
### XMPP hooks (list) | ||
|
||
- `room` is the XMPP hook key: an incoming groupchat (or chat) from this room (or this user) will trigger corresponding `action` | ||
|
||
- `action` among enumeration: | ||
- `outgoing_webhook` will execute a request to corresponding webhook with `args` as webhook code | ||
|
||
## Credits | ||
|
||
- **[Nioc](https://github.com/nioc/)** - _Initial work_ | ||
|
||
See also the list of [contributors](https://github.com/nioc/xmpp-bot/contributors) to this project. | ||
|
||
This project is powered by the following components: | ||
|
||
- [node-simple-xmpp](https://github.com/simple-xmpp/node-simple-xmpp) (MIT) | ||
- [express](https://github.com/expressjs/express) (MIT) | ||
- [body-parser](https://github.com/expressjs/body-parser) (MIT) | ||
- [express-basic-auth](https://github.com/LionC/express-basic-auth) (MIT) | ||
- [morgan](https://github.com/expressjs/morgan) (MIT) | ||
- [jmespath.js](https://github.com/jmespath/jmespath.js) (Apache-2.0) | ||
- [request](https://github.com/request/request) (Apache-2.0) | ||
- [node-cleanup](https://github.com/jtlapp/node-cleanup) (MIT) | ||
- [log4js-node](https://github.com/log4js-node/log4js-node) (Apache-2.0) | ||
|
||
## License | ||
|
||
This project is licensed under the GNU Affero General Public License v3.0 - see the [LICENSE](LICENSE.md) file for details |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* Configuration | ||
* | ||
* Handle configuration file | ||
* | ||
* @file This files defines the configuration | ||
* @author nioc | ||
* @since 1.0.0 | ||
* @license AGPL-3.0+ | ||
*/ | ||
|
||
module.exports = function Configuration (logger) { | ||
let config | ||
try { | ||
let data = require('fs').readFileSync('./config.json') | ||
config = JSON.parse(data) | ||
} catch (error) { | ||
logger.fatal(`Invalid configuration file: ${error.message}`) | ||
process.exit(99) | ||
} | ||
return { | ||
listener: { | ||
path: config.webhooksListener.path, | ||
port: config.webhooksListener.port, | ||
ssl: config.webhooksListener.ssl, | ||
log: config.webhooksListener.accessLog, | ||
users: config.webhooksListener.users.reduce((acc, user) => { | ||
acc[user.login] = user.password | ||
return acc | ||
}, {}) | ||
}, | ||
xmpp: config.xmppServer, | ||
logger: config.logger, | ||
getWebhookAction: (path) => { | ||
return config.incomingWebhooks.find((webhook) => { | ||
return (webhook.path === path) | ||
}) | ||
}, | ||
getOutgoingWebhook: (code) => { | ||
return config.outgoingWebhooks.find((webhook) => { | ||
return (webhook.code === code) | ||
}) | ||
}, | ||
getXmppHookAction: (room) => { | ||
return config.xmppHooks.find((xmppHook) => { | ||
return (xmppHook.room === room) | ||
}) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
{ | ||
"logger": { | ||
"level": "debug", | ||
"file": { | ||
"active": false, | ||
"pattern": "%d %p %m", | ||
"path": "/var/log/xmpp-bot/", | ||
"filename": "xmpp-bot.log" | ||
}, | ||
"console": { | ||
"active": false, | ||
"coloured": true | ||
}, | ||
"stdout": { | ||
"active": true, | ||
"pattern": "%p %m" | ||
} | ||
}, | ||
"webhooksListener": { | ||
"path": "/webhooks", | ||
"port": 8000, | ||
"ssl": { | ||
"port": 8001, | ||
"certPath": "/etc/ssl/certs/ssl-cert-snakeoil.pem", | ||
"keyPath": "/etc/ssl/private/ssl-cert-snakeoil.key" | ||
}, | ||
"users": [ | ||
{ | ||
"login": "login1", | ||
"password": "1pass" | ||
}, | ||
{ | ||
"login": "login2", | ||
"password": "2pass" | ||
} | ||
], | ||
"accessLog": { | ||
"active": true, | ||
"path": "/var/log/xmpp-bot/", | ||
"filename": "webhook.log" | ||
} | ||
}, | ||
"xmppServer": { | ||
"host": "domain-xmpp.ltd", | ||
"port": 5222, | ||
"jid": "[email protected]", | ||
"password": "botPass", | ||
"rooms": [ | ||
{ | ||
"id": "[email protected]", | ||
"password": null | ||
} | ||
] | ||
}, | ||
"incomingWebhooks": [ | ||
{ | ||
"path": "/webhooks/w1", | ||
"action": "send_xmpp_message" | ||
}, | ||
{ | ||
"path": "/webhooks/grafana", | ||
"action": "send_xmpp_template", | ||
"args": { | ||
"destination": "[email protected]", | ||
"sendToGroup": true | ||
}, | ||
"template": "${title}\r\n${message}\r\n${evalMatches[].metric}: ${evalMatches[].value}\r\n${imageUrl}" | ||
} | ||
], | ||
"xmppHooks": [ | ||
{ | ||
"room": "bot", | ||
"action": "outgoing_webhook", | ||
"args": ["w1"] | ||
}, | ||
{ | ||
"room": "[email protected]", | ||
"action": "outgoing_webhook", | ||
"args": ["w1"] | ||
} | ||
], | ||
"outgoingWebhooks": [ | ||
{ | ||
"code": "w1", | ||
"url": "https://domain.ltd:port/path/resource?parameter1=value1", | ||
"strictSSL": true, | ||
"contentType": "application/json", | ||
"authMethod": "basic", | ||
"user": "user3", | ||
"password": "3pass", | ||
"bearer": null | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Fail2Ban configuration file for webhook log | ||
|
||
# Option: failregex | ||
# Notes.: regex to match the Unauthorized log entrys in webhook log (defined in config.json: webhooksListener.accessLog). | ||
# Values: TEXT | ||
# | ||
[Definition] | ||
failregex=^<HOST> - .* ".*" 401 \d* ".*" ".*"$ | ||
|
||
# Option: ignoreregex | ||
# Notes.: regex to ignore. If this regex matches, the line is ignored. | ||
# Values: TEXT | ||
# | ||
ignoreregex = |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[Unit] | ||
Description=XMPP Bot | ||
Documentation=https://github.com/nioc/xmpp-bot | ||
After=network.target | ||
|
||
[Service] | ||
User=xmpp-bot | ||
WorkingDirectory=/usr/local/bin/xmpp-bot/ | ||
ExecStart=/usr/bin/node /usr/local/bin/xmpp-bot/server.js | ||
Restart=on-failure | ||
RestartSec=1000ms | ||
Environment=NODE_ENV=production | ||
SyslogIdentifier=xmpp-bot | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* Close handler | ||
* | ||
* Disconnect bot from XMPP server before app closes | ||
* | ||
* @file This files defines the closing handler | ||
* @author nioc | ||
* @since 1.0.0 | ||
* @license AGPL-3.0+ | ||
*/ | ||
|
||
module.exports = (logger, xmpp) => { | ||
let nodeCleanup = require('node-cleanup') | ||
nodeCleanup(function (exitCode, signal) { | ||
logger.warn(`Received ${exitCode}/${signal} (application is closing), disconnect from XMPP server`) | ||
try { | ||
xmpp.disconnect() | ||
} catch (error) { | ||
logger.error('Error during XMPP disconnection: ' + error.message) | ||
} | ||
logger.debug('Synchronize logs file') | ||
logger.shutdown() | ||
}) | ||
} |
Oops, something went wrong.