diff --git a/commands/test/test-command.ts b/commands/test/test-command.ts index 998b9c1..7337e69 100644 --- a/commands/test/test-command.ts +++ b/commands/test/test-command.ts @@ -1,5 +1,6 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder, Guild, Role, User, TextChannel } from 'discord.js'; import { client, db } from '../../common'; +import { encrypt, decrypt } from '../../encryptionUtils'; import cron from 'cron'; import 'dotenv/config' @@ -170,7 +171,12 @@ export const sendQuestion = async (interaction: any) => { const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); let currentQuestionIndex = userContext?.currentQuestionIndex || 0; - let userResponses = userContext?.userVector || []; + let userResponses; + if (Array.isArray(userContext?.userVector)) { + userResponses = userContext?.userVector || []; + } else { + userResponses = userContext?.userVector ? JSON.parse(decrypt(userContext.userVector)) : []; + } var currentQuestionDisplay = currentQuestionIndex + 1 if (currentQuestionIndex === 0) { @@ -203,7 +209,7 @@ export const sendQuestion = async (interaction: any) => { components: [builder] }); - + const encryptedUserVector = encrypt(JSON.stringify(userResponses)); // Update context for this user in the database await db.db('contrabot').collection("users").updateOne( { userId: interaction.user.id }, @@ -213,7 +219,7 @@ export const sendQuestion = async (interaction: any) => { username: interaction.user.username, currentQuestionIndex: currentQuestionIndex + 1, - userVector: userResponses, + userVector: encryptedUserVector, feedbackRequestSent: false, currentFeedbackQuestionIndex: 0, invited: interaction.user.invited, @@ -366,21 +372,41 @@ async function findMatchingUser(userId: string, userResponses: number[], guild: continue; } - if (!Array.isArray(user.userVector) || user.userVector.length === 0) { - console.log(`Skipped: Missing or invalid userVector for userId ${user.userId}`); + let decryptedUserVector: number[]; // Explicit type declaration + if (typeof user.userVector === 'string') { // Check if it's a string + try { + decryptedUserVector = JSON.parse(decrypt(user.userVector)); + } catch (error) { + console.error(`Failed to decrypt userVector for userId ${user.userId}:`, error); + continue; + } + } else { + console.warn(`Skipped: userVector for userId ${user.userId} is not a string`); + continue; + } + + + if (!Array.isArray(decryptedUserVector) || decryptedUserVector.length === 0) { + console.log(`Skipped: Missing or invalid decrypted userVector for userId ${user.userId}`); continue; } const differenceScore = userResponses.reduce((acc, value, index) => { - return acc + value * user.userVector[index]; + return acc + value * decryptedUserVector[index]; }, 0); if (differenceScore < lowestDifferenceScore) { lowestDifferenceScore = differenceScore; - mostOppositeUser = { userId: user.userId, username: user.username, userVector: user.userVector, GuildMember: null }; + mostOppositeUser = { + userId: user.userId, + username: user.username, + userVector: decryptedUserVector, + GuildMember: null + }; } } + if (mostOppositeUser) { const isMember = await guild.members.fetch(mostOppositeUser.userId).then(() => true).catch(() => false); if (!isMember) { diff --git a/encryptionUtils.ts b/encryptionUtils.ts new file mode 100644 index 0000000..ef301cf --- /dev/null +++ b/encryptionUtils.ts @@ -0,0 +1,31 @@ +import crypto from 'crypto'; +import 'dotenv/config'; + +const IV_LENGTH = 16; // AES block size +const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // Must be 256 bits (32 characters) + +if (!ENCRYPTION_KEY) { + throw new Error("Missing ENCRYPTION_KEY in .env file."); +} + +export const encrypt = (text: string): string => { + let iv = crypto.randomBytes(IV_LENGTH); + let cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(ENCRYPTION_KEY), iv); + let encrypted = cipher.update(text); + + encrypted = Buffer.concat([encrypted, cipher.final()]); + + return iv.toString('hex') + ':' + encrypted.toString('hex'); +} + +export const decrypt = (text: string): string => { + let textParts = text.split(':'); + let iv = Buffer.from(textParts.shift()!, 'hex'); + let encryptedText = Buffer.from(textParts.join(':'), 'hex'); + let decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(ENCRYPTION_KEY), iv); + let decrypted = decipher.update(encryptedText); + + decrypted = Buffer.concat([decrypted, decipher.final()]); + + return decrypted.toString(); +} \ No newline at end of file diff --git a/index.ts b/index.ts index 9193a5e..9b14bbf 100644 --- a/index.ts +++ b/index.ts @@ -1,6 +1,7 @@ import 'dotenv/config' import { Events } from 'discord.js'; -import { sendQuestion, sendTestButton } from './commands/test/test-command'; +import { sendQuestion } from './commands/test/test-command'; +import { encrypt, decrypt } from './encryptionUtils'; import { sendSurveyQuestions, Feedbackquestions } from './startSurvey'; import * as fs from 'fs'; import path from 'path' @@ -91,7 +92,7 @@ client.on(Events.InteractionCreate, async (interaction) => { // Fetch user's context from the database const userContext = await db.db('contrabot').collection("users").findOne({ userId: interaction.user.id }); - const userResponses = userContext?.userVector || []; + const userResponses = userContext?.userVector ? JSON.parse(decrypt(userContext.userVector)) : []; // Update the userResponses based on button clicked if (buttonId === 'agree') userResponses.push(1); @@ -99,11 +100,12 @@ client.on(Events.InteractionCreate, async (interaction) => { else if (buttonId === 'neutral') userResponses.push(0); // Update the userResponses for this user in the database + const encryptedUserVector = encrypt(JSON.stringify(userResponses)); await db.db('contrabot').collection("users").updateOne( { userId: interaction.user.id }, { $set: { - userVector: userResponses + userVector: encryptedUserVector } } );