From a31e2d4cedeaca576b1ff1ead535ce9aa3850c50 Mon Sep 17 00:00:00 2001 From: Inbestigator <119569726+Inbestigator@users.noreply.github.com> Date: Thu, 29 Feb 2024 01:50:23 -0800 Subject: [PATCH] Delete src/plugins/Encryptcord directory --- src/plugins/Encryptcord/index.tsx | 516 ------------------------------ 1 file changed, 516 deletions(-) delete mode 100644 src/plugins/Encryptcord/index.tsx diff --git a/src/plugins/Encryptcord/index.tsx b/src/plugins/Encryptcord/index.tsx deleted file mode 100644 index fdf365245..000000000 --- a/src/plugins/Encryptcord/index.tsx +++ /dev/null @@ -1,516 +0,0 @@ -import { addChatBarButton, ChatBarButton } from "@api/ChatButtons"; -import { removeButton } from "@api/MessagePopover"; -import definePlugin, { StartAt } from "@utils/types"; -import * as DataStore from "@api/DataStore"; -import { sleep } from "@utils/misc"; -import { findByPropsLazy } from "@webpack"; -import { addPreSendListener, removePreSendListener, SendListener } from "@api/MessageEvents"; -import { useEffect, useState } from "@webpack/common"; -import { Devs } from "@utils/constants"; -import { - RestAPI, - SnowflakeUtils, - UserUtils, - UserStore, - MessageActions, -} from "@webpack/common"; -import { - ApplicationCommandInputType, - sendBotMessage, - ApplicationCommandOptionType, - findOption, -} from "@api/Commands"; -import { Message } from "discord-types/general"; -const MessageCreator = findByPropsLazy("createBotMessage"); -const CloudUtils = findByPropsLazy("CloudUpload"); -import axios from 'axios'; -import { getCurrentChannel } from "@utils/discord"; -import forge from 'node-forge'; - -let enabled; -let setEnabled; - -// Interface for Message Create -interface IMessageCreate { - type: "MESSAGE_CREATE"; - optimistic: boolean; - isPushNotification: boolean; - channelId: string; - message: Message; -} - -// Generate RSA key pair -function generateKeyPair(): { privateKey: string; publicKey: string; } { - const keys = forge.pki.rsa.generateKeyPair({ bits: 2048 }); - const privateKey = forge.pki.privateKeyToPem(keys.privateKey); - const publicKey = forge.pki.publicKeyToPem(keys.publicKey); - - return { privateKey, publicKey }; -} - -// Encrypt message with public key -function encrypt(message: string, publicKey): string[] { - try { - const publicKeyObj = forge.pki.publicKeyFromPem(publicKey); - const chunkSize = 190; - - const emojiRegex = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g; - message = message.replace(emojiRegex, ''); - - const encryptedChunks: string[] = []; - - for (let i = 0; i < message.length; i += chunkSize) { - const chunk = message.substring(i, i + chunkSize); - const encryptedChunk = publicKeyObj.encrypt(chunk, 'RSA-OAEP', { - md: forge.md.sha256.create(), - }); - encryptedChunks.push(forge.util.encode64(encryptedChunk)); - } - - return encryptedChunks; - } catch (error) { - return []; - } -} - -// Decrypt message with private key -function decrypt(encryptedMessages: string[], privateKey): string { - const privateKeyObj = forge.pki.privateKeyFromPem(privateKey); - let decryptedMessages: string[] = []; - - encryptedMessages.forEach((encryptedMessage) => { - const encrypted = forge.util.decode64(encryptedMessage); - const decrypted = privateKeyObj.decrypt(encrypted, 'RSA-OAEP', { - md: forge.md.sha256.create(), - }); - decryptedMessages.push(decrypted); - }); - - return decryptedMessages.join(''); -} - -// Chat Bar Icon Component -const ChatBarIcon: ChatBarButton = ({ isMainChat }) => { - [enabled, setEnabled] = useState(false); - - useEffect(() => { - const listener: SendListener = async (_, message) => { - if (enabled) { - const groupChannel = await DataStore.get('encryptcordChannelId'); - if (getCurrentChannel().id !== groupChannel) { - sendBotMessage(getCurrentChannel().id, { content: `You must be in <#${groupChannel}> to send an encrypted message!\n> If you wish to send an unencrypted message, please click the button in the chatbar.` }); - message.content = ""; - return; - } - const trimmedMessage = message.content.trim(); - await MessageActions.receiveMessage(groupChannel, await createMessage(trimmedMessage, UserStore.getCurrentUser().id, groupChannel, 0)); - const encryptcordGroupMembers = await DataStore.get('encryptcordGroupMembers'); - const dmPromises = Object.keys(encryptcordGroupMembers).map(async (memberId) => { - const groupMember = await UserUtils.getUser(memberId).catch(() => null); - if (!groupMember) return; - const encryptedMessage = encrypt(trimmedMessage, encryptcordGroupMembers[memberId]); - const encryptedMessageString = JSON.stringify(encryptedMessage); - await sendTempMessage(groupMember.id, encryptedMessageString, `message`); - }); - - await Promise.all(dmPromises); - message.content = ""; - } - }; - - addPreSendListener(listener); - return () => void removePreSendListener(listener); - }, [enabled]); - - if (!isMainChat) return null; - - return ( - { - const groupChannel = await DataStore.get('encryptcordChannelId'); - if (await DataStore.get('encryptcordGroup') == false) { - sendBotMessage(getCurrentChannel().id, { content: `You must be in an E2EE group to send an encrypted message!` }); - return; - } - if (getCurrentChannel().id !== groupChannel) { - sendBotMessage(getCurrentChannel().id, { content: `You must be in the E2EE group channel to send an encrypted message!` }); - return; - } - setEnabled(!enabled); - }} - buttonProps={{ - "aria-haspopup": "dialog", - }} - > - - {!enabled && <> - - - - - } - - - - ); -}; - -// Export Plugin -export default definePlugin({ - name: "Encryptcord", - description: "End-to-end encryption in Discord!", - authors: [Devs.Inbestigator], - dependencies: ["CommandsAPI"], - patches: [ - { - find: "executeMessageComponentInteraction:", - replacement: { - match: /await\s+l\.default\.post\({\s*url:\s*A\.Endpoints\.INTERACTIONS,\s*body:\s*C,\s*timeout:\s*3e3\s*},\s*t\s*=>\s*{\s*h\(T,\s*p,\s*f,\s*t\)\s*}\s*\)/, - replace: 'if(await $self.joinGroup(C))return;$&' - } - } - ], - async joinGroup(interaction) { - const sender = await UserUtils.getUser(interaction.application_id).catch(() => null); - if (!sender || sender.bot == true) return false; - if (interaction.data.component_type == 2 && interaction.data.custom_id == "acceptGroup") { - await sendTempMessage(interaction.application_id, `${await DataStore.get("encryptcordPublicKey")}`, "join"); - } - return true; - }, - flux: { - async MESSAGE_CREATE({ optimistic, type, message, channelId }: IMessageCreate) { - if (optimistic || type !== "MESSAGE_CREATE") return; - if (message.state === "SENDING") return; - if (!message.content) return; - const encryptcordGroupMembers = await DataStore.get('encryptcordGroupMembers'); - if (!Object.keys(encryptcordGroupMembers).some(key => key == message.author.id)) { - const encryptcordGroupJoinList = await DataStore.get('encryptcordGroupJoinList'); - if (!encryptcordGroupJoinList.includes(message.author.id)) { - switch (message.content.split("/")[0].toLowerCase()) { - case "e2eeinvite": - const inviteMessage = `I've invited you to an [end-to-end encrypted]() group in <#${message.content.split("/")[1]}>.`; - await MessageActions.receiveMessage(channelId, { - ...await createMessage(inviteMessage, message.author.id, channelId, 0), components: [{ - type: 1, - components: [{ - type: 2, - style: 3, - label: 'Accept!', - custom_id: 'acceptGroup' - }] - }] - }); - break; - case "groupdata": - const groupdata = (await axios.get(message.attachments[0].url)).data; - await handleGroupData(groupdata); - break; - default: - break; - } - return; - }; - if (message.content.toLowerCase() !== "join") return; - const sender = await UserUtils.getUser(message.author.id).catch(() => null); - if (!sender) return; - const userKey = (await axios.get(message.attachments[0].url)).data; - await handleJoin(sender.id, userKey, encryptcordGroupMembers); - return; - } - const dmChannelId = await RestAPI.post({ - url: `/users/@me/channels`, - body: { - recipient_id: message.author.id, - }, - }).then((response) => response.body.id); - if (channelId !== dmChannelId) return; - const sender = await UserUtils.getUser(message.author.id).catch(() => null); - if (!sender) return; - const groupChannel = await DataStore.get('encryptcordChannelId'); - switch (message.content.toLowerCase()) { - case "leaving": - handleLeaving(sender.id, encryptcordGroupMembers, groupChannel); - break; - case "message": - const messagedata = (await axios.get(message.attachments[0].url)).data; - await handleMessage(messagedata, sender.id, groupChannel); - break; - case "groupdata": - const groupdata = (await axios.get(message.attachments[0].url)).data; - await handleGroupData(groupdata); - break; - default: - break; - } - }, - }, - commands: [ - { - name: "encryptcord", - description: "End-to-end encryption in Discord!", - options: [ - { - name: "leave", - description: "Leave current group", - options: [], - type: ApplicationCommandOptionType.SUB_COMMAND, - }, - { - name: "start", - description: "Start an E2EE group", - options: [], - type: ApplicationCommandOptionType.SUB_COMMAND, - }, - { - name: "invite", - description: "Invite a user to your group", - options: [ - { - name: "user", - description: "Who to invite", - required: true, - type: ApplicationCommandOptionType.USER, - }, - ], - type: ApplicationCommandOptionType.SUB_COMMAND, - }, - ], - inputType: ApplicationCommandInputType.BOT, - execute: (opts, ctx) => { - switch (opts[0].name) { - case "start": - startGroup(opts[0].options, ctx); - break; - case "invite": - invite(opts[0].options, ctx); - break; - case "leave": - leave(opts[0].options, ctx); - break; - } - }, - }, - ], - startAt: StartAt.DOMContentLoaded, - async start() { - addChatBarButton("Encryptcord", ChatBarIcon); - const pair = generateKeyPair(); - await DataStore.set('encryptcordPublicKey', pair.publicKey); - await DataStore.set('encryptcordPrivateKey', pair.privateKey); - if (await DataStore.get("encryptcordGroup") == true) { - await leave("", { channel: { id: await DataStore.get("encryptcordChannelId") } }); - } - await DataStore.set('encryptcordGroup', false); - await DataStore.set('encryptcordChannelId', ""); - await DataStore.set('encryptcordGroupMembers', {}); - await DataStore.set('encryptcordGroupJoinList', []); - }, - stop() { - removeButton("Encryptcord"); - }, -}); - -// Send Temporary Message -async function sendTempMessage(recipientId: string, attachment: string, content: string) { - if (recipientId == UserStore.getCurrentUser().id) return; - - const dmChannelId = await RestAPI.post({ - url: `/users/@me/channels`, - body: { - recipient_id: recipientId, - }, - }).then((response) => response.body.id); - - if (attachment && attachment != "") { - const upload = await new CloudUtils.CloudUpload({ - file: new File([new Blob([attachment])], "file.text", { type: "text/plain; charset=utf-8" }), - isClip: false, - isThumbnail: false, - platform: 1, - }, dmChannelId, false, 0); - upload.on("complete", async () => { - const messageId = await RestAPI.post({ - url: `/channels/${dmChannelId}/messages`, - body: { - content, - attachments: [{ - id: "0", - filename: upload.filename, - uploaded_filename: upload.uploadedFilename, - }], - nonce: SnowflakeUtils.fromTimestamp(Date.now()), - }, - }).then((response) => response.body.id); - - await sleep(500); - RestAPI.delete({ - url: `/channels/${dmChannelId}/messages/${messageId}` - }); - }); - await upload.upload(); - return; - } - - const messageId = await RestAPI.post({ - url: `/channels/${dmChannelId}/messages`, - body: { - content, - nonce: SnowflakeUtils.fromTimestamp(Date.now()), - }, - }).then((response) => response.body.id); - - await sleep(500); - RestAPI.delete({ - url: `/channels/${dmChannelId}/messages/${messageId}` - }); -} - -// Handle leaving group -async function handleLeaving(senderId: string, encryptcordGroupMembers: object, groupChannel: string) { - const updatedMembers = Object.keys(encryptcordGroupMembers).reduce((result, memberId) => { - if (memberId !== senderId) { - result[memberId] = encryptcordGroupMembers[memberId]; - } - return result; - }, {}); - - await DataStore.set('encryptcordGroupMembers', updatedMembers); - - await MessageActions.receiveMessage(groupChannel, await createMessage("", senderId, groupChannel, 2)); -} - -// Handle receiving message -async function handleMessage(message, senderId: string, groupChannel: string) { - const decryptedMessage = decrypt(message, await DataStore.get("encryptcordPrivateKey")); - await MessageActions.receiveMessage(groupChannel, await createMessage(decryptedMessage, senderId, groupChannel, 0)); -} - -// Handle receiving group data -async function handleGroupData(groupData) { - await DataStore.set('encryptcordChannelId', groupData.channel); - await DataStore.set('encryptcordGroupMembers', groupData.members); - await DataStore.set('encryptcordGroup', true); - await MessageActions.receiveMessage(groupData.channel, await createMessage("", UserStore.getCurrentUser().id, groupData.channel, 7)); - setEnabled(true); -} - -// Handle joining group -async function handleJoin(senderId: string, senderKey: string, encryptcordGroupMembers: object) { - const encryptcordGroupJoinList = await DataStore.get('encryptcordGroupJoinList'); - const updatedMembers = encryptcordGroupJoinList.filter(memberId => memberId !== senderId); - await DataStore.set('encryptcordGroupJoinList', updatedMembers); - - encryptcordGroupMembers[senderId] = senderKey; - await DataStore.set('encryptcordGroupMembers', encryptcordGroupMembers); - const groupChannel = await DataStore.get('encryptcordChannelId'); - const newMember = await UserUtils.getUser(senderId).catch(() => null); - if (!newMember) return; - - const membersData = {}; - Object.entries(encryptcordGroupMembers) - .forEach(([memberId, value]) => { - membersData[memberId] = value; - }); - - const membersDataString = JSON.stringify({ members: membersData, channel: groupChannel }); - - const dmPromises = Object.keys(encryptcordGroupMembers).map(async (memberId) => { - const groupMember = await UserUtils.getUser(memberId).catch(() => null); - if (!groupMember) return; - await sendTempMessage(groupMember.id, membersDataString, `groupdata`); - }); - - await Promise.all(dmPromises); - await MessageActions.receiveMessage(groupChannel, await createMessage("", senderId, groupChannel, 7)); -} - -// Create message for group -async function createMessage(message: string, senderId: string, channelId: string, type: number) { - const messageStart = MessageCreator.createBotMessage({ channelId, content: "", embeds: [] }); - const sender = await UserUtils.getUser(senderId).catch(() => null); - if (!sender) return; - return { ...messageStart, content: message, author: sender, type, flags: 0 }; -} - -// Start E2EE Group -async function startGroup(opts, ctx) { - const channelId = ctx.channel.id; - await DataStore.set('encryptcordChannelId', channelId); - await DataStore.set('encryptcordGroupMembers', { - [UserStore.getCurrentUser().id]: await DataStore.get("encryptcordPublicKey") - }); - await DataStore.set('encryptcordGroupJoinList', []); - await DataStore.set('encryptcordGroup', true); - sendBotMessage(channelId, { content: "Group created!" }); - await MessageActions.receiveMessage(channelId, await createMessage("", UserStore.getCurrentUser().id, channelId, 7)); - setEnabled(true); -} - -// Invite User to Group -async function invite(opts, ctx) { - const invitedUser = await UserUtils.getUser(findOption(opts, "user", "")).catch(() => null); - if (!invitedUser) return; - - const channelId = ctx.channel.id; - if (!(await DataStore.get('encryptcordGroup'))) { - sendBotMessage(channelId, { content: `You're not in a group!` }); - return; - } - - const encryptcordGroupMembers = await DataStore.get('encryptcordGroupMembers'); - if (Object.keys(encryptcordGroupMembers).some(key => key == invitedUser.id)) { - sendBotMessage(channelId, { content: `<@${invitedUser.id}> is already in the group.` }); - return; - } - - const encryptcordGroupJoinList = await DataStore.get('encryptcordGroupJoinList'); - if (encryptcordGroupJoinList.includes(invitedUser.id)) { - sendBotMessage(channelId, { content: `<@${invitedUser.id}> is already in the join list.` }); - return; - } - - encryptcordGroupJoinList.push(invitedUser.id); - await DataStore.set('encryptcordGroupJoinList', encryptcordGroupJoinList); - - await sendTempMessage(invitedUser.id, "", `e2eeinvite/${await DataStore.get('encryptcordChannelId')}`); - - sendBotMessage(channelId, { content: `<@${invitedUser.id}> invited successfully.` }); -} - -// Leave the Group -async function leave(opts, ctx) { - const channelId = ctx.channel.id; - if (!(await DataStore.get('encryptcordGroup'))) { - sendBotMessage(channelId, { content: `You're not in a group!` }); - return; - } - const user = UserStore.getCurrentUser(); - const encryptcordGroupMembers = await DataStore.get('encryptcordGroupMembers'); - - const dmPromises = Object.keys(encryptcordGroupMembers).map(async (memberId) => { - const groupMember = await UserUtils.getUser(memberId).catch(() => null); - if (!groupMember) return; - await sendTempMessage(groupMember.id, "", `leaving`); - }); - - await Promise.all(dmPromises); - await DataStore.set('encryptcordGroup', false); - await DataStore.set('encryptcordChannelId', ""); - await DataStore.set('encryptcordGroupMembers', {}); - await DataStore.set('encryptcordGroupJoinList', []); - await MessageActions.receiveMessage(channelId, await createMessage("", user.id, channelId, 2)); - setEnabled(false); -}