diff --git a/src/plugins/bypassdnd/index.tsx b/src/plugins/bypassdnd/index.tsx
new file mode 100644
index 000000000..1a826a6e1
--- /dev/null
+++ b/src/plugins/bypassdnd/index.tsx
@@ -0,0 +1,155 @@
+import { NavContextMenuPatchCallback, addContextMenuPatch, removeContextMenuPatch } from "@api/ContextMenu";
+import { showNotification } from "@api/Notifications";
+import { definePluginSettings } from "@api/Settings";
+import { DataStore } from "@api/index";
+import { Devs } from "@utils/constants";
+import definePlugin, { OptionType } from "@utils/types";
+import { ChannelStore, Menu, PrivateChannelsStore, UserStore } from "@webpack/common";
+import { Channel, Guild, Message, User } from "discord-types/general";
+interface ContextProps {
+ channel: Channel;
+ user: User;
+ guild: Guild;
+}
+
+interface IMessageCreate {
+ type: "MESSAGE_CREATE";
+ optimistic: boolean;
+ isPushNotification: boolean;
+ channelId: string;
+ guildId: string;
+ message: Message;
+}
+
+const GuildContext: NavContextMenuPatchCallback = (children, { guild }: ContextProps) => () => {
+ if (!guild) return;
+ children.splice(-1, 0, (
+
+ {
+ if (bypasses["guilds"].includes(guild.id)) bypasses["guilds"] = await bypasses["guilds"].filter(id => id !== guild.id);
+ else bypasses["guilds"].push(guild.id);
+ await DataStore.set("bypassdnd", bypasses);
+ settings.store.guilds = (bypasses["guilds"].join(', '));
+ }}
+ />
+
+ ));
+};
+
+const ChannelContext: NavContextMenuPatchCallback = (children, { channel }: ContextProps) => () => {
+ if (!channel) return;
+ children.splice(-1, 0, (
+
+ {
+ if (bypasses["channels"].includes(channel.id)) bypasses["channels"] = await bypasses["channels"].filter(id => id !== channel.id);
+ else bypasses["channels"].push(channel.id);
+ await DataStore.set("bypassdnd", bypasses);
+ settings.store.channels = (bypasses["channels"].join(', '));
+ }}
+ />
+
+ ));
+};
+
+const UserContext: NavContextMenuPatchCallback = (children, { user }: ContextProps) => () => {
+ if (!user) return;
+ children.splice(-1, 0, (
+
+ {
+ if (bypasses["users"].includes(user.id)) bypasses["users"] = await bypasses["users"].filter(id => id !== user.id);
+ else bypasses["users"].push(user.id);
+ await DataStore.set("bypassdnd", bypasses);
+ settings.store.users = (bypasses["users"].join(', '));
+ }}
+ />
+
+ ));
+};
+
+let bypasses;
+
+const settings = definePluginSettings({
+ guilds: {
+ type: OptionType.STRING,
+ description: "Guilds to let bypass (notified when pinged anywhere in guild)",
+ default: "",
+ placeholder: "Separate with commas",
+ onChange: async function (value) {
+ bypasses["guild"] = value.replace(/\s/g, '').split(',').filter(id => id.trim() !== '');
+ await DataStore.set("bypassdnd", bypasses);
+ },
+ },
+ channels: {
+ type: OptionType.STRING,
+ description: "Channels to let bypass (notified when pinged in that channel)",
+ default: "",
+ placeholder: "Separate with commas",
+ onChange: async function (value) {
+ bypasses["channels"] = value.replace(/\s/g, '').split(',').filter(id => id.trim() !== '');
+ await DataStore.set("bypassdnd", bypasses);
+ },
+ },
+ users: {
+ type: OptionType.STRING,
+ description: "Users to let bypass (notified for all messages)",
+ default: "",
+ placeholder: "Separate with commas",
+ onChange: async function (value) {
+ bypasses["users"] = value.replace(/\s/g, '').split(',').filter(id => id.trim() !== '');
+ await DataStore.set("bypassdnd", bypasses);
+ },
+ }
+});
+
+export default definePlugin({
+ name: "BypassDND",
+ description: "Still get notifications from specific sources.",
+ authors: [Devs.Inbestigator],
+ flux: {
+ async MESSAGE_CREATE({ optimistic, type, message, guildId, channelId }: IMessageCreate) {
+ if (optimistic || type !== "MESSAGE_CREATE") return;
+ if (message.state === "SENDING") return;
+ if (message.author.id === UserStore.getCurrentUser().id) return;
+ if (!message.content) return;
+
+ const { guilds, channels, users } = bypasses;
+ if ((guilds.includes(guildId) || channels.includes(channelId)) && (message.content.includes(`<@${UserStore.getCurrentUser().id}>`) || message.mentions.some(mention => mention.id === UserStore.getCurrentUser().id))) {
+ await showNotification({
+ title: `${message.author.username} sent a message in ${ChannelStore.getChannel(channelId).name}`,
+ body: message.content,
+ onClick: () => window.location.href = `https://discord.com/channels/${guildId}/${channelId}/${message.id}`
+ });
+ return;
+ }
+ if (users.includes(message.author.id) && channelId === await PrivateChannelsStore.getOrEnsurePrivateChannel(message.author.id)) {
+ await showNotification({
+ title: `${message.author.username} sent a message in a DM`,
+ body: message.content,
+ onClick: () => window.location.href = `https://discord.com/channels/@me/${channelId}/${message.id}`
+ });
+ }
+ }
+ },
+ settings,
+ async start() {
+ addContextMenuPatch("guild-context", GuildContext);
+ addContextMenuPatch("channel-context", ChannelContext);
+ addContextMenuPatch("user-context", UserContext);
+ bypasses = await DataStore.get("bypassdnd") ?? { guilds: [], channels: [], users: [] };
+ await DataStore.set("bypassdnd", bypasses);
+ },
+ stop() {
+ removeContextMenuPatch("guild-context", GuildContext);
+ removeContextMenuPatch("channel-context", ChannelContext);
+ removeContextMenuPatch("user-context", UserContext);
+ }
+});
diff --git a/src/plugins/encryptcord/index.tsx b/src/plugins/encryptcord/index.tsx
deleted file mode 100644
index d3e247026..000000000
--- a/src/plugins/encryptcord/index.tsx
+++ /dev/null
@@ -1,457 +0,0 @@
-import { addChatBarButton, ChatBarButton } from "@api/ChatButtons";
-import { removeButton } from "@api/MessagePopover";
-import definePlugin 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, FluxDispatcher, PrivateChannelsStore } from "@webpack/common";
-import { generateKeys, encryptData, decryptData, formatPemKey } from "./rsa-utils";
-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 { getCurrentChannel, openPrivateChannel } from "@utils/discord";
-
-let enabled;
-let setEnabled;
-
-// Interface for Message Create
-interface IMessageCreate {
- type: "MESSAGE_CREATE";
- optimistic: boolean;
- isPushNotification: boolean;
- channelId: string;
- message: Message;
-}
-
-// Chat Bar Icon Component
-const ChatBarIcon: ChatBarButton = ({ isMainChat }) => {
- [enabled, setEnabled] = useState(false);
- let [buttonDisabled, setButtonDisabled] = 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 = await encryptData(encryptcordGroupMembers[memberId].key, trimmedMessage);
- 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 (
- {
- if (await DataStore.get('encryptcordGroup') == false || (await DataStore.get('encryptcordChannelId') != getCurrentChannel().id)) {
- setButtonDisabled(true);
- await sendTempMessage(getCurrentChannel().id, "", `join\`\`\`\n${await DataStore.get("encryptcordPublicKey")}\`\`\``, false);
- sendBotMessage(getCurrentChannel().id, { content: `*Checking for any groups in this channel...*\n> If none is found, a new one will be created \n> [Tip] You can do \`/encryptcord leave\` to leave a group` });
- await sleep(5000);
- if (await DataStore.get('encryptcordGroup') == true && (await DataStore.get('encryptcordChannelId') != getCurrentChannel().id)) {
- sendBotMessage(getCurrentChannel().id, { content: "*Leaving current group...*" });
- await leave("", { channel: { id: await DataStore.get('encryptcordChannelId') } });
- } else if (await DataStore.get('encryptcordGroup') == true) {
- setButtonDisabled(false);
- return;
- };
- await startGroup("", { channel: { id: getCurrentChannel().id } });
- }
- setEnabled(!enabled);
- setButtonDisabled(false);
- }}
- buttonProps={{
- style: {
- transition: 'transform 0.3s ease-in-out',
- transform: `rotate(${enabled ? 0 : 15}deg)`,
- },
- disabled: buttonDisabled
- }}
- >
-
-
- );
-};
-
-// 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: 'await $self.joinGroup(C);$&'
- }
- }
- ],
- async joinGroup(interaction) {
- const sender = await UserUtils.getUser(interaction.application_id).catch(() => null);
- if (!sender || (sender.bot == true && sender.id != "1")) return;
- if (interaction.data.component_type != 2) return;
- switch (interaction.data.custom_id) {
- case "removeFromSelf":
- await handleLeaving(sender.id, await DataStore.get("encryptcordGroupMembers") ?? {}, interaction.channel_id);
- await sendTempMessage(sender.id, "", "leaving");
- FluxDispatcher.dispatch({
- type: "MESSAGE_DELETE",
- channelId: interaction.channel_id,
- id: interaction.message_id,
- mlDeleted: true
- });
- break;
- case "createGroup":
- await leave("", { channel: { id: interaction.channel_id } });
- await startGroup("", { channel: { id: interaction.channel_id } });
- break;
- default:
- return;
- }
- },
- flux: {
- async MESSAGE_CREATE({ optimistic, type, message, channelId }: IMessageCreate) {
- if (optimistic || type !== "MESSAGE_CREATE") return;
- if (message.state === "SENDING") return;
- if (message.author.id == UserStore.getCurrentUser().id) return;
- if (!message.content) return;
- const encryptcordGroupMembers = await DataStore.get('encryptcordGroupMembers');
- if (!Object.keys(encryptcordGroupMembers).some(key => key == message.author.id)) {
- switch (message.content.toLowerCase().split("```")[0]) {
- case "groupdata":
- const response = await fetch(message.attachments[0].url);
- const groupdata = await response.json();
- await handleGroupData(groupdata);
- break;
- case "join":
- if (encryptcordGroupMembers[UserStore.getCurrentUser().id].child) return;
- if (!await DataStore.get("encryptcordGroup")) return;
- const sender = await UserUtils.getUser(message.author.id).catch(() => null);
- if (!sender) return;
- const userKey = message.content.split("```")[1];
- await handleJoin(sender.id, userKey, encryptcordGroupMembers);
- break;
- default:
- break;
- }
- return;
- }
- const dmChannelId = await PrivateChannelsStore.getOrEnsurePrivateChannel(message.author.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 msgResponse = await fetch(message.attachments[0].url);
- const messagedata = await msgResponse.json();
- await handleMessage(messagedata, sender.id, groupChannel);
- break;
- case "groupdata":
- const response = await fetch(message.attachments[0].url);
- const groupdata = await response.json();
- 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: "data",
- description: "View your keys and current group members",
- options: [],
- type: ApplicationCommandOptionType.SUB_COMMAND,
- },
- ],
- inputType: ApplicationCommandInputType.BOT,
- execute: (opts, ctx) => {
- switch (opts[0].name) {
- case "start":
- startGroup(opts[0].options, ctx);
- break;
- case "leave":
- leave(opts[0].options, ctx);
- break;
- case "data":
- data(opts[0].options, ctx);
- break;
- }
- },
- },
- ],
- async start() {
- addChatBarButton("Encryptcord", ChatBarIcon);
- const pair = await generateKeys();
- 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', {});
- },
- async stop() {
- removeButton("Encryptcord");
- if (await DataStore.get("encryptcordGroup") == true) {
- await leave("", { channel: { id: await DataStore.get("encryptcordChannelId") } });
- }
- },
-});
-
-// Send Temporary Message
-async function sendTempMessage(recipientId: string, attachment: string, content: string, dm: boolean = true) {
- if (recipientId == UserStore.getCurrentUser().id) return;
- const dmChannelId = dm ? await PrivateChannelsStore.getOrEnsurePrivateChannel(recipientId) : recipientId;
- 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];
- if (result[memberId].child == senderId) {
- result[memberId].child = encryptcordGroupMembers[senderId].child;
- }
- if (result[memberId].parent == senderId) {
- result[memberId].parent = encryptcordGroupMembers[senderId].parent;
- }
- }
- 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 = await decryptData(await DataStore.get("encryptcordPrivateKey"), message);
- 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) {
- encryptcordGroupMembers[senderId] = { key: senderKey, parent: UserStore.getCurrentUser().id, child: null };
- encryptcordGroupMembers[UserStore.getCurrentUser().id].child = senderId;
- 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), components: [{
- type: 1,
- components: [{
- type: 2,
- style: 4,
- label: 'I don\'t want to talk to you!',
- custom_id: 'removeFromSelf'
- },
- {
- type: 2,
- style: 2,
- label: '(Other users can still send/receive messages to/from them)',
- disabled: true,
- custom_id: 'encryptcord'
- }]
- }]
- });
-}
-
-// 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]: { key: await DataStore.get("encryptcordPublicKey"), parent: null, child: null }
- });
- await DataStore.set('encryptcordGroup', true);
- sendBotMessage(channelId, { content: "Group created!\n> Other users can click the lock icon to join." });
- await MessageActions.receiveMessage(channelId, await createMessage("", UserStore.getCurrentUser().id, channelId, 7));
- setEnabled(true);
-}
-
-// 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 MessageActions.receiveMessage(channelId, await createMessage("", user.id, channelId, 2));
- setEnabled(false);
-}
-
-// View user data
-async function data(opts, ctx) {
- const channelId = ctx.channel.id;
- const encryptcordGroupMembers = await DataStore.get('encryptcordGroupMembers');
- const encryptcordPublicKey = await DataStore.get('encryptcordPublicKey');
- const encryptcordPrivateKey = await DataStore.get('encryptcordPrivateKey');
- const exportedPrivateKey = await crypto.subtle.exportKey("pkcs8", encryptcordPrivateKey);
- const groupMembers = Object.keys(encryptcordGroupMembers);
- sendBotMessage(channelId, {
- content: `## Public key:\n\`\`\`${encryptcordPublicKey}\`\`\`\n## Private key:\n||\`\`\`${formatPemKey(exportedPrivateKey, "private")}\`\`\`||*(DO **NOT** SHARE THIS)*\n## Group members:\n\`\`\`json\n${JSON.stringify(groupMembers)}\`\`\``
- });
-}
-
diff --git a/src/plugins/encryptcord/rsa-utils.tsx b/src/plugins/encryptcord/rsa-utils.tsx
deleted file mode 100644
index 80e3ca35f..000000000
--- a/src/plugins/encryptcord/rsa-utils.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-export const generateKeys = async () => {
- const keyPair = await crypto.subtle.generateKey(
- {
- name: "RSA-OAEP",
- modulusLength: 4096,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: "SHA-256",
- },
- true,
- ["encrypt", "decrypt"]
- );
-
- const exportedPublicKey = await crypto.subtle.exportKey("spki", keyPair.publicKey);
- const publicKey = formatPemKey(exportedPublicKey, "public");
-
- return { privateKey: keyPair.privateKey, publicKey };
-};
-
-export const encryptData = async (pemPublicKey, data) => {
- const publicKey = await importPemPublicKey(pemPublicKey);
-
- const chunkSize = 446;
-
- const encryptedChunks: any[] = [];
- const encoder = new TextEncoder();
-
- for (let i = 0; i < data.length; i += chunkSize) {
- const chunk = await data.substring(i, i + chunkSize);
- const encryptedChunk = await crypto.subtle.encrypt(
- {
- name: "RSA-OAEP",
- },
- publicKey,
- encoder.encode(chunk)
- );
- encryptedChunks.push(arrayBufferToBase64(encryptedChunk));
- }
-
- return encryptedChunks;
-};
-
-export const decryptData = async (privateKey, encArray) => {
- const decryptionPromises = encArray.map(async (encStr) => {
- const encBuffer = base64ToArrayBuffer(encStr);
-
- const dec = await crypto.subtle.decrypt(
- {
- name: "RSA-OAEP",
- },
- privateKey,
- encBuffer
- );
-
- return new TextDecoder().decode(dec);
- });
-
- const decryptedMessages = await Promise.all(decryptionPromises);
-
- return decryptedMessages.join('');
-};
-
-// Helper functions
-const arrayBufferToBase64 = (buffer) => {
- const binary = String.fromCharCode(...new Uint8Array(buffer));
- return btoa(binary);
-};
-
-const base64ToArrayBuffer = (base64String) => {
- const binaryString = atob(base64String);
- const length = binaryString.length;
- const buffer = new ArrayBuffer(length);
- const view = new Uint8Array(buffer);
-
- for (let i = 0; i < length; i++) {
- view[i] = binaryString.charCodeAt(i);
- }
-
- return buffer;
-};
-
-export const formatPemKey = (keyData, type) => {
- const base64Key = arrayBufferToBase64(keyData);
- return `-----BEGIN ${type.toUpperCase()} KEY-----\n` + base64Key + `\n-----END ${type.toUpperCase()} KEY----- `;
-};
-
-const importPemPublicKey = async (pemKey) => {
- try {
- const trimmedPemKey = pemKey.trim();
-
- const keyBody = trimmedPemKey
- .replace("-----BEGIN PUBLIC KEY-----", "")
- .replace("-----END PUBLIC KEY-----", "");
-
- const binaryDer = atob(keyBody);
-
- const arrayBuffer = new Uint8Array(binaryDer.length);
- for (let i = 0; i < binaryDer.length; i++) {
- arrayBuffer[i] = binaryDer.charCodeAt(i);
- }
-
- return await crypto.subtle.importKey(
- "spki",
- arrayBuffer,
- {
- name: "RSA-OAEP",
- hash: { name: "SHA-256" },
- },
- true,
- ["encrypt"]
- );
- } catch (error) {
- console.error("Error importing PEM public key:", error);
- throw error;
- }
-};
-