diff --git a/README.md b/README.md index e32f026..26d015b 100644 --- a/README.md +++ b/README.md @@ -135,9 +135,11 @@ Emits `message` when a message arrives. | [options.polling.autoStart] | Boolean | true | Start polling immediately | | [options.webHook] | Boolean | Object | false | Set true to enable WebHook or set options | | [options.webHook.port] | Number | 8443 | Port to bind to | -| [options.webHook.key] | String | | Path to file with PEM private key for webHook server. (Read synchronously!) | -| [options.webHook.cert] | String | | Path to file with PEM certificate (public) for webHook server. (Read synchronously!) | +| [options.webHook.key] | String | | Path to file with PEM private key for webHook server. The file is read **synchronously**! | +| [options.webHook.cert] | String | | Path to file with PEM certificate (public) for webHook server. The file is read **synchronously**! | +| [options.webHook.pfx] | String | | Path to file with PFX private key and certificate chain for webHook server. The file is read **synchronously**! | | [options.webHook.autoOpen] | Boolean | true | Open webHook immediately | +| [options.webHook.https] | Object | | Options to be passed to `https.createServer()`. Note that `options.webHook.key`, `options.webHook.cert` and `options.webHook.pfx`, if provided, will be used to override `key`, `cert` and `pfx` in this object, respectively. See https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener for more information. | | [options.onlyFirstMatch] | Boolean | false | Set to true to stop after first match. Otherwise, all regexps are executed | | [options.request] | Object | | Options which will be added for all requests to telegram api. See https://github.com/request/request#requestoptions-callback for more information. | | [options.baseApiUrl] | String | https://api.telegram.org | API Base URl; useful for proxying and testing | diff --git a/src/telegram.js b/src/telegram.js index 9f7674d..6476251 100644 --- a/src/telegram.js +++ b/src/telegram.js @@ -47,9 +47,17 @@ class TelegramBot extends EventEmitter { * @param {Boolean} [options.polling.autoStart=true] Start polling immediately * @param {Boolean|Object} [options.webHook=false] Set true to enable WebHook or set options * @param {Number} [options.webHook.port=8443] Port to bind to - * @param {String} [options.webHook.key] Path to file with PEM private key for webHook server. (Read synchronously!) - * @param {String} [options.webHook.cert] Path to file with PEM certificate (public) for webHook server. (Read synchronously!) + * @param {String} [options.webHook.key] Path to file with PEM private key for webHook server. + * The file is read **synchronously**! + * @param {String} [options.webHook.cert] Path to file with PEM certificate (public) for webHook server. + * The file is read **synchronously**! + * @param {String} [options.webHook.pfx] Path to file with PFX private key and certificate chain for webHook server. + * The file is read **synchronously**! * @param {Boolean} [options.webHook.autoOpen=true] Open webHook immediately + * @param {Object} [options.webHook.https] Options to be passed to `https.createServer()`. + * Note that `options.webHook.key`, `options.webHook.cert` and `options.webHook.pfx`, if provided, will be + * used to override `key`, `cert` and `pfx` in this object, respectively. + * See https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener for more information. * @param {Boolean} [options.onlyFirstMatch=false] Set to true to stop after first match. Otherwise, all regexps are executed * @param {Object} [options.request] Options which will be added for all requests to telegram api. * See https://github.com/request/request#requestoptions-callback for more information. diff --git a/src/telegramWebHook.js b/src/telegramWebHook.js index 710c77f..05bd1c2 100644 --- a/src/telegramWebHook.js +++ b/src/telegramWebHook.js @@ -24,19 +24,25 @@ class TelegramBotWebHook { this.token = token; this.options = options; this.options.port = options.port || 8443; + this.options.https = options.https || {}; this.callback = callback; this._regex = new RegExp(this.token); this._webServer = null; this._requestListener = this._requestListener.bind(this); this._parseBody = this._parseBody.bind(this); - if (options.key && options.cert) { // HTTPS Server - debug('HTTPS WebHook enabled'); - const opts = { - key: fs.readFileSync(options.key), - cert: fs.readFileSync(options.cert) - }; - this._webServer = https.createServer(opts, this._requestListener); + if (options.key && options.cert) { + debug('HTTPS WebHook enabled (by key/cert)'); + this.options.https.key = fs.readFileSync(options.key); + this.options.https.cert = fs.readFileSync(options.cert); + this._webServer = https.createServer(this.options.https, this._requestListener); + } else if (options.pfx) { + debug('HTTPS WebHook enabled (by pfx)'); + this.options.https.pfx = fs.readFileSync(options.pfx); + this._webServer = https.createServer(this.options.https, this._requestListener); + } else if (options.https) { + debug('HTTPS WebHook enabled by (https)'); + this._webServer = https.createServer(this.options.https, this._requestListener); } else { debug('HTTP WebHook enabled'); this._webServer = http.createServer(this._requestListener); diff --git a/test/telegram.js b/test/telegram.js index 3364448..a2b18b4 100644 --- a/test/telegram.js +++ b/test/telegram.js @@ -1,4 +1,4 @@ -const Telegram = require('../lib/telegram'); +const TelegramBot = require('../lib/telegram'); const Promise = require('bluebird'); const request = require('request-promise'); const assert = require('assert'); @@ -8,7 +8,9 @@ const path = require('path'); const is = require('is'); const utils = require('./utils'); +// Allows self-signed certificates to be used in our tests process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + const TOKEN = process.env.TEST_TELEGRAM_TOKEN; if (!TOKEN) { throw new Error('Bot token not provided'); @@ -19,12 +21,15 @@ const USERID = process.env.TEST_USER_ID || 777000; const GROUPID = process.env.TEST_GROUP_ID || -1001075450562; const GAME_SHORT_NAME = process.env.TEST_GAME_SHORT_NAME || 'medusalab_test'; const timeout = 60 * 1000; -const staticPort = 8091; -const pollingPort = 8092; -const webHookPort = 8093; -const pollingPort2 = 8094; -const webHookPort2 = 8095; +let portindex = 8091; +const staticPort = portindex++; +const pollingPort = portindex++; +const webHookPort = portindex++; +const pollingPort2 = portindex++; +const webHookPort2 = portindex++; const staticUrl = `http://127.0.0.1:${staticPort}`; +const key = `${__dirname}/../examples/key.pem`; +const cert = `${__dirname}/../examples/crt.pem`; let FILE_ID; let GAME_CHAT_ID; let GAME_MSG_ID; @@ -37,7 +42,7 @@ before(function beforeAll() { }); }); -describe('Telegram', function telegramSuite() { +describe('TelegramBot', function telegramSuite() { let bot; let testbot; let botPolling; @@ -45,8 +50,8 @@ describe('Telegram', function telegramSuite() { before(function beforeAll() { this.timeout(timeout); - bot = new Telegram(TOKEN); - testbot = new Telegram(TOKEN, { + bot = new TelegramBot(TOKEN); + testbot = new TelegramBot(TOKEN, { baseApiUrl: `http://127.0.0.1:${pollingPort}`, polling: { autoStart: false, @@ -56,11 +61,11 @@ describe('Telegram', function telegramSuite() { port: webHookPort, }, }); - botPolling = new Telegram(TOKEN, { + botPolling = new TelegramBot(TOKEN, { baseApiUrl: `http://127.0.0.1:${pollingPort2}`, polling: true, }); - botWebHook = new Telegram(TOKEN, { + botWebHook = new TelegramBot(TOKEN, { webHook: { port: webHookPort2, }, @@ -136,6 +141,31 @@ describe('Telegram', function telegramSuite() { }); }); + describe('WebHook HTTPS', function webHookHTTPSSuite() { + const port = portindex++; + let httpsbot; + afterEach(function afterEach() { + return httpsbot.closeWebHook(); + }); + it('is enabled, through options.key and options.cert', function test() { + httpsbot = new TelegramBot(TOKEN, { webHook: { port, key, cert } }); + return utils.sendWebHookMessage(port, TOKEN, { https: true }); + }); + it('is enabled, through options.pfx'); + it('is enabled, through options.https', function test() { + httpsbot = new TelegramBot(TOKEN, { + webHook: { + port, + https: { + key: fs.readFileSync(key), + cert: fs.readFileSync(cert), + }, + }, + }); + return utils.sendWebHookMessage(port, TOKEN, { https: true }); + }); + }); + describe('#initPolling', function initPollingSuite() { it('initiates polling', function test() { testbot.initPolling(); @@ -215,7 +245,6 @@ describe('Telegram', function telegramSuite() { describe('#setWebHook', function setWebHookSuite() { const ip = '216.58.210.174'; - const cert = `${__dirname}/../examples/crt.pem`; before(function before() { utils.handleRatelimit(bot, 'setWebHook', this); }); diff --git a/test/utils.js b/test/utils.js index c4b59a9..c63c58e 100644 --- a/test/utils.js +++ b/test/utils.js @@ -37,6 +37,7 @@ exports = module.exports = { * @param {Object} [options] * @param {String} [options.method=POST] Method to use * @param {Object} [options.message] Message to send. Default to a generic text message + * @param {Boolean} [options.https=false] Use https * @return {Promise} */ sendWebHookMessage, @@ -136,7 +137,8 @@ function hasOpenWebHook(port, reverse) { function sendWebHookMessage(port, token, options = {}) { assert.ok(port); assert.ok(token); - const url = `http://127.0.0.1:${port}/bot${token}`; + const protocol = options.https ? 'https' : 'http'; + const url = `${protocol}://127.0.0.1:${port}/bot${token}`; return request({ url, method: options.method || 'POST',