Fixes and stuff

This commit is contained in:
Isaac 2022-07-17 22:33:42 +01:00
parent 3aa9a9b2c6
commit 24d5e6d99d
9 changed files with 198 additions and 43 deletions

View File

@ -39,7 +39,7 @@
"@fastify/oauth2": "^5.0.0", "@fastify/oauth2": "^5.0.0",
"@prisma/client": "^4.0.0", "@prisma/client": "^4.0.0",
"cryptr": "^6.0.3", "cryptr": "^6.0.3",
"discord.js": "^13.8.1", "discord.js": "^13.9.0",
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"fastify": "^4.2.1", "fastify": "^4.2.1",
"figlet": "^1.5.2", "figlet": "^1.5.2",

View File

@ -36,7 +36,7 @@ module.exports = class Client extends FrameworkClient {
async login(token) { async login(token) {
/** @type {PrismaClient} */ /** @type {PrismaClient} */
this.prisma = new PrismaClient(); this.prisma = new PrismaClient();
this.prisma.$use(middleware); this.prisma.$use(middleware(this.log));
this.keyv = new Keyv(); this.keyv = new Keyv();
return super.login(token); return super.login(token);
} }

View File

@ -1,7 +1,9 @@
command: command:
log: log:
admin: admin:
changes: 'Changes' changes:
title: 'Changes'
description: 'These were the changes made:'
description: description:
joined: '{user} {verb} {targetType}' joined: '{user} {verb} {targetType}'
target: target:

View File

@ -37,7 +37,7 @@ module.exports = config => {
} }
return new Logger({ return new Logger({
namespaces: ['commands', 'http', 'listeners'], namespaces: ['commands', 'http', 'listeners', 'settings', 'tickets'],
transports, transports,
}); });
}; };

View File

@ -32,21 +32,6 @@ async function getLogChannel(client, guildId) {
return channelId && client.channels.cache.get(channelId); return channelId && client.channels.cache.get(channelId);
} }
/**
* @param {import("client")} client
* @param {*} target
* @returns {string} target.type
* @returns {string} target.id
*/
async function getTargetName(client, target) {
if (target.type === 'settings') {
return client.guilds.cache.get(target.id).name;
} else {
const row = await client.prisma[target.type].findUnique({ where: { id: target.id } });
return row.name ?? target.id;
}
}
/** /**
* @param {import("client")} client * @param {import("client")} client
* @param {object} details * @param {object} details
@ -58,7 +43,7 @@ async function logAdminEvent(client, {
guildId, userId, action, target, diff, guildId, userId, action, target, diff,
}) { }) {
const user = await client.users.fetch(userId); const user = await client.users.fetch(userId);
client.log.info(`${user.tag} ${action}d ${target.type} ${target.id}`); client.log.info.settings(`${user.tag} ${action}d ${target.type} ${target.id}`);
const settings = await client.prisma.guild.findUnique({ const settings = await client.prisma.guild.findUnique({
select: { select: {
footer: true, footer: true,
@ -75,7 +60,6 @@ async function logAdminEvent(client, {
}; };
const channel = client.channels.cache.get(settings.logChannel); const channel = client.channels.cache.get(settings.logChannel);
if (!channel) return; if (!channel) return;
const targetName = await getTargetName(client, target);
return await channel.send({ return await channel.send({
embeds: [ embeds: [
@ -95,7 +79,7 @@ async function logAdminEvent(client, {
targetType: getMessage(`log.admin.description.target.${target.type}`), targetType: getMessage(`log.admin.description.target.${target.type}`),
verb: getMessage(`log.admin.verb.${action}`), verb: getMessage(`log.admin.verb.${action}`),
})) }))
.addField(getMessage(`log.admin.title.target.${target.type}`), targetName), .addField(getMessage(`log.admin.title.target.${target.type}`), target.name ?? target.id),
// .setFooter({ // .setFooter({
// iconURL: client.guilds.cache.get(guildId).iconURL(), // iconURL: client.guilds.cache.get(guildId).iconURL(),
// text: settings.footer, // text: settings.footer,
@ -104,7 +88,8 @@ async function logAdminEvent(client, {
diff?.original && diff?.original &&
new MessageEmbed() new MessageEmbed()
.setColor('ORANGE') .setColor('ORANGE')
.setTitle(getMessage('log.admin.changes')) .setTitle(getMessage('log.admin.changes.title'))
.setDescription(getMessage('log.admin.changes.description'))
.setFields(makeDiff(diff)), .setFields(makeDiff(diff)),
], ],
], ],

View File

@ -5,7 +5,7 @@ const fields = [
'content', 'content',
'username', 'username',
'displayName', 'displayName',
'channelName', // 'channelName',
'openingMessage', 'openingMessage',
'description', 'description',
'value', 'value',
@ -19,23 +19,50 @@ const fields = [
const shouldEncrypt = ['create', 'createMany', 'update', 'updateMany', 'upsert']; const shouldEncrypt = ['create', 'createMany', 'update', 'updateMany', 'upsert'];
const shouldDecrypt = ['findUnique', 'findFirst', 'findMany']; const shouldDecrypt = ['findUnique', 'findFirst', 'findMany'];
module.exports = async (params, next) => {
if (params.args.data && shouldEncrypt.includes(params.action)) {
for (const field of fields) {
if (field in params.args.data && params.args.data[field] !== null && params.args.data[field] !== undefined) { module.exports = log => {
params.args.data[field] = cryptr.encrypt(params.args.data[field]); 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 result = await next(params); const decrypt = obj => {
for (const prop in obj) {
if (result && shouldDecrypt.includes(params.action)) { if (obj.hasOwnProperty(prop)) {
for (const field of fields) { if (typeof obj[prop] === 'object') {
if (field in result && result[field] !== null && result[field] !== undefined) { obj[prop] = decrypt(obj[prop]);
result[field] = cryptr.decrypt(params.result[field]); } 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 result; };
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);
return result;
};
}; };

View File

@ -0,0 +1,102 @@
const { logAdminEvent } = require('../../../../../../lib/logging');
module.exports.get = fastify => ({
handler: async (req, res) => {
/** @type {import('client')} */
const client = res.context.config.client;
const category = await client.prisma.category.findUnique({
include: {
questions: {
select: {
createdAt: true,
id: true,
label: true,
maxLength: true,
minLength: true,
order: true,
placeholder: true,
required: true,
style: true,
value: true,
},
},
},
where: { id: Number(req.params.category) },
});
return category;
},
onRequest: [fastify.authenticate, fastify.isAdmin],
});
module.exports.patch = fastify => ({
handler: async (req, res) => {
/** @type {import('client')} */
const client = res.context.config.client;
const user = await client.users.fetch(req.user.payload.id);
const guild = client.guilds.cache.get(req.params.guild);
const data = req.body;
const allow = ['VIEW_CHANNEL', 'READ_MESSAGE_HISTORY', 'SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES'];
const original = req.params.category && await client.prisma.category.findUnique({ where: { id: req.params.category } });
if (!original) return res.status(404);
if (!data.discordCategory) {
const channel = await guild.channels.create(data.name, {
permissionOverwrites: [
...[
{
deny: ['VIEW_CHANNEL'],
id: guild.roles.everyone,
},
{
allow: allow,
id: client.user.id,
},
],
...data.staffRoles.map(id => ({
allow: allow,
id,
})),
],
position: 1,
reason: `Tickets category created by ${user.tag}`,
type: 'GUILD_CATEGORY',
});
data.discordCategory = channel.id;
}
const category = await client.prisma.category.update({
data: {
guild: { connect: { id: guild.id } },
...data,
questions: {
upsert: data.questions?.map(q => ({
create: q,
update: q,
where: { id: q.id },
})),
},
},
});
logAdminEvent(client, {
action: 'update',
diff: {
original,
updated: category,
},
guildId: guild.id,
target: {
id: category.id,
name: category.name,
type: 'category',
},
userId: req.user.payload.id,
});
return category;
},
onRequest: [fastify.authenticate, fastify.isAdmin],
});

