From 09ee28d9c8713bb8fad2e4909afae96b15a512d6 Mon Sep 17 00:00:00 2001 From: Sim-hu Date: Fri, 20 Mar 2026 23:20:14 +0900 Subject: [PATCH 1/2] fix: escape user input in JSON template replacement to prevent crashes --- src/utils/close.ts | 18 ++++++++++++------ src/utils/createTicket.ts | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/utils/close.ts b/src/utils/close.ts index cd2edef6..92639c8d 100644 --- a/src/utils/close.ts +++ b/src/utils/close.ts @@ -114,12 +114,12 @@ export async function close( ViewChannel: false }) .catch((e: unknown) => console.log(e)); - invited.forEach(async (user) => { - (interaction.channel as TextChannel | null)?.permissionOverwrites + for (const user of invited) { + await (interaction.channel as TextChannel | null)?.permissionOverwrites .edit(user, { ViewChannel: false }); - }); + } interaction .editReply({ @@ -185,14 +185,20 @@ export async function close( .setDisabled(deleteTicket) ); const locale = client.locales; + // JSON.stringify().slice(1, -1) を使って安全にエスケープする(外側の引用符を除去しつつJSON特殊文字はエスケープ済み) + const safeTicketCount = JSON.stringify(ticket.id.toString()).slice(1, -1); + const safeReason = JSON.stringify( + (ticket.closereason ?? client.locales.getSubValue("other", "noReasonGiven")).replace(/[\n\r]/g, "\\n") + ).slice(1, -1); + const safeCloserName = JSON.stringify(interaction.user.tag).slice(1, -1); interaction.channel ?.send({ embeds: [ JSON.parse( JSON.stringify(locale.getSubRawValue("embeds", "ticketClosed")) - .replace("TICKETCOUNT", ticket.id.toString()) - .replace("REASON", (ticket.closereason ?? client.locales.getSubValue("other", "noReasonGiven")).replace(/[\n\r]/g, "\\n")) - .replace("CLOSERNAME", interaction.user.tag) + .replace("TICKETCOUNT", safeTicketCount) + .replace("REASON", safeReason) + .replace("CLOSERNAME", safeCloserName) ) ], components: [row] diff --git a/src/utils/createTicket.ts b/src/utils/createTicket.ts index e23fbb71..59481aa4 100644 --- a/src/utils/createTicket.ts +++ b/src/utils/createTicket.ts @@ -40,9 +40,9 @@ export const createTicket = async ( let allReasons = ""; if (typeof reasons === "object") { - reasons.forEach(async (r) => { + for (const [, r] of reasons) { reason.push(r.value); - }); + } allReasons = reason.map((r, i) => `Question ${i + 1}: ${r}`).join(", "); } if (typeof reasons === "string") allReasons = reasons; From 6830d2d08a16df7689bbd2e533d0e007177ac12e Mon Sep 17 00:00:00 2001 From: Sim-hu Date: Fri, 20 Mar 2026 23:25:27 +0900 Subject: [PATCH 2/2] fix: use English comments --- src/utils/close.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/close.ts b/src/utils/close.ts index 92639c8d..5f6f7331 100644 --- a/src/utils/close.ts +++ b/src/utils/close.ts @@ -185,7 +185,7 @@ export async function close( .setDisabled(deleteTicket) ); const locale = client.locales; - // JSON.stringify().slice(1, -1) を使って安全にエスケープする(外側の引用符を除去しつつJSON特殊文字はエスケープ済み) + // Use JSON.stringify().slice(1, -1) to safely escape (strips outer quotes while keeping JSON special chars escaped) const safeTicketCount = JSON.stringify(ticket.id.toString()).slice(1, -1); const safeReason = JSON.stringify( (ticket.closereason ?? client.locales.getSubValue("other", "noReasonGiven")).replace(/[\n\r]/g, "\\n")