"use strict";
/**
* ExpressService
* @namespace ExpressService
* @description Manages web hooks
* @example See ["hooks/examples/webhook_spammer.js"]{@link hooks/examples.webhook_spammer} for a web hook definition
*/
const hooks = require('./hooks');
const monitor = require("./monitor");
const config = require('./config');
const logger = require('./logger');
const _ = require('underscore');
const s = require("underscore.string");
_.mixin(s.exports());
const Promise = require('promise');
const express = require("express");
const bodyParser = require('body-parser');
/**
* @property {TelegramService} api Link to TelegramService
* @private
* @memberof ExpressService
*/
let api = null;
/**
* @property {Express} app Link to Express app
* @private
* @memberof ExpressService
*/
let app = null;
/**
* @property {Boolean} initialized If initialized
* @private
* @memberof ExpressService
*/
let initialized = false;
/**
* @function authorized
* @description Check if call is authorized
* @static
* @param {Request} req Web request
* @param {Response} res Web response
* @memberof ExpressService
* @private
* @returns {Boolean}
*/
const authorized = function (req, res) {
if (config.get("express:auth") && config.get("express:auth_token_name")) {
if (req.get(config.get("express:auth_token_name")) == config.get("express:auth")) {
return true;
} else {
res.sendStatus(403);
return false;
}
} else {
return true;
}
};
/**
* @class
* @classdesc Manages web hooks
*/
const ExpressService = {
/**
* @function list_methods
* @description Return an help page listing all mounted hooks
* @static
* @param {Request} req Web request
* @param {Response} res Web response
* @memberof ExpressService
* @public
*/
list_methods: function (req, res) {
if (authorized(req, res)) {
let out_hooks = _.groupBy(_.sortBy(_.sortBy(hooks.get_hooks(), "name"), "namespace"), "namespace");
res.render('_sys/list', {
_: _,
config: config,
header: require("../assets/ansi-header-html.js"),
hooks: out_hooks,
package_def: require("../package.json")
});
}
},
/**
* @function init
* @description Initialize web hooks manager
* @static
* @param {TelegramService} tapi Link to Telegram service
* @memberof ExpressService
* @public
* @returns {Promise}
*/
init: function (tapi) {
return new Promise(function (resolve, reject) {
api = tapi;
hooks.load().then(function () {
if (config.get("express:active") == false) {
initialized = true;
return resolve(api);
}
if (app) {
app.close();
}
const path = require('path');
const dir = path.resolve(__dirname, '..');
let express_hooks = hooks.get_hooks("has_web_hook", "route_path");
app = express();
app.set('view engine', 'jade');
app.set('views', path.resolve(dir, 'views'));
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
app.use(express.static('public'));
let port = (process.env.PORT || config.get("express:port") || 3000);
app.listen(port, function (error) {
if (error) {
reject(error);
} else {
logger.log(`WebServer is listening on port ${port}`);
app.get('/', ExpressService.list_methods);
app.get('/tid', function (req, res) {
if (authorized(req, res)) {
res.json(api.get_hook_id() || false);
}
});
app.post('/tid', function (req, res) {
if (authorized(req, res)) {
api.set_hook_id(req.body("id"));
res.json((api.get_hook_id() || false) == req.body("id"));
}
});
app.get('/hooked', function (req, res) {
if (authorized(req, res)) {
res.json(api.is_hooked());
}
});
app.all('/start/:hook', function (req, res) {
if (authorized(req, res)) {
monitor.start(req.param("hook")).then(res.send).catch(res.send);
}
});
app.all('/stop/:hook', function (req, res) {
if (authorized(req, res)) {
monitor.stop(req.param("hook")).then(res.send).catch(res.send);
}
});
app.all('/restart/:hook', function (req, res) {
if (authorized(req, res)) {
monitor.restart(req.param("hook")).then(res.send).catch(res.send);
}
});
for (let route_path in express_hooks) {
if (express_hooks.hasOwnProperty(route_path)) {
let hook = express_hooks[route_path];
let router = _.bind(hook.route, hook);
let method = (hook.method || "all").toLowerCase();
let filter_params = [];
if (_.isArray(hook.params)) {
for (let i = 0; i < hook.params.length; i++) {
filter_params = _.union([], filter_params, [hook.params[i].name, hook.params[i].alias])
}
}
filter_params = _.compact(filter_params);
app[method]("/" + route_path, function (req, res) {
if (authorized(req, res)) {
let params = _.pick(_.extend({}, req.params, req.query, req.body), filter_params);
router(params, api, req, res).then(function (content) {
if (_.isString(hook.response)) {
res.send(hook.response);
} else if (content !== null) {
res.json(content);
}
}).catch(function (error) {
if (_.isString(hook.error)) {
res.status(500).send(hook.error);
} else {
res.status(500).send(error.message || error);
}
}).finally(function () {
res.end();
});
}
});
logger.notify(`Registered "${hook.full_name}" web hook at /${route_path} route`);
}
}
initialized = true;
resolve({
api: api,
hooks: hooks
});
}
});
}).catch(reject);
});
}
};
module.exports = ExpressService;