From b2790fca40e55b88e768ae608c01c8d66d77beea Mon Sep 17 00:00:00 2001 From: Isaac Date: Thu, 24 Aug 2023 17:34:32 +0100 Subject: [PATCH] =?UTF-8?q?fix(=F0=9F=9A=A8=20security):=20anyone=20with?= =?UTF-8?q?=20the=20channel=20ID=20could=20read=20transcripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/slash/transcript.js | 72 ++++++++++++++++++++++---------- src/i18n/en-GB.yml | 3 ++ 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/commands/slash/transcript.js b/src/commands/slash/transcript.js index c9642a5..d0b72e8 100644 --- a/src/commands/slash/transcript.js +++ b/src/commands/slash/transcript.js @@ -6,6 +6,8 @@ const Mustache = require('mustache'); const { AttachmentBuilder } = require('discord.js'); const Cryptr = require('cryptr'); const { decrypt } = new Cryptr(process.env.ENCRYPTION_KEY); +const { isStaff } = require('../../lib/users'); +const ExtendedEmbedBuilder = require('../../lib/embed'); module.exports = class TranscriptSlashCommand extends SlashCommand { constructor(client, options) { @@ -44,29 +46,9 @@ module.exports = class TranscriptSlashCommand extends SlashCommand { ); } - async fillTemplate(ticketId) { + async fillTemplate(ticket) { /** @type {import("client")} */ const client = this.client; - const ticket = await client.prisma.ticket.findUnique({ - include: { - archivedChannels: true, - archivedMessages: { - orderBy: { createdAt: 'asc' }, - where: { external: false }, - }, - archivedRoles: true, - archivedUsers: true, - category: true, - claimedBy: true, - closedBy: true, - createdBy: true, - feedback: true, - guild: true, - questionAnswers: true, - }, - where: { id: ticketId }, - }); - if (!ticket) throw new Error(`Ticket ${ticketId} does not exist`); ticket.claimedBy = ticket.archivedUsers.find(u => u.userId === ticket.claimedById); ticket.closedBy = ticket.archivedUsers.find(u => u.userId === ticket.closedById); @@ -137,14 +119,60 @@ module.exports = class TranscriptSlashCommand extends SlashCommand { * @param {import("discord.js").ChatInputCommandInteraction} interaction */ async run(interaction) { + /** @type {import("client")} */ + const client = this.client; + await interaction.deferReply({ ephemeral: true }); + const ticketId = interaction.options.getString('ticket', true); + const ticket = await client.prisma.ticket.findUnique({ + include: { + archivedChannels: true, + archivedMessages: { + orderBy: { createdAt: 'asc' }, + where: { external: false }, + }, + archivedRoles: true, + archivedUsers: true, + category: true, + claimedBy: true, + closedBy: true, + createdBy: true, + feedback: true, + guild: true, + questionAnswers: true, + }, + where: { id: ticketId }, + }); + + if (!ticket) throw new Error(`Ticket ${ticketId} does not exist`); + + if ( + ticket.createdById !== interaction.member.id && + !(await isStaff(interaction.guild, interaction.member.id)) + ) { + const settings = await client.prisma.guild.findUnique({ where: { id: interaction.guild.id } }); + const getMessage = client.i18n.getLocale(settings.locale); + return await interaction.editReply({ + embeds: [ + new ExtendedEmbedBuilder({ + iconURL: interaction.guild.iconURL(), + text: ticket.guild.footer, + }) + .setColor(ticket.guild.errorColour) + .setTitle(getMessage('commands.slash.transcript.not_staff.title')) + .setDescription(getMessage('commands.slash.transcript.not_staff.description')), + ], + }); + } + const { fileName, transcript, - } = await this.fillTemplate(interaction.options.getString('ticket', true)); + } = await this.fillTemplate(ticket); const attachment = new AttachmentBuilder() .setFile(Buffer.from(transcript)) .setName(fileName); + await interaction.editReply({ files: [attachment] }); // TODO: add portal link } diff --git a/src/i18n/en-GB.yml b/src/i18n/en-GB.yml index 803f574..e3db6b5 100644 --- a/src/i18n/en-GB.yml +++ b/src/i18n/en-GB.yml @@ -228,6 +228,9 @@ commands: transcript: description: Get the transcript of a ticket name: transcript + not_staff: + description: Only staff members can read the transcripts of others' tickets. + title: ❌ Error options: member: description: The member to search for tickets of