diff --git a/result b/result deleted file mode 120000 index 0025238..0000000 --- a/result +++ /dev/null @@ -1 +0,0 @@ -/nix/store/fmvzckvxnqrfbgv0mvzghgi87602pgcm-nucleus-1.1.0 \ No newline at end of file diff --git a/src/config/default.ts b/src/config/default.ts index 69de019..ea5600d 100644 --- a/src/config/default.ts +++ b/src/config/default.ts @@ -61,7 +61,7 @@ export default { stats: {}, logging: { logs: { - enabled: false, + enabled: true, channel: null, toLog: "3fffff" }, diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index 5277383..b7eb745 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -46,13 +46,16 @@ async function interactionCreate(interaction: Interaction) { : false; return await modifySuggestion(interaction, value); } - if (interaction.customId.startsWith("log:edit:")) { - const messageId = interaction.customId.split(":")[2]; - const message = await interaction.channel?.messages.fetch(messageId!); - const attachment = message?.attachments.find((a) => a.name === "log.json"); + if (interaction.customId === "log:edit") { + const attachment = interaction.message.embeds[0]?.image; + console.log(attachment) if (!attachment) return; - const log = JSON.parse(Buffer.from(await (await fetch(attachment.url)).text(), 'base64').toString('binary')); - console.log(log); + const attachmentData = await (await fetch(attachment.url)).text() + console.log(attachmentData) + const decoded = atob(attachmentData); + console.log("decoded", decoded) + const json = JSON.parse(decoded); + console.log("json", json) } switch (interaction.customId) { case "rolemenu": { diff --git a/src/events/messageEdit.ts b/src/events/messageEdit.ts index 5964df9..f61a873 100644 --- a/src/events/messageEdit.ts +++ b/src/events/messageEdit.ts @@ -18,8 +18,7 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe renderUser, renderDelta, renderNumberDelta, - renderChannel, - preLog + renderChannel } = client.logger; const replyTo: MessageReference | null = newMessage.reference; const newContent = newMessage.cleanContent.replaceAll("`", "‘"); @@ -73,10 +72,14 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe return; } const differences = diff.diffChars(oldContent, newContent); - const charsAdded = differences.filter((x) => x.added).length; - const charsRemoved = differences.filter((x) => x.removed).length; - const preLogMessage = await preLog(newMessage.guild.id, JSON.stringify(differences, null, 2)); - if (!preLogMessage) return; + const charsAdded = (differences.filter((d) => d.added).map((d) => d.count)).reduce((a, b) => a! + b!, 0)!; + const charsRemoved = (differences.filter((d) => d.removed).map((d) => d.count)).reduce((a, b) => a! + b!, 0)!; + const imageData = JSON.stringify({data: differences, extra: "The image in this embed contains data about the below log.\n" + + "It isn't designed to be read by humans, but you can decode " + + "it with any base64 decoder, and then read it as JSON.\n" + + "We use base 64 to get around people using virus tests and the file being blocked, and an image to have the embed hidden (files can't be suppressed)\n" + + "If you've got to this point and are reading this hidden message, you should come and work with us " + + "at https://discord.gg/w35pXdrxKW (Internal development server) and let us know how you got here."}, null, 2) const data = { meta: { type: "messageUpdate", @@ -85,10 +88,11 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe color: NucleusColors.yellow, emoji: "MESSAGE.EDIT", timestamp: newMessage.editedTimestamp, - changes: { messageId: `${preLogMessage.id}`, buttonText: "View Changes", buttonStyle: ButtonStyle.Secondary, buttonId: `log:edit:${preLogMessage.id}` } + buttons: [{ buttonText: "View Changes", buttonStyle: ButtonStyle.Secondary, buttonId: `log:edit` }], + imageData: imageData }, separate: { - start: `${charsAdded} ${addPlural(charsAdded, "character")} added, ${charsRemoved} ${addPlural(charsRemoved, "character")} removed`, + start: `${addPlural(charsAdded, "character")} added, ${addPlural(charsRemoved, "character")} removed`, end: `[[Jump to message]](${newMessage.url})` }, list: { diff --git a/src/utils/log.ts b/src/utils/log.ts index 325aaa8..2679fd6 100644 --- a/src/utils/log.ts +++ b/src/utils/log.ts @@ -4,7 +4,6 @@ import { promisify } from "util"; import generateKeyValueList from "./generateKeyValueList.js"; import client from "./client.js"; import { DiscordAPIError } from "discord.js"; -import { Stream } from "node:stream"; import EmojiEmbed from "./generateEmojiEmbed.js"; const wait = promisify(setTimeout); @@ -17,15 +16,8 @@ export interface LoggerOptions { color: number; emoji: string; timestamp: number; - files?: ( - | Discord.BufferResolvable - | Stream - | Discord.JSONEncodable - | Discord.Attachment - | Discord.AttachmentBuilder - | Discord.AttachmentPayload - )[]; - showDetails?: boolean; + buttons?: { buttonText: string, buttonId: string, buttonStyle: Discord.ButtonStyle }[]; + imageData?: string; }; list: Record; hidden: { @@ -47,6 +39,13 @@ async function isLogging(guild: string, type: string): Promise { return true; } +const NucleusColors = { + red: 0xf27878, + yellow: 0xf2d478, + green: 0x68d49e, + blue: 0x72aef5, +}; + export const Logger = { renderUser(user: Discord.User | string) { if (typeof user === "string") user = client.users.cache.get(user)!; @@ -86,11 +85,7 @@ export const Logger = { renderEmoji(emoji: Discord.GuildEmoji) { return `<${emoji.animated ? "a" : ""}:${emoji.name}:${emoji.id}> [\`:${emoji.name}:\`]`; }, - NucleusColors: { - red: 0xf27878, - yellow: 0xf2d478, - green: 0x68d49e - }, + NucleusColors, async getAuditLog( guild: Discord.Guild, event: Discord.GuildAuditLogsResolvable, @@ -106,22 +101,7 @@ export const Logger = { throw e; } }, - async preLog(guild: string, file: string): Promise { - const config = await client.database.guilds.read(guild); - if (!config.logging.logs.channel) return; - const channel = (await client.channels.fetch(config.logging.logs.channel)) as Discord.TextChannel | null; - if (!channel) return; - const message = await channel.send({ - files: [ - { - attachment: Buffer.from(file, "base64"), - name: "log.json" - } - ], - flags: ["SuppressEmbeds"] - }); - return message; - }, + async log(log: LoggerOptions): Promise { if (!(await isLogging(log.hidden.guild, log.meta.calculateType))) return; const config = await client.database.guilds.read(log.hidden.guild); @@ -139,6 +119,7 @@ export const Logger = { description[key] = value; } }); + console.log("imageData", log.meta.imageData) if (channel) { log.separate = log.separate ?? {}; const messageOptions: Parameters[0] = {}; @@ -154,17 +135,29 @@ export const Logger = { ) .setTimestamp(log.meta.timestamp) .setColor(log.meta.color) + .setImage(log.meta.imageData ? "attachment://extra_log_data.json.base64" : null) ]; - if (log.meta.files) messageOptions.files = log.meta.files; - if (log.meta.showDetails) { - components.addComponents( - new Discord.ButtonBuilder() - .setCustomId("log:showDetails") - .setLabel("Show Details") - .setStyle(Discord.ButtonStyle.Primary) - ); + if (log.meta.buttons) { + const buttons = [] + for (const button of log.meta.buttons) { + buttons.push( + new Discord.ButtonBuilder() + .setCustomId(button.buttonId) + .setLabel(button.buttonText) + .setStyle(button.buttonStyle) + ) + } + components.addComponents(buttons); messageOptions.components = [components]; } + if (log.meta.imageData) { + messageOptions.files = [ + { + attachment: Buffer.from(btoa(log.meta.imageData), "utf-8"), // Use base 64 to prevent virus scanning (EICAR)Buffer.from(log.meta.imageData, "base64"), + name: "extra_log_data.json.base64" + } + ]; + } await channel.send(messageOptions); } }