mirror of
https://github.com/nioc/xmpp-bot.git
synced 2024-12-04 22:23:36 +01:00
Version 2.2.0
Update dependencies (security fix) Fix lint errors
This commit is contained in:
parent
e7f8967176
commit
061725526b
11 changed files with 9952 additions and 4692 deletions
|
@ -15,7 +15,7 @@ module.exports = function Configuration (logger, configPath = null) {
|
||||||
configPath = './lib/config/config.json'
|
configPath = './lib/config/config.json'
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let data = require('fs').readFileSync(configPath)
|
const data = require('fs').readFileSync(configPath)
|
||||||
config = JSON.parse(data)
|
config = JSON.parse(data)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.fatal(`Invalid configuration file: ${error.message}, current directory is: ${process.cwd()}`)
|
logger.fatal(`Invalid configuration file: ${error.message}, current directory is: ${process.cwd()}`)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = (logger, xmpp) => {
|
module.exports = (logger, xmpp) => {
|
||||||
let nodeCleanup = require('node-cleanup')
|
const nodeCleanup = require('node-cleanup')
|
||||||
nodeCleanup(function (exitCode, signal) {
|
nodeCleanup(function (exitCode, signal) {
|
||||||
logger.warn(`Received ${exitCode}/${signal} (application is closing), disconnect from XMPP server`)
|
logger.warn(`Received ${exitCode}/${signal} (application is closing), disconnect from XMPP server`)
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -25,7 +25,7 @@ module.exports = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add appenders
|
// add appenders
|
||||||
let appenders = []
|
const appenders = []
|
||||||
if (config.file.active) {
|
if (config.file.active) {
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
if (!fs.existsSync(config.file.path)) {
|
if (!fs.existsSync(config.file.path)) {
|
||||||
|
@ -73,7 +73,7 @@ module.exports = () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
categories: {
|
categories: {
|
||||||
default: { appenders: appenders, level: 'info' }
|
default: { appenders, level: 'info' }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
logger = log4js.getLogger()
|
logger = log4js.getLogger()
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = async (logger, config, xmpp, user, destination, message, type, code) => {
|
module.exports = async (logger, config, xmpp, user, destination, message, type, code) => {
|
||||||
let webhook = config.getOutgoingWebhook(code)
|
const webhook = config.getOutgoingWebhook(code)
|
||||||
if (!webhook) {
|
if (!webhook) {
|
||||||
logger.warn(`There is no webhook with code "${code}"`)
|
logger.warn(`There is no webhook with code "${code}"`)
|
||||||
throw new Error(`There is no webhook with code "${code}"`)
|
throw new Error(`There is no webhook with code "${code}"`)
|
||||||
|
@ -18,7 +18,7 @@ module.exports = async (logger, config, xmpp, user, destination, message, type,
|
||||||
const { promisify } = require('util')
|
const { promisify } = require('util')
|
||||||
const request = promisify(require('request'))
|
const request = promisify(require('request'))
|
||||||
// request.debug = true
|
// request.debug = true
|
||||||
let options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: webhook.url,
|
url: webhook.url,
|
||||||
strictSSL: webhook.strictSSL
|
strictSSL: webhook.strictSSL
|
||||||
|
@ -50,7 +50,7 @@ module.exports = async (logger, config, xmpp, user, destination, message, type,
|
||||||
logger.trace('Content-type: application/x-www-form-urlencoded')
|
logger.trace('Content-type: application/x-www-form-urlencoded')
|
||||||
options.form = {
|
options.form = {
|
||||||
from: user,
|
from: user,
|
||||||
message: message,
|
message,
|
||||||
channel: destination
|
channel: destination
|
||||||
}
|
}
|
||||||
logger.trace('Outgoing webhook request:', options.form)
|
logger.trace('Outgoing webhook request:', options.form)
|
||||||
|
@ -59,7 +59,7 @@ module.exports = async (logger, config, xmpp, user, destination, message, type,
|
||||||
logger.trace('Content-type: application/json')
|
logger.trace('Content-type: application/json')
|
||||||
options.json = {
|
options.json = {
|
||||||
from: user,
|
from: user,
|
||||||
message: message,
|
message,
|
||||||
channel: destination
|
channel: destination
|
||||||
}
|
}
|
||||||
logger.trace('Outgoing webhook request:', options.json)
|
logger.trace('Outgoing webhook request:', options.json)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
// create default logger
|
// create default logger
|
||||||
let logger = require('./logger')()
|
const logger = require('./logger')()
|
||||||
|
|
||||||
// get configuration
|
// get configuration
|
||||||
let config = require('./config')(logger)
|
const config = require('./config')(logger)
|
||||||
|
|
||||||
// update logger with configuration
|
// update logger with configuration
|
||||||
logger.updateConfig(config.logger)
|
logger.updateConfig(config.logger)
|
||||||
|
|
|
@ -18,7 +18,7 @@ module.exports = (logger, config, xmpp) => {
|
||||||
const port = config.listener.port || 8000
|
const port = config.listener.port || 8000
|
||||||
const portSsl = config.listener.ssl.port || 8001
|
const portSsl = config.listener.ssl.port || 8001
|
||||||
|
|
||||||
var webhook = express()
|
const webhook = express()
|
||||||
|
|
||||||
// handle connection from proxy (get IP in 'X-Forwarded-For' header)
|
// handle connection from proxy (get IP in 'X-Forwarded-For' header)
|
||||||
webhook.set('trust proxy', true)
|
webhook.set('trust proxy', true)
|
||||||
|
@ -57,7 +57,7 @@ module.exports = (logger, config, xmpp) => {
|
||||||
// handle post request
|
// handle post request
|
||||||
webhook.post(config.listener.path + '/*', (req, res) => {
|
webhook.post(config.listener.path + '/*', (req, res) => {
|
||||||
logger.info(`Incoming webhook from ${req.auth.user}`)
|
logger.info(`Incoming webhook from ${req.auth.user}`)
|
||||||
let webhook = config.getWebhookAction(req.path)
|
const webhook = config.getWebhookAction(req.path)
|
||||||
if (!webhook) {
|
if (!webhook) {
|
||||||
logger.error(`Webhook received: ${req.path}, not found`)
|
logger.error(`Webhook received: ${req.path}, not found`)
|
||||||
return res.status(404).send('Webhook not found')
|
return res.status(404).send('Webhook not found')
|
||||||
|
@ -65,21 +65,20 @@ module.exports = (logger, config, xmpp) => {
|
||||||
logger.debug(`Webhook received: ${webhook.path}, start action: ${webhook.action}`)
|
logger.debug(`Webhook received: ${webhook.path}, start action: ${webhook.action}`)
|
||||||
logger.trace(req.body)
|
logger.trace(req.body)
|
||||||
switch (webhook.action) {
|
switch (webhook.action) {
|
||||||
case 'send_xmpp_message':
|
case 'send_xmpp_message': {
|
||||||
|
|
||||||
// get destination
|
// get destination
|
||||||
if ('destination' in req.body === false) {
|
if ('destination' in req.body === false) {
|
||||||
logger.error('Destination not found')
|
logger.error('Destination not found')
|
||||||
return res.status(400).send('Destination not found')
|
return res.status(400).send('Destination not found')
|
||||||
}
|
}
|
||||||
let destination = req.body.destination
|
const destination = req.body.destination
|
||||||
|
|
||||||
// get message
|
// get message
|
||||||
if ('message' in req.body === false) {
|
if ('message' in req.body === false) {
|
||||||
logger.error('Message not found')
|
logger.error('Message not found')
|
||||||
return res.status(400).send('Message not found')
|
return res.status(400).send('Message not found')
|
||||||
}
|
}
|
||||||
let message = req.body.message
|
const message = req.body.message
|
||||||
|
|
||||||
// check if destination is a group chat
|
// check if destination is a group chat
|
||||||
const type = config.xmpp.rooms.some((room) => room.id === destination) ? 'groupchat' : 'chat'
|
const type = config.xmpp.rooms.some((room) => room.id === destination) ? 'groupchat' : 'chat'
|
||||||
|
@ -88,17 +87,17 @@ module.exports = (logger, config, xmpp) => {
|
||||||
logger.trace(`Send to ${destination} (group:${type}) following message :\r\n${message}`)
|
logger.trace(`Send to ${destination} (group:${type}) following message :\r\n${message}`)
|
||||||
xmpp.send(destination, message, type)
|
xmpp.send(destination, message, type)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return res.status(200).send({ 'status': 'ok', destination })
|
return res.status(200).send({ status: 'ok', destination })
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
return res.status(500).send('Could not send message')
|
return res.status(500).send('Could not send message')
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
}
|
||||||
|
|
||||||
case 'send_xmpp_template':
|
case 'send_xmpp_template': {
|
||||||
|
|
||||||
// bind data in template
|
// bind data in template
|
||||||
let msg = webhook.template.replace(/\$\{(.+?)\}/g, (match, $1) => {
|
const msg = webhook.template.replace(/\$\{(.+?)\}/g, (match, $1) => {
|
||||||
return jmespath.search(req.body, $1) || ''
|
return jmespath.search(req.body, $1) || ''
|
||||||
})
|
})
|
||||||
logger.trace(`Message:\r\n${msg}`)
|
logger.trace(`Message:\r\n${msg}`)
|
||||||
|
@ -114,6 +113,7 @@ module.exports = (logger, config, xmpp) => {
|
||||||
return res.status(500).send('Could not send message')
|
return res.status(500).send('Could not send message')
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return res.status(204).send()
|
return res.status(204).send()
|
||||||
|
@ -133,10 +133,10 @@ module.exports = (logger, config, xmpp) => {
|
||||||
// get IP v4 addresses and prepare endpoints for output
|
// get IP v4 addresses and prepare endpoints for output
|
||||||
let addresses = []
|
let addresses = []
|
||||||
const networkInterfaces = require('os').networkInterfaces()
|
const networkInterfaces = require('os').networkInterfaces()
|
||||||
for (let ifaceName in networkInterfaces) {
|
for (const ifaceName in networkInterfaces) {
|
||||||
addresses = addresses.concat(networkInterfaces[ifaceName].reduce((add, iface) => {
|
addresses = addresses.concat(networkInterfaces[ifaceName].reduce((add, iface) => {
|
||||||
if (iface['family'] === 'IPv4') {
|
if (iface.family === 'IPv4') {
|
||||||
add.push(iface['address'])
|
add.push(iface.address)
|
||||||
}
|
}
|
||||||
return add
|
return add
|
||||||
}, []))
|
}, []))
|
||||||
|
@ -166,7 +166,7 @@ module.exports = (logger, config, xmpp) => {
|
||||||
try {
|
try {
|
||||||
fs.accessSync(config.listener.ssl.certPath, fs.constants.R_OK)
|
fs.accessSync(config.listener.ssl.certPath, fs.constants.R_OK)
|
||||||
logger.debug('Can read certificate')
|
logger.debug('Can read certificate')
|
||||||
let credentials = {
|
const credentials = {
|
||||||
key: fs.readFileSync(config.listener.ssl.keyPath),
|
key: fs.readFileSync(config.listener.ssl.keyPath),
|
||||||
cert: fs.readFileSync(config.listener.ssl.certPath)
|
cert: fs.readFileSync(config.listener.ssl.certPath)
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ module.exports = (logger, config) => {
|
||||||
})
|
})
|
||||||
// join rooms
|
// join rooms
|
||||||
config.xmpp.rooms.forEach(function (room) {
|
config.xmpp.rooms.forEach(function (room) {
|
||||||
let occupantJid = room.id + '/' + address.local
|
const occupantJid = room.id + '/' + address.local
|
||||||
logger.debug(`Join room: ${room.id} ('${occupantJid}')`)
|
logger.debug(`Join room: ${room.id} ('${occupantJid}')`)
|
||||||
const stanza = xml(
|
const stanza = xml(
|
||||||
'presence', {
|
'presence', {
|
||||||
|
@ -78,16 +78,16 @@ module.exports = (logger, config) => {
|
||||||
// not a message, do nothing
|
// not a message, do nothing
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let type = stanza.attrs.type
|
const type = stanza.attrs.type
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'chat':
|
case 'chat':
|
||||||
case 'groupchat':
|
case 'groupchat': {
|
||||||
let body = stanza.getChild('body')
|
const body = stanza.getChild('body')
|
||||||
if (!body) {
|
if (!body) {
|
||||||
// empty body, do nothing
|
// empty body, do nothing
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let fromJid = jid(stanza.attrs.from)
|
const fromJid = jid(stanza.attrs.from)
|
||||||
// for chat, "to" and "replyTo" must be something like "user@domain.ltd", "from" is local part "user"
|
// for chat, "to" and "replyTo" must be something like "user@domain.ltd", "from" is local part "user"
|
||||||
let to = this.jid.bare()
|
let to = this.jid.bare()
|
||||||
let from = fromJid.local
|
let from = fromJid.local
|
||||||
|
@ -102,15 +102,15 @@ module.exports = (logger, config) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let message = body.text()
|
const message = body.text()
|
||||||
// handle message delivery receipts for chat
|
// handle message delivery receipts for chat
|
||||||
if (type === 'chat') {
|
if (type === 'chat') {
|
||||||
let request = stanza.getChild('request')
|
const request = stanza.getChild('request')
|
||||||
if (request &&
|
if (request &&
|
||||||
request.attrs.xmlns &&
|
request.attrs.xmlns &&
|
||||||
request.attrs.xmlns === 'urn:xmpp:receipts' &&
|
request.attrs.xmlns === 'urn:xmpp:receipts' &&
|
||||||
stanza.attrs.id) {
|
stanza.attrs.id) {
|
||||||
logger.debug(`Message delivery receipt is requested and will be processed`)
|
logger.debug('Message delivery receipt is requested and will be processed')
|
||||||
const receiptStanza = xml(
|
const receiptStanza = xml(
|
||||||
'message', {
|
'message', {
|
||||||
to: fromJid
|
to: fromJid
|
||||||
|
@ -127,7 +127,7 @@ module.exports = (logger, config) => {
|
||||||
}
|
}
|
||||||
logger.info(`Incoming ${type} message from ${from} (${fromJid.toString()}) to ${to}`)
|
logger.info(`Incoming ${type} message from ${from} (${fromJid.toString()}) to ${to}`)
|
||||||
logger.debug(`Message: "${message.replace(/\n|\r/g, ' ')}"`)
|
logger.debug(`Message: "${message.replace(/\n|\r/g, ' ')}"`)
|
||||||
let xmppHook = config.getXmppHookAction(to.toString())
|
const xmppHook = config.getXmppHookAction(to.toString())
|
||||||
if (!xmppHook) {
|
if (!xmppHook) {
|
||||||
logger.error(`There is no action for incoming ${type} message to: "${to}"`)
|
logger.error(`There is no action for incoming ${type} message to: "${to}"`)
|
||||||
return
|
return
|
||||||
|
@ -144,6 +144,7 @@ module.exports = (logger, config) => {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
14523
package-lock.json
generated
14523
package-lock.json
generated
File diff suppressed because it is too large
Load diff
45
package.json
45
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "xmpp-bot",
|
"name": "xmpp-bot",
|
||||||
"version": "2.1.0",
|
"version": "2.2.0",
|
||||||
"description": "XMPP bot",
|
"description": "XMPP bot",
|
||||||
"main": "./lib/server.js",
|
"main": "./lib/server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
"coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls"
|
"coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10.0.0"
|
"node": ">= 12.4.0"
|
||||||
},
|
},
|
||||||
"author": "nioc <dev@nioc.eu>",
|
"author": "nioc <dev@nioc.eu>",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
|
@ -22,30 +22,29 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@xmpp/client": "^0.8.0",
|
"@xmpp/client": "^0.13.1",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.20.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.18.1",
|
||||||
"express-basic-auth": "^1.2.0",
|
"express-basic-auth": "^1.2.1",
|
||||||
"jmespath": "^0.15.0",
|
"jmespath": "^0.16.0",
|
||||||
"log4js": "^4.5.1",
|
"log4js": "^6.6.1",
|
||||||
"morgan": "^1.9.1",
|
"morgan": "^1.10.0",
|
||||||
"node-cleanup": "^2.1.2",
|
"node-cleanup": "^2.1.2",
|
||||||
"request": "^2.88.0"
|
"request": "^2.88.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.3.6",
|
||||||
"coveralls": "^3.0.8",
|
"coveralls": "^3.0.9",
|
||||||
"eslint": "^6.7.0",
|
"eslint": "^8.24.0",
|
||||||
"eslint-config-standard": "^12.0.0",
|
"eslint-config-standard": "^17.0.0",
|
||||||
"eslint-plugin-import": "^2.18.2",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-node": "^9.2.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^6.0.1",
|
||||||
"eslint-plugin-standard": "^4.0.1",
|
"mocha": "^10.0.0",
|
||||||
"mocha": "^6.2.2",
|
|
||||||
"mock-require": "^3.0.3",
|
"mock-require": "^3.0.3",
|
||||||
"nock": "^11.7.0",
|
"nock": "^13.2.9",
|
||||||
"nodemon": "^1.19.4",
|
"nodemon": "^2.0.20",
|
||||||
"nyc": "^14.1.1",
|
"nyc": "^15.1.0",
|
||||||
"sinon": "^7.5.0"
|
"sinon": "^14.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
/* eslint-disable handle-callback-err */
|
/* eslint-disable n/handle-callback-err */
|
||||||
|
/* eslint-disable prefer-regex-literals */
|
||||||
process.env.NODE_ENV = 'production'
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
require('chai').should()
|
require('chai').should()
|
||||||
|
|
|
@ -74,12 +74,12 @@ describe('XMPP component', () => {
|
||||||
it('Should connect to XMPP server and join rooms when application start', (done) => {
|
it('Should connect to XMPP server and join rooms when application start', (done) => {
|
||||||
sinon.assert.called(xmppSendStub)
|
sinon.assert.called(xmppSendStub)
|
||||||
// 1 "send" call for presence and n "send" calls for joining rooms
|
// 1 "send" call for presence and n "send" calls for joining rooms
|
||||||
let roomsLength = config.xmpp.rooms.length
|
const roomsLength = config.xmpp.rooms.length
|
||||||
sinon.assert.callCount(xmppSendStub, roomsLength + 1)
|
sinon.assert.callCount(xmppSendStub, roomsLength + 1)
|
||||||
for (let index = 1; index < roomsLength + 1; index++) {
|
for (let index = 1; index < roomsLength + 1; index++) {
|
||||||
const args = xmppSendStub.args[index]
|
const args = xmppSendStub.args[index]
|
||||||
args.should.have.length(1)
|
args.should.have.length(1)
|
||||||
let occupantJid = config.xmpp.rooms[index - 1].id + '/' + 'bot'
|
const occupantJid = config.xmpp.rooms[index - 1].id + '/' + 'bot'
|
||||||
const stanza = xml(
|
const stanza = xml(
|
||||||
'presence', {
|
'presence', {
|
||||||
to: occupantJid
|
to: occupantJid
|
||||||
|
@ -353,7 +353,7 @@ describe('XMPP component', () => {
|
||||||
})
|
})
|
||||||
it('Should call xmpp/client.send() with valid stanza', (done) => {
|
it('Should call xmpp/client.send() with valid stanza', (done) => {
|
||||||
sinon.assert.calledOnce(xmppSendStub)
|
sinon.assert.calledOnce(xmppSendStub)
|
||||||
let stanza = xml(
|
const stanza = xml(
|
||||||
'message', {
|
'message', {
|
||||||
to: 'someone@domain-xmpp.ltd',
|
to: 'someone@domain-xmpp.ltd',
|
||||||
type: 'chat'
|
type: 'chat'
|
||||||
|
|
Loading…
Reference in a new issue