@codebam/cf-workers-telegram-bot 12.1.0 → 12.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,6 +20,10 @@ export default class TelegramBot {
20
20
  defaultCommand: string;
21
21
  /** Optional secret token for webhook verification */
22
22
  secretToken?: string;
23
+ /** The bot's own user ID */
24
+ botId: number;
25
+ /** TTL for self-responses */
26
+ ttl: number;
23
27
  /**
24
28
  * Create a bot
25
29
  * @param token - the telegram secret token
@@ -19,6 +19,10 @@ export default class TelegramBot {
19
19
  defaultCommand = ':message';
20
20
  /** Optional secret token for webhook verification */
21
21
  secretToken;
22
+ /** The bot's own user ID */
23
+ botId;
24
+ /** TTL for self-responses */
25
+ ttl = 2;
22
26
  /**
23
27
  * Create a bot
24
28
  * @param token - the telegram secret token
@@ -27,6 +31,7 @@ export default class TelegramBot {
27
31
  constructor(token, options) {
28
32
  this.token = token.trim();
29
33
  this.api = new URL('https://api.telegram.org/bot' + this.token);
34
+ this.botId = parseInt(this.token.split(':')[0]);
30
35
  if (options?.defaultCommand) {
31
36
  this.defaultCommand = options.defaultCommand;
32
37
  }
@@ -7,6 +7,8 @@ export default class TelegramExecutionContext {
7
7
  private static businessOwners;
8
8
  /** Cache for dead business connections */
9
9
  private static poisonedConnections;
10
+ /** Cache for self-response counts to prevent infinite loops */
11
+ private static selfResponseCount;
10
12
  /** an instance of the telegram bot */
11
13
  bot: TelegramBot;
12
14
  /** an instance of the telegram update */
@@ -5,6 +5,8 @@ export default class TelegramExecutionContext {
5
5
  static businessOwners = new Map();
6
6
  /** Cache for dead business connections */
7
7
  static poisonedConnections = new Set();
8
+ /** Cache for self-response counts to prevent infinite loops */
9
+ static selfResponseCount = new Map();
8
10
  /** an instance of the telegram bot */
9
11
  bot;
10
12
  /** an instance of the telegram update */
@@ -73,6 +75,16 @@ export default class TelegramExecutionContext {
73
75
  */
74
76
  async shouldProcess() {
75
77
  if (this.update_type !== 'business_message') {
78
+ if (this.userId === this.bot.botId) {
79
+ const chatId = this.getChatId();
80
+ const count = TelegramExecutionContext.selfResponseCount.get(chatId) || 0;
81
+ if (count < this.bot.ttl) {
82
+ TelegramExecutionContext.selfResponseCount.set(chatId, count + 1);
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+ TelegramExecutionContext.selfResponseCount.delete(this.getChatId());
76
88
  return true;
77
89
  }
78
90
  const connectionId = this.update.business_message?.business_connection_id?.toString();
@@ -111,8 +123,15 @@ export default class TelegramExecutionContext {
111
123
  }
112
124
  }
113
125
  if (ownerId !== undefined && (this.getChatId() === ownerId.toString() || this.userId === ownerId)) {
126
+ const chatId = this.getChatId();
127
+ const count = TelegramExecutionContext.selfResponseCount.get(chatId) || 0;
128
+ if (count < this.bot.ttl) {
129
+ TelegramExecutionContext.selfResponseCount.set(chatId, count + 1);
130
+ return true;
131
+ }
114
132
  return false;
115
133
  }
134
+ TelegramExecutionContext.selfResponseCount.delete(this.getChatId());
116
135
  return true;
117
136
  }
118
137
  determineUpdateType() {
@@ -156,13 +175,13 @@ export default class TelegramExecutionContext {
156
175
  * @returns The chat ID as a string or empty string if not available
157
176
  */
158
177
  getChatId() {
159
- if (this.update.message?.chat.id) {
178
+ if (this.update.message?.chat?.id) {
160
179
  return this.update.message.chat.id.toString();
161
180
  }
162
- else if (this.update.business_message?.chat.id) {
181
+ else if (this.update.business_message?.chat?.id) {
163
182
  return this.update.business_message.chat.id.toString();
164
183
  }
165
- else if (this.update.guest_message?.chat.id) {
184
+ else if (this.update.guest_message?.chat?.id) {
166
185
  return this.update.guest_message.chat.id.toString();
167
186
  }
168
187
  return '';
package/dist/utils.js CHANGED
@@ -31,17 +31,18 @@ export async function markdownToHtml(s) {
31
31
  };
32
32
  renderer.strong = ({ tokens }) => `<b>${renderer.parser.parseInline(tokens)}</b>`;
33
33
  renderer.em = ({ tokens }) => `<i>${renderer.parser.parseInline(tokens)}</i>`;
34
- renderer.codespan = ({ text }) => `<code>${text}</code>`;
34
+ const escapeHtml = (text) => text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
35
+ renderer.codespan = ({ text }) => `<code>${escapeHtml(text)}</code>`;
35
36
  renderer.code = ({ text, lang }) => {
36
- const escapedText = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
37
+ const escapedText = escapeHtml(text);
37
38
  if (lang) {
38
39
  return `<pre><code class="language-${lang}">${escapedText}</code></pre>\n`;
39
40
  }
40
41
  return `<pre><code>${escapedText}</code></pre>\n`;
41
42
  };
42
43
  renderer.del = ({ tokens }) => `<s>${renderer.parser.parseInline(tokens)}</s>`;
43
- renderer.link = ({ href, tokens }) => `<a href="${href}">${renderer.parser.parseInline(tokens)}</a>`;
44
- renderer.image = ({ href, text }) => `<a href="${href}">${text}</a>`;
44
+ renderer.link = ({ href, tokens }) => `<a href="${escapeHtml(href)}">${renderer.parser.parseInline(tokens)}</a>`;
45
+ renderer.image = ({ href, text }) => `<a href="${escapeHtml(href)}">${escapeHtml(text)}</a>`;
45
46
  renderer.blockquote = ({ tokens }) => {
46
47
  return `<blockquote>${renderer.parser.parse(tokens)}</blockquote>\n`;
47
48
  };
@@ -60,14 +61,14 @@ export async function markdownToHtml(s) {
60
61
  }
61
62
  }
62
63
  // Escape everything else
63
- return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
64
+ return escapeHtml(text);
64
65
  };
65
66
  renderer.text = (token) => {
66
67
  if ('tokens' in token && token.tokens) {
67
68
  return renderer.parser.parseInline(token.tokens);
68
69
  }
69
70
  // Escape standard HTML entities
70
- return token.text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
71
+ return escapeHtml(token.text);
71
72
  };
72
73
  marked.setOptions({
73
74
  gfm: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebam/cf-workers-telegram-bot",
3
- "version": "12.1.0",
3
+ "version": "12.3.0",
4
4
  "description": "serverless telegram bot on cf workers",
5
5
  "main": "./dist/main.js",
6
6
  "module": "./dist/main.js",