diff --git a/.eslintignore b/.eslintignore index 45ad95d..d7b2f7f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1 @@ -ClicksMigratingProblems/**/* +ClicksMigratingProblems/**/* \ No newline at end of file diff --git a/src/api/index.ts b/src/api/index.ts index 9676194..c8b7b14 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -152,7 +152,7 @@ const runServer = (client: NucleusClient) => { app.get("/transcript/:code/human", jsonParser, async function (req: express.Request, res: express.Response) { const code = req.params.code; if (code === undefined) return res.status(400).send("No code provided"); - const entry = await client.database.transcripts.read(code); + const entry = await client.database.transcripts.read(code, req.query.key as string, req.query.iv as string); if (entry === null) return res.status(404).send("Could not find a transcript by that code"); // Convert to a human readable format const data = client.database.transcripts.toHumanReadable(entry); @@ -164,7 +164,7 @@ const runServer = (client: NucleusClient) => { app.get("/transcript/:code", jsonParser, async function (req: express.Request, res: express.Response) { const code = req.params.code; if (code === undefined) return res.status(400).send("No code provided"); - const entry = await client.database.transcripts.read(code); + const entry = await client.database.transcripts.read(code, req.query.key as string, req.query.iv as string); if (entry === null) return res.status(404).send("Could not find a transcript by that code"); // Convert to a human readable format return res.status(200).send(entry); diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts index 8644e26..7728e56 100644 --- a/src/commands/mod/purge.ts +++ b/src/commands/mod/purge.ts @@ -318,7 +318,7 @@ const callback = async (interaction: CommandInteraction): Promise => { )).map(message => message as Message); const newOut = await client.database.transcripts.createTranscript(messageArray, interaction, interaction.member as GuildMember); - const code = await client.database.transcripts.create(newOut); + const [code, key, iv] = await client.database.transcripts.create(newOut); await interaction.editReply({ embeds: [ new EmojiEmbed() @@ -329,7 +329,7 @@ const callback = async (interaction: CommandInteraction): Promise => { ], components: [ new Discord.ActionRowBuilder().addComponents([ - new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript?code=${code}`), + new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript/${code}?key=${key}&iv=${iv}`).setDisabled(!code), ]) ] }); diff --git a/src/commands/privacy.ts b/src/commands/privacy.ts index 46784f5..69c8980 100644 --- a/src/commands/privacy.ts +++ b/src/commands/privacy.ts @@ -179,9 +179,10 @@ const callback = async (interaction: CommandInteraction): Promise => { continue; } if (confirmation.success) { - client.database.guilds.delete(interaction.guild!.id); - client.database.history.delete(interaction.guild!.id); - client.database.notes.delete(interaction.guild!.id); + await client.database.guilds.delete(interaction.guild!.id); + await client.database.history.delete(interaction.guild!.id); + await client.database.notes.delete(interaction.guild!.id); + await client.database.transcripts.deleteAll(interaction.guild!.id); nextFooter = "All data cleared"; continue; } else { diff --git a/src/context/messages/purgeto.ts b/src/context/messages/purgeto.ts index aef159b..0dc84e1 100644 --- a/src/context/messages/purgeto.ts +++ b/src/context/messages/purgeto.ts @@ -193,7 +193,7 @@ const callback = async (interaction: MessageContextMenuCommandInteraction) => { ) )).map(message => message as Message); const transcript = await client.database.transcripts.createTranscript(messageArray, interaction, interaction.member as GuildMember); - const code = await client.database.transcripts.create(transcript); + const [code, key, iv] = await client.database.transcripts.create(transcript); await interaction.editReply({ embeds: [ new EmojiEmbed() @@ -204,7 +204,7 @@ const callback = async (interaction: MessageContextMenuCommandInteraction) => { ], components: [ new Discord.ActionRowBuilder().addComponents([ - new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript?code=${code}`), + new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript/${code}?key=${key}&iv=${iv}`).setDisabled(!code), ]) ] }); diff --git a/src/premium/createTranscript.ts b/src/premium/createTranscript.ts index 67aed04..fa5ec84 100644 --- a/src/premium/createTranscript.ts +++ b/src/premium/createTranscript.ts @@ -60,7 +60,7 @@ export default async function (interaction: CommandInteraction | MessageComponen const newOut = await client.database.transcripts.createTranscript(messages, interaction, member); - const code = await client.database.transcripts.create(newOut); + const [code, key, iv] = await client.database.transcripts.create(newOut); if(!code) return await interaction.reply({ embeds: [ new EmojiEmbed() @@ -86,7 +86,7 @@ export default async function (interaction: CommandInteraction | MessageComponen ], components: [ new ActionRowBuilder().addComponents([ - new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://clicks.codes/nucleus/transcript/${code}`), + new ButtonBuilder().setLabel("View").setStyle(ButtonStyle.Link).setURL(`https://testing.coded.codes/nucleus/transcript/${code}?key=${key}&iv=${iv}`), new ButtonBuilder() .setLabel("Delete") .setStyle(ButtonStyle.Danger) diff --git a/src/utils/database.ts b/src/utils/database.ts index 2e64320..0d21979 100644 --- a/src/utils/database.ts +++ b/src/utils/database.ts @@ -21,6 +21,7 @@ await mongoClient.connect(); const database = mongoClient.db(); const collectionOptions = { authdb: "admin" }; +const getIV = () => crypto.randomBytes(16); export class Guilds { guilds: Collection; @@ -203,15 +204,39 @@ export class Transcript { do { code = crypto.randomBytes(64).toString("base64").replace(/=/g, "").replace(/\//g, "_").replace(/\+/g, "-"); } while (await this.transcripts.findOne({ code: code })); + const key = crypto.randomBytes(32**2).toString("base64").replace(/=/g, "").replace(/\//g, "_").replace(/\+/g, "-").substring(0, 32); + const iv = getIV().toString("base64").replace(/=/g, "").replace(/\//g, "_").replace(/\+/g, "-"); + for(const message of transcript.messages) { + if(message.content) { + const encCipher = crypto.createCipheriv("AES-256-CBC", key, iv); + message.content = encCipher.update(message.content, "utf8", "base64") + encCipher.final("base64"); + } + } const doc = await this.transcripts.insertOne(Object.assign(transcript, { code: code }), collectionOptions); - if(doc.acknowledged) return code; - else return null; + if(doc.acknowledged) return [code, key, iv]; + else return [null, null, null]; } - async read(code: string) { + async read(code: string, key: string, iv: string) { // console.log("Transcript read") - return await this.transcripts.findOne({ code: code }); + const doc = await this.transcripts.findOne({ code: code }); + if(!doc) return null; + for(const message of doc.messages) { + if(message.content) { + const decCipher = crypto.createDecipheriv("AES-256-CBC", key, iv); + message.content = decCipher.update(message.content, "base64", "utf8") + decCipher.final("utf8"); + } + } + return doc; + } + + async deleteAll(guild: string) { + // console.log("Transcript delete") + const filteredDocs = await this.transcripts.find({ guild: guild }).toArray(); + for (const doc of filteredDocs) { + await this.transcripts.deleteOne({ code: doc.code }); + } } async createTranscript(messages: Message[], interaction: MessageComponentInteraction | CommandInteraction, member: GuildMember) {