fix(🚨 security): anyone with the channel ID could read transcripts

This commit is contained in:
Isaac 2023-08-24 17:34:32 +01:00
parent 2abd9cc008
commit b2790fca40
No known key found for this signature in database
GPG Key ID: 0DE40AE37BBA5C33
2 changed files with 53 additions and 22 deletions

View File

@ -6,6 +6,8 @@ const Mustache = require('mustache');
const { AttachmentBuilder } = require('discord.js'); const { AttachmentBuilder } = require('discord.js');
const Cryptr = require('cryptr'); const Cryptr = require('cryptr');
const { decrypt } = new Cryptr(process.env.ENCRYPTION_KEY); const { decrypt } = new Cryptr(process.env.ENCRYPTION_KEY);
const { isStaff } = require('../../lib/users');
const ExtendedEmbedBuilder = require('../../lib/embed');
module.exports = class TranscriptSlashCommand extends SlashCommand { module.exports = class TranscriptSlashCommand extends SlashCommand {
constructor(client, options) { constructor(client, options) {
@ -44,29 +46,9 @@ module.exports = class TranscriptSlashCommand extends SlashCommand {
); );
} }
async fillTemplate(ticketId) { async fillTemplate(ticket) {
/** @type {import("client")} */ /** @type {import("client")} */
const client = this.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.claimedBy = ticket.archivedUsers.find(u => u.userId === ticket.claimedById);
ticket.closedBy = ticket.archivedUsers.find(u => u.userId === ticket.closedById); 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 * @param {import("discord.js").ChatInputCommandInteraction} interaction
*/ */
async run(interaction) { async run(interaction) {
/** @type {import("client")} */
const client = this.client;
await interaction.deferReply({ ephemeral: true }); 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 { const {
fileName, fileName,
transcript, transcript,
} = await this.fillTemplate(interaction.options.getString('ticket', true)); } = await this.fillTemplate(ticket);
const attachment = new AttachmentBuilder() const attachment = new AttachmentBuilder()
.setFile(Buffer.from(transcript)) .setFile(Buffer.from(transcript))
.setName(fileName); .setName(fileName);
await interaction.editReply({ files: [attachment] }); await interaction.editReply({ files: [attachment] });
// TODO: add portal link // TODO: add portal link
} }

View File

@ -228,6 +228,9 @@ commands:
transcript: transcript:
description: Get the transcript of a ticket description: Get the transcript of a ticket
name: transcript name: transcript
not_staff:
description: Only staff members can read the transcripts of others' tickets.
title: ❌ Error
options: options:
member: member:
description: The member to search for tickets of description: The member to search for tickets of