Skip to content

Commit a0a009f

Browse files
fix: escape Telegram MarkdownV2 after template rendering (#6579)
2 parents d74963e + e83039f commit a0a009f

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

server/notification-providers/telegram.js

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,47 @@ const axios = require("axios");
44
class Telegram extends NotificationProvider {
55
name = "telegram";
66

7+
/**
8+
* Escapes special characters for Telegram MarkdownV2 format
9+
* @param {string} text Text to escape
10+
* @returns {string} Escaped text
11+
*/
12+
escapeMarkdownV2(text) {
13+
if (!text) {
14+
return text;
15+
}
16+
17+
// Characters that need to be escaped in MarkdownV2
18+
// https://core.telegram.org/bots/api#markdownv2-style
19+
return String(text).replace(/[_*[\]()~>#+\-=|{}.!\\]/g, "\\$&");
20+
}
21+
22+
/**
23+
* Recursively escapes string properties of an object for Telegram MarkdownV2
24+
* @param {object|string} obj Object or string to escape
25+
* @returns {object|string} Escaped object or string
26+
*/
27+
escapeObjectRecursive(obj) {
28+
if (typeof obj === "string") {
29+
return this.escapeMarkdownV2(obj);
30+
}
31+
if (typeof obj === "object" && obj !== null) {
32+
// Check if array
33+
if (Array.isArray(obj)) {
34+
return obj.map(item => this.escapeObjectRecursive(item));
35+
}
36+
37+
const newObj = {};
38+
for (const key in obj) {
39+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
40+
newObj[key] = this.escapeObjectRecursive(obj[key]);
41+
}
42+
}
43+
return newObj;
44+
}
45+
return obj;
46+
}
47+
748
/**
849
* @inheritdoc
950
*/
@@ -24,7 +65,29 @@ class Telegram extends NotificationProvider {
2465
}
2566

2667
if (notification.telegramUseTemplate) {
27-
params.text = await this.renderTemplate(notification.telegramTemplate, msg, monitorJSON, heartbeatJSON);
68+
let monitorJSONCopy = monitorJSON;
69+
let heartbeatJSONCopy = heartbeatJSON;
70+
71+
if (notification.telegramTemplateParseMode === "MarkdownV2") {
72+
msg = this.escapeMarkdownV2(msg);
73+
74+
if (monitorJSONCopy) {
75+
monitorJSONCopy = this.escapeObjectRecursive(monitorJSONCopy);
76+
} else {
77+
// for testing monitorJSON is null, provide escaped defaults
78+
monitorJSONCopy = {
79+
name: this.escapeMarkdownV2("Monitor Name not available"),
80+
hostname: this.escapeMarkdownV2("testing.hostname"),
81+
url: this.escapeMarkdownV2("testing.hostname"),
82+
};
83+
}
84+
85+
if (heartbeatJSONCopy) {
86+
heartbeatJSONCopy = this.escapeObjectRecursive(heartbeatJSONCopy);
87+
}
88+
}
89+
90+
params.text = await this.renderTemplate(notification.telegramTemplate, msg, monitorJSONCopy, heartbeatJSONCopy);
2891

2992
if (notification.telegramTemplateParseMode !== "plain") {
3093
params.parse_mode = notification.telegramTemplateParseMode;

0 commit comments

Comments
 (0)