From 5786c3598d56747279f3e3afdf3cd7038113f6e4 Mon Sep 17 00:00:00 2001 From: Isaac Date: Tue, 19 Jul 2022 15:57:19 +0100 Subject: [PATCH] Giving up on encryption and life --- prisma/schema.prisma | 36 +++++----- src/client.js | 2 - src/lib/logging.js | 11 +-- src/lib/prisma.js | 69 ------------------- .../guilds/[guild]/categories/[category].js | 28 +++++--- .../admin/guilds/[guild]/categories/index.js | 38 +++++----- .../api/admin/guilds/[guild]/problems.js | 32 +++++++++ 7 files changed, 95 insertions(+), 121 deletions(-) delete mode 100644 src/lib/prisma.js create mode 100644 src/routes/api/admin/guilds/[guild]/problems.js diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 757dd7f..a9d2717 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -53,13 +53,13 @@ model ArchivedUser { bot Boolean @default(false) createdAt DateTime @default(now()) discriminator String @db.Char(4) - displayName String @db.VarChar(512) + displayName String @db.Text role ArchivedRole @relation(fields: [ticketId, roleId], references: [ticketId, roleId], onDelete: Cascade) roleId String @db.VarChar(19) ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade) ticketId String @db.VarChar(19) userId String @db.VarChar(19) - username String @db.VarChar(512) + username String @db.Text @@id([ticketId, userId]) @@unique([ticketId, userId]) @@ -70,7 +70,7 @@ model Category { channelName String claiming Boolean @default(false) createdAt DateTime @default(now()) - description String @db.VarChar(512) + description String discordCategory String @db.VarChar(19) emoji String enableFeedback Boolean @default(false) @@ -79,7 +79,7 @@ model Category { id Int @id @default(autoincrement()) image String? memberLimit Int @default(1) - name String @db.VarChar(512) + name String openingMessage String @db.Text pingRoles Json @default("[]") questions Question[] @@ -134,14 +134,14 @@ model Guild { model Question { answers QuestionAnswer[] createdAt DateTime @default(now()) - id Int @id @default(autoincrement()) - category Category? @relation(fields: [categoryId], references: [id]) - categoryId Int? - label String @db.VarChar(512) + id String @id @default(uuid()) + category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade) + categoryId Int + label String maxLength Int? @default(4000) minLength Int? @default(0) order Int - placeholder String? @db.VarChar(512) + placeholder String? required Boolean @default(true) style Int @default(2) value String? @db.Text @@ -152,11 +152,11 @@ model Question { model QuestionAnswer { createdAt DateTime @default(now()) id Int @id @default(autoincrement()) - ticket Ticket @relation(fields: [ticketId], references: [id]) + ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade) ticketId String @db.VarChar(19) - question Question @relation(fields: [questionId], references: [id]) - questionId Int - user User @relation(fields: [userId], references: [id]) + question Question @relation(fields: [questionId], references: [id], onDelete: Cascade) + questionId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String @db.VarChar(19) value String? @db.Text @@ -164,13 +164,13 @@ model QuestionAnswer { } model Tag { - content String @db.Text() + content String @db.Text createdAt DateTime @default(now()) guild Guild @relation(fields: [guildId], references: [id], onDelete: Cascade) guildId String @db.VarChar(19) id Int @id @default(autoincrement()) - name String @db.VarChar(512) - regex String? @db.VarChar(512) + name String + regex String? @@unique([guildId, name]) @@map("tags") @@ -188,7 +188,7 @@ model Ticket { closedAt DateTime? closedBy User @relation(name: "TicketsClosedByUser", fields: [closedById], references: [id]) closedById String @db.VarChar(19) - closedReason String? @db.VarChar(512) + closedReason String? createdAt DateTime @default(now()) createdBy User @relation(name: "TicketsCreatedByUser", fields: [createdById], references: [id]) createdById String @db.VarChar(19) @@ -210,7 +210,7 @@ model Ticket { referencesMessageId String @db.VarChar(19) referencesTicket Ticket? @relation(name: "TicketsReferencedByTicket", fields: [referencesTicketId], references: [id], onDelete: SetNull) referencesTicketId String? @db.VarChar(19) - topic String? @db.VarChar(512) + topic String? questionAnswers QuestionAnswer[] @@unique([guildId, number]) diff --git a/src/client.js b/src/client.js index 3c8b02a..4467174 100644 --- a/src/client.js +++ b/src/client.js @@ -6,7 +6,6 @@ const I18n = require('@eartharoid/i18n'); const fs = require('fs'); const { join } = require('path'); const YAML = require('yaml'); -const middleware = require('./lib/prisma'); module.exports = class Client extends FrameworkClient { constructor(config, log) { @@ -37,7 +36,6 @@ module.exports = class Client extends FrameworkClient { async login(token) { /** @type {PrismaClient} */ this.prisma = new PrismaClient(); - this.prisma.$use(middleware(this.log)); this.keyv = new Keyv(); return super.login(token); } diff --git a/src/lib/logging.js b/src/lib/logging.js index a88572a..19e7edf 100644 --- a/src/lib/logging.js +++ b/src/lib/logging.js @@ -1,4 +1,7 @@ -const { EmbedBuilder } = require('discord.js'); +const { + cleanCodeBlockContent, + EmbedBuilder, +} = require('discord.js'); const { diff: getDiff } = require('object-diffy'); function makeDiff({ @@ -8,12 +11,12 @@ function makeDiff({ const fields = []; for (const key in diff) { if (key === 'createdAt') continue; // object-diffy doesn't like dates - const from = diff[key].from === null ? '' : `- ${diff[key].from}\n`; - const to = diff[key].to === null ? '' : `+ ${diff[key].to}\n`; + const from = diff[key].from === null ? '' : `- ${diff[key].from.toString().replace(/\n/g, '\\n')}\n`; + const to = diff[key].to === null ? '' : `+ ${diff[key].to.toString().replace(/\n/g, '\\n')}\n`; fields.push({ inline: true, name: key, - value: `\`\`\`diff\n${from + to}\n\`\`\``, + value: `\`\`\`diff\n${cleanCodeBlockContent(from + to)}\n\`\`\``, }); } return fields; diff --git a/src/lib/prisma.js b/src/lib/prisma.js deleted file mode 100644 index d0818c9..0000000 --- a/src/lib/prisma.js +++ /dev/null @@ -1,69 +0,0 @@ -const Cryptr = require('cryptr'); -const cryptr = new Cryptr(process.env.ENCRYPTION_KEY); -const fields = [ - 'name', - 'content', - 'username', - 'displayName', - // 'channelName', - 'openingMessage', - 'description', - 'value', - 'placeholder', - 'closedReason', - 'topic', - 'comment', - 'label', - 'regex', -]; -const shouldEncrypt = ['create', 'createMany', 'update', 'updateMany', 'upsert']; -// const shouldDecrypt = ['findUnique', 'findFirst', 'findMany']; - - - - -module.exports = log => { - const encrypt = obj => { - for (const prop in obj) { - if (obj.hasOwnProperty(prop)) { - if (typeof obj[prop] === 'object') { - obj[prop] = encrypt(obj[prop]); - } else if (typeof obj[prop] === 'string' && obj[prop].length !== 0 && fields.includes(prop)) { - try { - obj[prop] = cryptr.encrypt(obj[prop]); - } catch (error) { - log.warn(`Failed to encrypt ${prop}`); - log.debug(error); - } - } - } - } - return obj; - }; - - const decrypt = obj => { - for (const prop in obj) { - if (obj.hasOwnProperty(prop)) { - if (typeof obj[prop] === 'object') { - obj[prop] = decrypt(obj[prop]); - } else if (typeof obj[prop] === 'string' && obj[prop].length !== 0 && fields.includes(prop)) { - try { - obj[prop] = cryptr.decrypt(obj[prop]); - } catch (error) { - log.warn(`Failed to decrypt ${prop}`); - log.debug(error); - } - } - } - } - return obj; - }; - - return async (params, next) => { - if (params.args.data && shouldEncrypt.includes(params.action)) params.args = encrypt(params.args); - let result = await next(params); - // if (result && shouldDecrypt.includes(params.action)) result = decrypt(result); - if (result) result = decrypt(result); - return result; - }; -}; \ No newline at end of file diff --git a/src/routes/api/admin/guilds/[guild]/categories/[category].js b/src/routes/api/admin/guilds/[guild]/categories/[category].js index 20b0d52..6f9aa16 100644 --- a/src/routes/api/admin/guilds/[guild]/categories/[category].js +++ b/src/routes/api/admin/guilds/[guild]/categories/[category].js @@ -1,10 +1,14 @@ const { logAdminEvent } = require('../../../../../../lib/logging'); +const { randomUUID } = require('crypto'); module.exports.delete = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ const client = res.context.config.client; + const guildId = req.params.guild; const categoryId = Number(req.params.category); + const original = req.params.category && await client.prisma.category.findUnique({ where: { id: categoryId } }); + if (!original || original.guildId !== guildId) return res.status(404).send(new Error('Not Found')); const category = await client.prisma.category.delete({ where: { id: categoryId } }); logAdminEvent(client, { @@ -27,12 +31,13 @@ module.exports.get = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ const client = res.context.config.client; + const guildId = req.params.guild; const categoryId = Number(req.params.category); const category = await client.prisma.category.findUnique({ include: { questions: { select: { - createdAt: true, + // createdAt: true, id: true, label: true, maxLength: true, @@ -45,9 +50,11 @@ module.exports.get = fastify => ({ }, }, }, - where: { id: categoryId }, + where: { id: categoryId }, }); + if (!category || category.guildId !== guildId) return res.status(404).send(new Error('Not Found')); + return category; }, onRequest: [fastify.authenticate, fastify.isAdmin], @@ -57,11 +64,13 @@ module.exports.patch = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ const client = res.context.config.client; + const guildId = req.params.guild; const categoryId = Number(req.params.category); const guild = client.guilds.cache.get(req.params.guild); const data = req.body; const original = req.params.category && await client.prisma.category.findUnique({ where: { id: categoryId } }); - if (!original) return res.status(404); + if (!original || original.guildId !== guildId) return res.status(404).send(new Error('Not Found')); + if (data.hasOwnProperty('id')) delete data.id; if (data.hasOwnProperty('createdAt')) delete data.createdAt; @@ -70,11 +79,14 @@ module.exports.patch = fastify => ({ data: { ...data, questions: { - upsert: data.questions?.map(q => ({ - create: q, - update: q, - where: { id: q.id }, - })), + upsert: data.questions?.map(q => { + if (!q.id) q.id = randomUUID(); + return { + create: q, + update: q, + where: { id: q.id }, + }; + }), }, }, where: { id: categoryId }, diff --git a/src/routes/api/admin/guilds/[guild]/categories/index.js b/src/routes/api/admin/guilds/[guild]/categories/index.js index f7219a1..ec9a5a0 100644 --- a/src/routes/api/admin/guilds/[guild]/categories/index.js +++ b/src/routes/api/admin/guilds/[guild]/categories/index.js @@ -8,29 +8,27 @@ module.exports.get = fastify => ({ const client = res.context.config.client; const { categories } = await client.prisma.guild.findUnique({ - select: { - categories: { - include: { - questions: { - select: { - createdAt: true, - id: true, - label: true, - maxLength: true, - minLength: true, - order: true, - placeholder: true, - required: true, - style: true, - value: true, - }, - }, - }, - }, - }, + select: { categories: true }, where: { id: req.params.guild }, }); + // include: { + // questions: { + // select: { + // createdAt: true, + // id: true, + // label: true, + // maxLength: true, + // minLength: true, + // order: true, + // placeholder: true, + // required: true, + // style: true, + // value: true, + // }, + // }, + // }, + return categories; }, onRequest: [fastify.authenticate, fastify.isAdmin], diff --git a/src/routes/api/admin/guilds/[guild]/problems.js b/src/routes/api/admin/guilds/[guild]/problems.js new file mode 100644 index 0000000..d4c5b2b --- /dev/null +++ b/src/routes/api/admin/guilds/[guild]/problems.js @@ -0,0 +1,32 @@ +module.exports.get = fastify => ({ + handler: async (req, res) => { + /** @type {import('client')} */ + const client = res.context.config.client; + const id = req.params.guild; + const guild = client.guilds.cache.get(id); + const settings = await client.prisma.guild.findUnique({ where: { id } }) ?? + await client.prisma.guild.create({ data: { id } }); + const problems = []; + + if (settings.logChannel) { + const permissions = guild.members.me.permissionsIn(settings.logChannel); + + if (!permissions.has('SendMessages')) { + problems.push({ + id: 'logChannelMissingPermission', + permission: 'SendMessages', + }); + } + + if (!permissions.has('EmbedLinks')) { + problems.push({ + id: 'logChannelMissingPermission', + permission: 'EmbedLinks', + }); + } + } + + return problems; + }, + onRequest: [fastify.authenticate, fastify.isAdmin], +});