mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-10-19 15:11:36 +00:00
fix: escape HTML and truncate long messages in Telegram notifications
This commit is contained in:
@@ -5,6 +5,7 @@ import { render } from "@react-email/components";
|
||||
import { format } from "date-fns";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import {
|
||||
formatTelegramErrorMessage,
|
||||
sendCustomNotification,
|
||||
sendDiscordNotification,
|
||||
sendEmailNotification,
|
||||
@@ -201,7 +202,7 @@ export const sendBuildErrorNotifications = async ({
|
||||
|
||||
await sendTelegramNotification(
|
||||
telegram,
|
||||
`<b>⚠️ Build Failed</b>\n\n<b>Project:</b> ${projectName}\n<b>Application:</b> ${applicationName}\n<b>Type:</b> ${applicationType}\n<b>Date:</b> ${format(date, "PP")}\n<b>Time:</b> ${format(date, "pp")}\n\n<b>Error:</b>\n<pre>${errorMessage}</pre>`,
|
||||
`<b>⚠️ Build Failed</b>\n\n<b>Project:</b> ${projectName}\n<b>Application:</b> ${applicationName}\n<b>Type:</b> ${applicationType}\n<b>Date:</b> ${format(date, "PP")}\n<b>Time:</b> ${format(date, "pp")}\n\n<b>Error:</b>\n<pre>${formatTelegramErrorMessage(errorMessage)}</pre>`,
|
||||
inlineButton,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { render } from "@react-email/components";
|
||||
import { format } from "date-fns";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import {
|
||||
formatTelegramErrorMessage,
|
||||
sendCustomNotification,
|
||||
sendDiscordNotification,
|
||||
sendEmailNotification,
|
||||
@@ -208,7 +209,7 @@ export const sendDatabaseBackupNotifications = async ({
|
||||
const statusEmoji = type === "success" ? "✅" : "❌";
|
||||
const typeStatus = type === "success" ? "Successful" : "Failed";
|
||||
const errorMsg = isError
|
||||
? `\n\n<b>Error:</b>\n<pre>${errorMessage}</pre>`
|
||||
? `\n\n<b>Error:</b>\n<pre>${formatTelegramErrorMessage(errorMessage)}</pre>`
|
||||
: "";
|
||||
|
||||
const messageText = `<b>${statusEmoji} Database Backup ${typeStatus}</b>\n\n<b>Project:</b> ${projectName}\n<b>Application:</b> ${applicationName}\n<b>Type:</b> ${databaseType}\n<b>Database Name:</b> ${databaseName}\n<b>Date:</b> ${format(date, "PP")}\n<b>Time:</b> ${format(date, "pp")}${isError ? errorMsg : ""}`;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { render } from "@react-email/components";
|
||||
import { format } from "date-fns";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import {
|
||||
escapeHtml,
|
||||
sendCustomNotification,
|
||||
sendDiscordNotification,
|
||||
sendEmailNotification,
|
||||
@@ -143,7 +144,7 @@ export const sendDockerCleanupNotifications = async (
|
||||
if (telegram) {
|
||||
await sendTelegramNotification(
|
||||
telegram,
|
||||
`<b>✅ Docker Cleanup</b>\n\n<b>Message:</b> ${message}\n<b>Date:</b> ${format(date, "PP")}\n<b>Time:</b> ${format(date, "pp")}`,
|
||||
`<b>✅ Docker Cleanup</b>\n\n<b>Message:</b> ${escapeHtml(message)}\n<b>Date:</b> ${format(date, "PP")}\n<b>Time:</b> ${format(date, "pp")}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { render } from "@react-email/components";
|
||||
import { format } from "date-fns";
|
||||
import { eq } from "drizzle-orm";
|
||||
import {
|
||||
formatTelegramErrorMessage,
|
||||
sendCustomNotification,
|
||||
sendDiscordNotification,
|
||||
sendEmailNotification,
|
||||
@@ -186,7 +187,7 @@ export const sendDokployBackupNotifications = async ({
|
||||
const statusEmoji = type === "success" ? "✅" : "❌";
|
||||
const typeStatus = type === "success" ? "Successful" : "Failed";
|
||||
const errorMsg = isError
|
||||
? `\n\n<b>Error:</b>\n<pre>${errorMessage}</pre>`
|
||||
? `\n\n<b>Error:</b>\n<pre>${formatTelegramErrorMessage(errorMessage)}</pre>`
|
||||
: "";
|
||||
const sizeInfo = backupSize
|
||||
? `\n<b>Backup Size:</b> ${backupSize}`
|
||||
|
||||
@@ -4,6 +4,7 @@ import { db } from "../../db";
|
||||
import { notifications } from "../../db/schema";
|
||||
import ServerThresholdEmail from "../../emails/emails/server-threshold";
|
||||
import {
|
||||
escapeHtml,
|
||||
sendCustomNotification,
|
||||
sendDiscordNotification,
|
||||
sendEmailNotification,
|
||||
@@ -193,7 +194,7 @@ export const sendServerThresholdNotifications = async (
|
||||
<b>Type:</b> ${payload.Type}
|
||||
<b>Current Value:</b> ${payload.Value.toFixed(2)}%
|
||||
<b>Threshold:</b> ${payload.Threshold.toFixed(2)}%
|
||||
<b>Message:</b> ${payload.Message}
|
||||
<b>Message:</b> ${escapeHtml(payload.Message)}
|
||||
<b>Time:</b> ${date.toLocaleString()}
|
||||
`,
|
||||
);
|
||||
|
||||
@@ -101,6 +101,30 @@ export const sendDiscordNotification = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const escapeHtml = (s: string) =>
|
||||
s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
|
||||
export const formatTelegramErrorMessage = (errorMessage: string) => {
|
||||
const escaped = escapeHtml(errorMessage);
|
||||
const limit = 3000;
|
||||
if (escaped.length <= limit) return escaped;
|
||||
let end = limit;
|
||||
const ampIdx = escaped.lastIndexOf("&", end);
|
||||
if (ampIdx !== -1 && escaped.indexOf(";", ampIdx) > end) {
|
||||
end = ampIdx;
|
||||
}
|
||||
if (
|
||||
end > 0 &&
|
||||
end < escaped.length &&
|
||||
isHighSurrogate(escaped.charCodeAt(end - 1))
|
||||
) {
|
||||
end--;
|
||||
}
|
||||
return `${escaped.substring(0, end)}…`;
|
||||
};
|
||||
|
||||
const isHighSurrogate = (code: number) => code >= 0xd800 && code <= 0xdbff;
|
||||
|
||||
export const sendTelegramNotification = async (
|
||||
connection: typeof telegram.$inferInsert,
|
||||
messageText: string,
|
||||
@@ -111,7 +135,7 @@ export const sendTelegramNotification = async (
|
||||
) => {
|
||||
try {
|
||||
const url = `https://api.telegram.org/bot${connection.botToken}/sendMessage`;
|
||||
await fetch(url, {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
@@ -125,8 +149,17 @@ export const sendTelegramNotification = async (
|
||||
},
|
||||
}),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const body = await response.text();
|
||||
throw new Error(
|
||||
`Failed to send telegram notification: ${response.status} ${body}`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw new Error(
|
||||
`Failed to send telegram notification ${err instanceof Error ? err.message : "Unknown error"}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { render } from "@react-email/components";
|
||||
import { format } from "date-fns";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import {
|
||||
formatTelegramErrorMessage,
|
||||
sendCustomNotification,
|
||||
sendDiscordNotification,
|
||||
sendEmailNotification,
|
||||
@@ -223,7 +224,7 @@ export const sendVolumeBackupNotifications = async ({
|
||||
const statusEmoji = type === "success" ? "✅" : "❌";
|
||||
const typeStatus = type === "success" ? "Successful" : "Failed";
|
||||
const errorMsg = isError
|
||||
? `\n\n<b>Error:</b>\n<pre>${errorMessage}</pre>`
|
||||
? `\n\n<b>Error:</b>\n<pre>${formatTelegramErrorMessage(errorMessage)}</pre>`
|
||||
: "";
|
||||
const sizeInfo = backupSize
|
||||
? `\n<b>Backup Size:</b> ${backupSize}`
|
||||
|
||||
Reference in New Issue
Block a user