diff --git a/src/plugins/webhookManager.desktop/README.MD b/src/plugins/webhookManager.desktop/README.MD
new file mode 100644
index 000000000..6ca49a7f6
--- /dev/null
+++ b/src/plugins/webhookManager.desktop/README.MD
@@ -0,0 +1,21 @@
+# WebhookManager
+Manage your webhooks easily; delete, send messages, get detailed info and more.
+
+## Commands
+
+- /webhook send - *Sends a message through a webhook.*
+- /webhook delete - *Deletes any webhook that is specified.*
+- /webhook info - *Gets advanced details on the webhook such as the name, profile pic, server and channel ID, and additionally, information on person who created it*
+
+
+ Full /webhookinfo Output
+
+ - Webhook Username
+ - Webhook ID
+ - Webhook Token
+ - Channel ID
+ - Server ID
+ - Webhook Profile Picture
+ - Webhook Type
+ - Creator Profile
+
diff --git a/src/plugins/webhookManager.desktop/index.tsx b/src/plugins/webhookManager.desktop/index.tsx
new file mode 100644
index 000000000..65540082b
--- /dev/null
+++ b/src/plugins/webhookManager.desktop/index.tsx
@@ -0,0 +1,176 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
+import { Devs } from "@utils/constants";
+import { Margins } from "@utils/margins";
+import { ModalContent, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
+import definePlugin, { PluginNative } from "@utils/types";
+import { Button, Forms, React, Switch, TextInput, useState } from "@webpack/common";
+
+const Native = VencordNative.pluginHelpers.WebhookManager as PluginNative;
+let url, content, username, avatarUrl = "";
+let jsonMode = false;
+
+// TODO: add sending as raw
+function WebhookMessageModal(props: ModalProps) {
+ const [params, setParams] = useState({ content: "", username: "", avatarUrl: "", url: "", jsonMode: false });
+
+ const onURL = (url: string) => setParams(prev => ({ ...prev, url }));
+ const onContent = (content: string) => setParams(prev => ({ ...prev, content }));
+ const onUsername = (username: string) => setParams(prev => ({ ...prev, username }));
+ const onAvatar = (avatarUrl: string) => setParams(prev => ({ ...prev, avatarUrl }));
+ const onSwitch = (jsonMode: boolean) => setParams(prev => ({ ...prev, jsonMode }));
+
+
+ return
+
+ Webhook URL
+
+ Webhook Message
+
+ Webhook Username
+
+ Webhook Avatar URL
+
+ Send as Raw JSON
+
+
+ ;
+}
+
+
+export default definePlugin({
+ name: "WebhookManager",
+ description: "Manage your webhooks easily; delete, send messages, get detailed info and more.",
+ authors: [Devs.Byeoon, Devs.Ven],
+ dependencies: ["CommandsAPI"],
+ commands: [
+ {
+ name: "webhook delete",
+ description: "Delete a webhook.",
+ inputType: ApplicationCommandInputType.BUILT_IN,
+ options: [
+ {
+ name: "url",
+ description: "The URL of the webhook",
+ type: ApplicationCommandOptionType.STRING,
+ required: true
+ }
+ ],
+ execute: async (option, ctx) => {
+ try {
+ await fetch(findOption(option, "url", ""), {
+ method: "DELETE"
+ });
+ sendBotMessage(ctx.channel.id, {
+ content: "The webhook has deleted successfully."
+ });
+ }
+ catch (error) {
+ sendBotMessage(ctx.channel.id, {
+ content: "There was an error deleting the webhook. Did you input a valid webhook URL? Error: " + error
+ });
+ }
+ }
+ },
+ {
+ name: "webhook info",
+ description: "Retrieve information about a webhook.",
+ inputType: ApplicationCommandInputType.BUILT_IN,
+ options: [
+ {
+ name: "url",
+ description: "The URL of the webhook",
+ type: ApplicationCommandOptionType.STRING,
+ required: true
+ }
+ ],
+ execute: async (option, ctx) => {
+ const webhookUrl = findOption(option, "url", "");
+ const { user, avatar, name, id, token, type, channel_id, guild_id }
+ = await fetch(webhookUrl).then(res => res.json());
+
+ sendBotMessage(ctx.channel.id, {
+ content: `This webhook was created by ${user?.name}.`,
+ embeds: [
+ {
+ title: "Webhook Information",
+ color: "1323",
+ // @ts-ignore
+ author: {
+ name,
+ url: ""
+ },
+ thumbnail: {
+ url: `https://cdn.discordapp.com/avatars/${id}/${avatar}.png`,
+ proxyURL: `https://cdn.discordapp.com/avatars/${id}/${avatar}.png`,
+ height: 128,
+ width: 128
+ },
+ description: `
+ Webhook ID: ${id}
+ Webhook Token: ${token}
+ Webhook Type: ${type}
+ Channel ID: ${channel_id}
+ Server ID: ${guild_id}
+ `
+ }
+ ]
+ });
+ }
+ },
+ {
+ name: "webhook send",
+ description: "Send a message through a webhook.",
+ inputType: ApplicationCommandInputType.BUILT_IN,
+ async execute(_, ctx) {
+ openModal(props => );
+ sendBotMessage(ctx.channel.id, {
+ content: "Your webhook message has been executed."
+ });
+ }
+ }
+ ]
+});
diff --git a/src/plugins/webhookManager.desktop/native.ts b/src/plugins/webhookManager.desktop/native.ts
new file mode 100644
index 000000000..f400029ff
--- /dev/null
+++ b/src/plugins/webhookManager.desktop/native.ts
@@ -0,0 +1,22 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { IpcMainInvokeEvent } from "electron";
+import https from "https";
+
+const DiscordHosts = new Set(["discord.com", "ptb.discord.com", "canary.discord.com"]);
+
+export function executeWebhook(_event: IpcMainInvokeEvent, url: string, body: object) {
+ const { hostname, pathname } = new URL(url);
+
+ if (!DiscordHosts.has(hostname) || !pathname.startsWith("/api/webhooks/")) {
+ throw new Error("This URL is not a valid webhook.");
+ }
+
+ const req = https.request(url, { method: "POST", headers: { "Content-Type": "application/json", } });
+ req.write(JSON.stringify(body));
+ req.end();
+}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 6653e6307..5a791d551 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -475,7 +475,7 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "Sqaaakoi",
id: 259558259491340288n
},
- Byron: {
+ Byeoon: {
name: "byeoon",
id: 1167275288036655133n
},