diff --git a/src/commands/ai.ts b/src/commands/ai.ts index 4431f56..75177e0 100644 --- a/src/commands/ai.ts +++ b/src/commands/ai.ts @@ -145,6 +145,12 @@ export function sanitizeForJson(text: string): string { .replace(/\t/g, '\\t') } +export function escapeMarkdown(text: string): string { + if (!text) return ''; + return text + .replace(/([_\*\[\]()~`>#+\-=|{}.!])/g, '\\$1'); +} + export async function preChecks() { const envs = [ "ollamaApi", @@ -354,16 +360,17 @@ async function handleAiReply(ctx: TextContext, db: NodePgDatabase if (!ctx.chat) return; if (aiResponse.success && aiResponse.response) { const modelHeader = `🤖 *${model}* | 🌡️ *${aiTemperature}*\n\n`; + const safeResponse = escapeMarkdown(modelHeader + aiResponse.response); await rateLimiter.editMessageWithRetry( ctx, ctx.chat.id, replyGenerating.message_id, - modelHeader + aiResponse.response, + safeResponse, { parse_mode: 'Markdown' } ); return; } - const error = Strings.unexpectedErr.replace("{error}", aiResponse.error); + const error = escapeMarkdown(Strings.unexpectedErr.replace("{error}", aiResponse.error)); await rateLimiter.editMessageWithRetry( ctx, ctx.chat.id, diff --git a/src/commands/lastfm.ts b/src/commands/lastfm.ts index d51ca25..a198772 100644 --- a/src/commands/lastfm.ts +++ b/src/commands/lastfm.ts @@ -4,6 +4,7 @@ import axios from 'axios'; import { getStrings } from '../plugins/checklang'; import { isOnSpamWatch } from '../spamwatch/spamwatch'; import spamwatchMiddlewareModule from '../spamwatch/Middleware'; +import { escapeMarkdown } from './ai'; const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch); @@ -69,7 +70,7 @@ export default (bot) => { const lastUser = ctx.message.text.split(' ')[1]; if (!lastUser) { - return ctx.reply(Strings.lastFm.noUser, { + return ctx.reply(escapeMarkdown(Strings.lastFm.noUser), { parse_mode: "Markdown", disable_web_page_preview: true, ...(ctx.message?.message_id ? { reply_parameters: { message_id: ctx.message.message_id } } : {}) @@ -79,7 +80,7 @@ export default (bot) => { users[userId] = lastUser; saveUsers(); - const message = Strings.lastFm.userHasBeenSet.replace('{lastUser}', lastUser); + const message = escapeMarkdown(Strings.lastFm.userHasBeenSet.replace('{lastUser}', lastUser)); ctx.reply(message, { parse_mode: "Markdown", @@ -170,9 +171,9 @@ export default (bot) => { num_plays = response_plays.data.track.userplaycount; } catch (err) { console.log(err) - const message = Strings.lastFm.apiErr + const message = escapeMarkdown(Strings.lastFm.apiErr .replace("{lastfmUser}", `[${lastfmUser}](${userUrl})`) - .replace("{err}", err); + .replace("{err}", err)); ctx.reply(message, { parse_mode: "Markdown", disable_web_page_preview: true, @@ -180,11 +181,11 @@ export default (bot) => { }); }; - let message = Strings.lastFm.listeningTo + let message = escapeMarkdown(Strings.lastFm.listeningTo .replace("{lastfmUser}", `[${lastfmUser}](${userUrl})`) .replace("{nowPlaying}", nowPlaying) .replace("{trackName}", `[${trackName}](${trackUrl})`) - .replace("{artistName}", `[${artistName}](${artistUrl})`) + .replace("{artistName}", `[${artistName}](${artistUrl})`)); if (`${num_plays}` !== "0" && `${num_plays}` !== "1" && `${num_plays}` !== "2" && `${num_plays}` !== "3") { message = message @@ -211,9 +212,9 @@ export default (bot) => { }; } catch (err) { const userUrl = `https://www.last.fm/user/${encodeURIComponent(lastfmUser)}`; - const message = Strings.lastFm.apiErr + const message = escapeMarkdown(Strings.lastFm.apiErr .replace("{lastfmUser}", `[${lastfmUser}](${userUrl})`) - .replace("{err}", err); + .replace("{err}", err)); ctx.reply(message, { parse_mode: "Markdown", disable_web_page_preview: true, diff --git a/src/spamwatch b/src/spamwatch index cee30dc..5e9de56 160000 --- a/src/spamwatch +++ b/src/spamwatch @@ -1 +1 @@ -Subproject commit cee30dc64217e7ec235635f5bf5066eac56eec87 +Subproject commit 5e9de56c7e117811f8dba16fb671b65469688144