fix: escape Telegram MarkdownV2 after template rendering (#6579)

This commit is contained in:
Frank Elsinga 2026-01-04 07:54:11 +01:00 committed by GitHub
commit a0a009f31c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -4,6 +4,47 @@ const axios = require("axios");
class Telegram extends NotificationProvider {
name = "telegram";
/**
* Escapes special characters for Telegram MarkdownV2 format
* @param {string} text Text to escape
* @returns {string} Escaped text
*/
escapeMarkdownV2(text) {
if (!text) {
return text;
}
// Characters that need to be escaped in MarkdownV2
// https://core.telegram.org/bots/api#markdownv2-style
return String(text).replace(/[_*[\]()~>#+\-=|{}.!\\]/g, "\\$&");
}
/**
* Recursively escapes string properties of an object for Telegram MarkdownV2
* @param {object|string} obj Object or string to escape
* @returns {object|string} Escaped object or string
*/
escapeObjectRecursive(obj) {
if (typeof obj === "string") {
return this.escapeMarkdownV2(obj);
}
if (typeof obj === "object" && obj !== null) {
// Check if array
if (Array.isArray(obj)) {
return obj.map(item => this.escapeObjectRecursive(item));
}
const newObj = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
newObj[key] = this.escapeObjectRecursive(obj[key]);
}
}
return newObj;
}
return obj;
}
/**
* @inheritdoc
*/
@ -24,7 +65,29 @@ class Telegram extends NotificationProvider {
}
if (notification.telegramUseTemplate) {
params.text = await this.renderTemplate(notification.telegramTemplate, msg, monitorJSON, heartbeatJSON);
let monitorJSONCopy = monitorJSON;
let heartbeatJSONCopy = heartbeatJSON;
if (notification.telegramTemplateParseMode === "MarkdownV2") {
msg = this.escapeMarkdownV2(msg);
if (monitorJSONCopy) {
monitorJSONCopy = this.escapeObjectRecursive(monitorJSONCopy);
} else {
// for testing monitorJSON is null, provide escaped defaults
monitorJSONCopy = {
name: this.escapeMarkdownV2("Monitor Name not available"),
hostname: this.escapeMarkdownV2("testing.hostname"),
url: this.escapeMarkdownV2("testing.hostname"),
};
}
if (heartbeatJSONCopy) {
heartbeatJSONCopy = this.escapeObjectRecursive(heartbeatJSONCopy);
}
}
params.text = await this.renderTemplate(notification.telegramTemplate, msg, monitorJSONCopy, heartbeatJSONCopy);
if (notification.telegramTemplateParseMode !== "plain") {
params.parse_mode = notification.telegramTemplateParseMode;