View File

@ -1,11 +1,35 @@
const { logAdminEvent } = require('../../../../../../lib/logging');
module.exports.get = fastify => ({ module.exports.get = fastify => ({
handler: async (req, res) => { handler: async (req, res) => {
/** @type {import('client')} */ /** @type {import('client')} */
const client = res.context.config.client; const client = res.context.config.client;
const categories = await client.prisma.guild.findUnique({ where: { id: req.params.guild } }).categories(); 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,
},
},
},
},
},
where: { id: req.params.guild },
});
res.send(categories); return categories;
}, },
onRequest: [fastify.authenticate, fastify.isAdmin], onRequest: [fastify.authenticate, fastify.isAdmin],
}); });
@ -45,14 +69,28 @@ module.exports.post = fastify => ({
data.discordCategory = channel.id; data.discordCategory = channel.id;
} }
if (data.channelName === null) data.channelName = undefined;
const category = await client.prisma.category.create({ const category = await client.prisma.category.create({
data: { data: {
guild: { connect: { id: guild.id } }, guild: { connect: { id: guild.id } },
...data, ...data,
questions: { createMany: { data: data.questions ?? [] } },
}, },
}); });
res.send(category); logAdminEvent(client, {
action: 'create',
guildId: guild.id,
target: {
id: category.id,
name: category.name,
type: 'category',
},
userId: req.user.payload.id,
});
return category;
}, },
onRequest: [fastify.authenticate, fastify.isAdmin], onRequest: [fastify.authenticate, fastify.isAdmin],
}); });

View File

@ -12,6 +12,7 @@ module.exports.delete = fastify => ({
guildId: id, guildId: id,
target: { target: {
id, id,
name: client.guilds.cache.get(id),
type: 'settings', type: 'settings',
}, },
userId: req.user.payload.id, userId: req.user.payload.id,
@ -53,9 +54,9 @@ module.exports.patch = fastify => ({
updated: settings, updated: settings,
}, },
guildId: id, guildId: id,
original,
target: { target: {
id, id,
name: client.guilds.cache.get(id),
type: 'settings', type: 'settings',
}, },
userId: req.user.payload.id, userId: req.user.payload.id,