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 },