Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encrypted user vector #70

Merged
merged 4 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions commands/test/test-command.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 },
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
31 changes: 31 additions & 0 deletions encryptionUtils.ts
Original file line number Diff line number Diff line change
@@ -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();
}
8 changes: 5 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -91,19 +92,20 @@ 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);
else if (buttonId === 'disagree') userResponses.push(-1);
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
}
}
);
Expand Down