1 | "use strict";
|
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3 | if (k2 === undefined) k2 = k;
|
4 | var desc = Object.getOwnPropertyDescriptor(m, k);
|
5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6 | desc = { enumerable: true, get: function() { return m[k]; } };
|
7 | }
|
8 | Object.defineProperty(o, k2, desc);
|
9 | }) : (function(o, m, k, k2) {
|
10 | if (k2 === undefined) k2 = k;
|
11 | o[k2] = m[k];
|
12 | }));
|
13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15 | }) : function(o, v) {
|
16 | o["default"] = v;
|
17 | });
|
18 | var __importStar = (this && this.__importStar) || function (mod) {
|
19 | if (mod && mod.__esModule) return mod;
|
20 | var result = {};
|
21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22 | __setModuleDefault(result, mod);
|
23 | return result;
|
24 | };
|
25 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
26 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
27 | };
|
28 | Object.defineProperty(exports, "__esModule", { value: true });
|
29 | exports.Telegraf = void 0;
|
30 | const crypto = __importStar(require("crypto"));
|
31 | const http = __importStar(require("http"));
|
32 | const https = __importStar(require("https"));
|
33 | const composer_1 = require("./composer");
|
34 | const compact_1 = require("./core/helpers/compact");
|
35 | const context_1 = __importDefault(require("./context"));
|
36 | const debug_1 = __importDefault(require("debug"));
|
37 | const webhook_1 = __importDefault(require("./core/network/webhook"));
|
38 | const polling_1 = require("./core/network/polling");
|
39 | const p_timeout_1 = __importDefault(require("p-timeout"));
|
40 | const telegram_1 = __importDefault(require("./telegram"));
|
41 | const url_1 = require("url");
|
42 | const safeCompare = require("safe-compare");
|
43 | const debug = (0, debug_1.default)('telegraf:main');
|
44 | const DEFAULT_OPTIONS = {
|
45 | telegram: {},
|
46 | handlerTimeout: 90000,
|
47 | contextType: context_1.default,
|
48 | };
|
49 | function always(x) {
|
50 | return () => x;
|
51 | }
|
52 | const anoop = always(Promise.resolve());
|
53 | const TOKEN_HEADER = 'x-telegram-bot-api-secret-token';
|
54 | class Telegraf extends composer_1.Composer {
|
55 | constructor(token, options) {
|
56 | super();
|
57 | this.context = {};
|
58 | |
59 |
|
60 |
|
61 |
|
62 | this.webhookFilter = function (req) {
|
63 | const debug = (0, debug_1.default)('telegraf:webhook');
|
64 | if (req.method === 'POST') {
|
65 | if (safeCompare(this.hookPath, req.url)) {
|
66 |
|
67 | if (!this.secretToken)
|
68 | return true;
|
69 | else {
|
70 | const token = req.headers[TOKEN_HEADER];
|
71 | if (safeCompare(this.secretToken, token))
|
72 | return true;
|
73 | else
|
74 | debug('Secret token does not match:', token, this.secretToken);
|
75 | }
|
76 | }
|
77 | else
|
78 | debug('Path does not match:', req.url, this.hookPath);
|
79 | }
|
80 | else
|
81 | debug('Unexpected request method, not POST. Received:', req.method);
|
82 | return false;
|
83 | };
|
84 | this.handleError = (err, ctx) => {
|
85 |
|
86 |
|
87 |
|
88 | process.exitCode = 1;
|
89 | console.error('Unhandled error while processing', ctx.update);
|
90 | throw err;
|
91 | };
|
92 |
|
93 | this.options = {
|
94 | ...DEFAULT_OPTIONS,
|
95 | ...(0, compact_1.compactOptions)(options),
|
96 | };
|
97 | this.telegram = new telegram_1.default(token, this.options.telegram);
|
98 | debug('Created a `Telegraf` instance');
|
99 | }
|
100 | get token() {
|
101 | return this.telegram.token;
|
102 | }
|
103 |
|
104 | set webhookReply(webhookReply) {
|
105 | this.telegram.webhookReply = webhookReply;
|
106 | }
|
107 |
|
108 | get webhookReply() {
|
109 | return this.telegram.webhookReply;
|
110 | }
|
111 | |
112 |
|
113 |
|
114 | catch(handler) {
|
115 | this.handleError = handler;
|
116 | return this;
|
117 | }
|
118 | |
119 |
|
120 |
|
121 |
|
122 | webhookCallback(hookPath = '/', opts = {}) {
|
123 | const { secretToken } = opts;
|
124 | return (0, webhook_1.default)(this.webhookFilter.bind({ hookPath, secretToken }), (update, res) => this.handleUpdate(update, res));
|
125 | }
|
126 | getDomainOpts(opts) {
|
127 | var _a;
|
128 | const protocol = opts.domain.startsWith('https://') || opts.domain.startsWith('http://');
|
129 | if (protocol)
|
130 | debug('Unexpected protocol in domain, telegraf will use https:', opts.domain);
|
131 | const domain = protocol ? new url_1.URL(opts.domain).host : opts.domain;
|
132 | const path = (_a = opts.path) !== null && _a !== void 0 ? _a : `/telegraf/${this.secretPathComponent()}`;
|
133 | const url = `https://${domain}${path}`;
|
134 | return { domain, path, url };
|
135 | }
|
136 | |
137 |
|
138 |
|
139 |
|
140 | async createWebhook(opts) {
|
141 | const { domain, path, ...extra } = opts;
|
142 | const domainOpts = this.getDomainOpts({ domain, path });
|
143 | await this.telegram.setWebhook(domainOpts.url, extra);
|
144 | debug(`Webhook set to ${domainOpts.url}`);
|
145 | return this.webhookCallback(domainOpts.path, {
|
146 | secretToken: extra.secret_token,
|
147 | });
|
148 | }
|
149 | startPolling(allowedUpdates = []) {
|
150 | this.polling = new polling_1.Polling(this.telegram, allowedUpdates);
|
151 | return this.polling.loop(async (update) => {
|
152 | await this.handleUpdate(update);
|
153 | });
|
154 | }
|
155 | startWebhook(hookPath, tlsOptions, port, host, cb, secretToken) {
|
156 | const webhookCb = this.webhookCallback(hookPath, { secretToken });
|
157 | const callback = typeof cb === 'function'
|
158 | ? (req, res) => webhookCb(req, res, () => cb(req, res))
|
159 | : webhookCb;
|
160 | this.webhookServer =
|
161 | tlsOptions != null
|
162 | ? https.createServer(tlsOptions, callback)
|
163 | : http.createServer(callback);
|
164 | this.webhookServer.listen(port, host, () => {
|
165 | debug('Webhook listening on port: %s', port);
|
166 | });
|
167 | return this;
|
168 | }
|
169 | secretPathComponent() {
|
170 | return crypto
|
171 | .createHash('sha3-256')
|
172 | .update(this.token)
|
173 | .update(process.version)
|
174 | .digest('hex');
|
175 | }
|
176 | |
177 |
|
178 |
|
179 | async launch(config = {}) {
|
180 | var _a;
|
181 | debug('Connecting to Telegram');
|
182 | (_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = await this.telegram.getMe());
|
183 | debug(`Launching @${this.botInfo.username}`);
|
184 | if (config.webhook === undefined) {
|
185 | await this.telegram.deleteWebhook({
|
186 | drop_pending_updates: config.dropPendingUpdates,
|
187 | });
|
188 | debug('Bot started with long polling');
|
189 | await this.startPolling(config.allowedUpdates);
|
190 | return;
|
191 | }
|
192 | const domainOpts = this.getDomainOpts({
|
193 | domain: config.webhook.domain,
|
194 | path: config.webhook.hookPath,
|
195 | });
|
196 | const { tlsOptions, port, host, cb, secretToken } = config.webhook;
|
197 | this.startWebhook(domainOpts.path, tlsOptions, port, host, cb, secretToken);
|
198 | await this.telegram.setWebhook(domainOpts.url, {
|
199 | drop_pending_updates: config.dropPendingUpdates,
|
200 | allowed_updates: config.allowedUpdates,
|
201 | ip_address: config.webhook.ipAddress,
|
202 | max_connections: config.webhook.maxConnections,
|
203 | secret_token: config.webhook.secretToken,
|
204 | certificate: config.webhook.certificate,
|
205 | });
|
206 | debug(`Bot started with webhook @ ${domainOpts.url}`);
|
207 | }
|
208 | stop(reason = 'unspecified') {
|
209 | var _a, _b;
|
210 | debug('Stopping bot... Reason:', reason);
|
211 |
|
212 | if (this.polling === undefined && this.webhookServer === undefined) {
|
213 | throw new Error('Bot is not running!');
|
214 | }
|
215 | (_a = this.webhookServer) === null || _a === void 0 ? void 0 : _a.close();
|
216 | (_b = this.polling) === null || _b === void 0 ? void 0 : _b.stop();
|
217 | }
|
218 | async handleUpdate(update, webhookResponse) {
|
219 | var _a, _b;
|
220 | (_a = this.botInfo) !== null && _a !== void 0 ? _a : (this.botInfo = (debug('Update %d is waiting for `botInfo` to be initialized', update.update_id),
|
221 | await ((_b = this.botInfoCall) !== null && _b !== void 0 ? _b : (this.botInfoCall = this.telegram.getMe()))));
|
222 | debug('Processing update', update.update_id);
|
223 | const tg = new telegram_1.default(this.token, this.telegram.options, webhookResponse);
|
224 | const TelegrafContext = this.options.contextType;
|
225 | const ctx = new TelegrafContext(update, tg, this.botInfo);
|
226 | Object.assign(ctx, this.context);
|
227 | try {
|
228 | await (0, p_timeout_1.default)(Promise.resolve(this.middleware()(ctx, anoop)), this.options.handlerTimeout);
|
229 | }
|
230 | catch (err) {
|
231 | return await this.handleError(err, ctx);
|
232 | }
|
233 | finally {
|
234 | if ((webhookResponse === null || webhookResponse === void 0 ? void 0 : webhookResponse.writableEnded) === false) {
|
235 | webhookResponse.end();
|
236 | }
|
237 | debug('Finished processing update', update.update_id);
|
238 | }
|
239 | }
|
240 | }
|
241 | exports.Telegraf = Telegraf;
|