/* * Vencord, a modification for Discord's desktop app * Copyright (c) 2022 Vendicated and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import { addMessagePopoverButton, removeMessagePopoverButton } from "@api/MessagePopover"; import { definePluginSettings } from "@api/Settings"; import { CodeBlock } from "@components/CodeBlock"; import ErrorBoundary from "@components/ErrorBoundary"; import { Flex } from "@components/Flex"; import { EquicordDevs } from "@utils/constants"; import { copyWithToast } from "@utils/misc"; import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; import definePlugin, { OptionType } from "@utils/types"; import { Button, ChannelStore, Forms, Text } from "@webpack/common"; const DecodeIcon = () => { return ( ); }; function isValidUtf8String(str) { try { new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array(str.split("").map(char => char.charCodeAt(0)))); return true; } catch (e) { return false; } } function findBase64Strings(content) { const base64Regex = /\b[A-Za-z0-9+/]{4,}(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?\b/g; const matches = content.match(base64Regex); return matches || []; } function decodeBase64Strings(base64Strings) { return base64Strings.map(base64 => { try { const decoded = atob(base64); return isValidUtf8String(decoded) ? decoded : null; } catch (e) { console.error("Failed to decode base64 content:", e); return null; } }).filter(decoded => decoded !== null); } function openDecodedBase64Modal(decodedContent) { const key = openModal(props => ( Decoded Base64 Content closeModal(key)} />
Decoded Content {decodedContent.map((content, index) => ( ))}
{decodedContent.map((content, index) => ( ))}
)); } const settings = definePluginSettings({ clickMethod: { description: "Change the button to decode base64 content of any message.", type: OptionType.SELECT, options: [ { label: "Left Click to decode the base64 content.", value: "Left", default: true }, { label: "Right click to decode the base64 content.", value: "Right" } ] } }); export default definePlugin({ name: "DecodeBase64", description: "Decode base64 content of any message and copy the decoded content.", authors: [EquicordDevs.ThePirateStoner], dependencies: ["MessagePopoverAPI"], settings, contextMenus: { }, start() { addMessagePopoverButton("DecodeBase64", msg => { const handleClick = () => { const base64Strings = findBase64Strings(msg.content); const decodedContent = decodeBase64Strings(base64Strings); if (settings.store.clickMethod === "Right") { decodedContent.forEach(content => copyWithToast(content)); } else { openDecodedBase64Modal(decodedContent); } }; const handleContextMenu = e => { const base64Strings = findBase64Strings(msg.content); const decodedContent = decodeBase64Strings(base64Strings); if (settings.store.clickMethod === "Left") { e.preventDefault(); e.stopPropagation(); decodedContent.forEach(content => copyWithToast(content)); } else { e.preventDefault(); e.stopPropagation(); openDecodedBase64Modal(decodedContent); } }; const label = settings.store.clickMethod === "Right" ? "Copy Decoded (Left Click) / Decode Base64 (Right Click)" : "Decode Base64 (Left Click) / Copy Decoded (Right Click)"; return { label, icon: DecodeIcon, message: msg, channel: ChannelStore.getChannel(msg.channel_id), onClick: handleClick, onContextMenu: handleContextMenu }; }); }, stop() { removeMessagePopoverButton("DecodeBase64"); } });