mirror of
https://github.com/Hessenuk/DiscordTickets.git
synced 2025-01-10 18:06:27 +02:00
fix(security): transcript access control (closes #555)
This commit is contained in:
parent
2d2f350284
commit
b8b5ac946a
@ -18,12 +18,13 @@ module.exports = class TicketCompleter extends Autocompleter {
|
||||
}
|
||||
|
||||
async getOptions(value, {
|
||||
guildId,
|
||||
interaction,
|
||||
open,
|
||||
userId,
|
||||
}) {
|
||||
/** @type {import("client")} */
|
||||
const client = this.client;
|
||||
const guildId = interaction.guild.id;
|
||||
const cacheKey = [guildId, userId, open].join('/');
|
||||
|
||||
let tickets = await this.cache.get(cacheKey);
|
||||
@ -34,21 +35,16 @@ module.exports = class TicketCompleter extends Autocompleter {
|
||||
where: { id: guildId },
|
||||
});
|
||||
tickets = await client.prisma.ticket.findMany({
|
||||
include: {
|
||||
category: {
|
||||
select: {
|
||||
emoji: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: { category: true },
|
||||
where: {
|
||||
createdById: userId,
|
||||
guildId,
|
||||
open,
|
||||
},
|
||||
});
|
||||
tickets = tickets.map(ticket => {
|
||||
tickets = tickets
|
||||
.filter(ticket => client.commands.commands.slash.get('transcript').shouldAllowAccess(interaction, ticket))
|
||||
.map(ticket => {
|
||||
const date = new Date(ticket.createdAt).toLocaleString([locale, 'en-GB'], { dateStyle: 'short' });
|
||||
const topic = ticket.topic ? '- ' + decrypt(ticket.topic).replace(/\n/g, ' ').substring(0, 50) : '';
|
||||
const category = emoji.hasEmoji(ticket.category.emoji) ? emoji.get(ticket.category.emoji) + ' ' + ticket.category.name : ticket.category.name;
|
||||
@ -77,7 +73,7 @@ module.exports = class TicketCompleter extends Autocompleter {
|
||||
const userId = otherMember || interaction.user.id;
|
||||
await interaction.respond(
|
||||
await this.getOptions(value, {
|
||||
guildId: interaction.guild.id,
|
||||
interaction,
|
||||
open: ['add', 'close', 'force-close', 'remove'].includes(command.name), // false for `new`, `transcript` etc
|
||||
userId,
|
||||
}),
|
||||
|
@ -1,5 +1,8 @@
|
||||
const { SlashCommand } = require('@eartharoid/dbf');
|
||||
const { ApplicationCommandOptionType } = require('discord.js');
|
||||
const {
|
||||
ApplicationCommandOptionType,
|
||||
PermissionsBitField,
|
||||
} = require('discord.js');
|
||||
const { isStaff } = require('../../lib/users');
|
||||
const ExtendedEmbedBuilder = require('../../lib/embed');
|
||||
const Cryptr = require('cryptr');
|
||||
@ -60,12 +63,45 @@ module.exports = class TicketsSlashCommand extends SlashCommand {
|
||||
}
|
||||
|
||||
const fields = [];
|
||||
let base_filter;
|
||||
|
||||
if (member.id === interaction.member.id) {
|
||||
base_filter = {
|
||||
createdById: member.id,
|
||||
guildId: interaction.guild.id,
|
||||
};
|
||||
} else {
|
||||
const { categories } = await client.prisma.guild.findUnique({
|
||||
select: {
|
||||
categories: {
|
||||
select: {
|
||||
id: true,
|
||||
staffRoles: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
where: { id: interaction.guild.id },
|
||||
});
|
||||
const allow_category_ids = (
|
||||
(
|
||||
client.supers.includes(interaction.member.id) ||
|
||||
interaction.member.permissions.has(PermissionsBitField.Flags.ManageGuild)
|
||||
)
|
||||
? categories
|
||||
: categories.filter(c => c.staffRoles.some(id => interaction.member.roles.cache.has(id)))
|
||||
)
|
||||
.map(c => c.id);
|
||||
base_filter = {
|
||||
categoryId: { in: allow_category_ids },
|
||||
createdById: member.id,
|
||||
guildId: interaction.guild.id,
|
||||
};
|
||||
}
|
||||
|
||||
const open = await client.prisma.ticket.findMany({
|
||||
include: { category: true },
|
||||
where: {
|
||||
createdById: member.id,
|
||||
guildId: interaction.guild.id,
|
||||
...base_filter,
|
||||
open: true,
|
||||
},
|
||||
});
|
||||
@ -75,8 +111,7 @@ module.exports = class TicketsSlashCommand extends SlashCommand {
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 10, // max 10 rows
|
||||
where: {
|
||||
createdById: member.id,
|
||||
guildId: interaction.guild.id,
|
||||
...base_filter,
|
||||
open: false,
|
||||
},
|
||||
});
|
||||
@ -84,8 +119,8 @@ module.exports = class TicketsSlashCommand extends SlashCommand {
|
||||
if (open.length >= 1) {
|
||||
fields.push({
|
||||
name: getMessage('commands.slash.tickets.response.fields.open.name'),
|
||||
value: open.map(ticket =>{
|
||||
const topic = ticket.topic ? `- \`${decrypt(ticket.topic).replace(/\n/g, ' ').slice(0, 30) }\`` : '';
|
||||
value: open.map(ticket => {
|
||||
const topic = ticket.topic ? `- \`${decrypt(ticket.topic).replace(/\n/g, ' ').slice(0, 30)}\`` : '';
|
||||
return `> <#${ticket.id}> ${topic}`;
|
||||
}).join('\n'),
|
||||
});
|
||||
|
@ -1,12 +1,14 @@
|
||||
const { SlashCommand } = require('@eartharoid/dbf');
|
||||
const { ApplicationCommandOptionType } = require('discord.js');
|
||||
const {
|
||||
ApplicationCommandOptionType,
|
||||
PermissionsBitField,
|
||||
} = require('discord.js');
|
||||
const fs = require('fs');
|
||||
const { join } = require('path');
|
||||
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 {
|
||||
@ -46,6 +48,15 @@ module.exports = class TranscriptSlashCommand extends SlashCommand {
|
||||
);
|
||||
}
|
||||
|
||||
shouldAllowAccess(interaction, ticket) {
|
||||
if (interaction.guild.id !== ticket.guildId) return false;
|
||||
if (ticket.createdById === interaction.member.id) return true;
|
||||
if (interaction.client.supers.includes(interaction.member.id)) return true;
|
||||
if (interaction.member.permissions.has(PermissionsBitField.Flags.ManageGuild)) return true;
|
||||
if (interaction.member.roles.cache.filter(role => ticket.category.staffRoles.includes(role.id)).size > 0) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
async fillTemplate(ticket) {
|
||||
/** @type {import("client")} */
|
||||
const client = this.client;
|
||||
@ -146,10 +157,7 @@ module.exports = class TranscriptSlashCommand extends SlashCommand {
|
||||
|
||||
if (!ticket) throw new Error(`Ticket ${ticketId} does not exist`);
|
||||
|
||||
if (
|
||||
ticket.createdById !== interaction.member.id &&
|
||||
!(await isStaff(interaction.guild, interaction.member.id))
|
||||
) {
|
||||
if (!this.shouldAllowAccess(interaction, ticket)) {
|
||||
const settings = await client.prisma.guild.findUnique({ where: { id: interaction.guild.id } });
|
||||
const getMessage = client.i18n.getLocale(settings.locale);
|
||||
return await interaction.editReply({
|
||||
|
Loading…
Reference in New Issue
Block a user