diff --git a/packages/discord.js/src/client/WebhookClient.js b/packages/discord.js/src/client/WebhookClient.js index 2752a1262..ff1f41ed4 100644 --- a/packages/discord.js/src/client/WebhookClient.js +++ b/packages/discord.js/src/client/WebhookClient.js @@ -3,6 +3,7 @@ const BaseClient = require('./BaseClient'); const { Error, ErrorCodes } = require('../errors'); const Webhook = require('../structures/Webhook'); +const { parseWebhookURL } = require('../util/Util'); /** * The webhook client. @@ -28,14 +29,12 @@ class WebhookClient extends BaseClient { let { id, token } = data; if ('url' in data) { - const url = data.url.match( - // eslint-disable-next-line no-useless-escape - /https?:\/\/(?:ptb\.|canary\.)?discord\.com\/api(?:\/v\d{1,2})?\/webhooks\/(\d{17,19})\/([\w-]{68})/i, - ); + const parsed = parseWebhookURL(data.url); + if (!parsed) { + throw new Error(ErrorCodes.WebhookURLInvalid); + } - if (!url || url.length <= 1) throw new Error(ErrorCodes.WebhookURLInvalid); - - [, id, token] = url; + ({ id, token } = parsed); } this.id = id; diff --git a/packages/discord.js/src/util/Util.js b/packages/discord.js/src/util/Util.js index 2f4773370..a2a273707 100644 --- a/packages/discord.js/src/util/Util.js +++ b/packages/discord.js/src/util/Util.js @@ -528,6 +528,32 @@ function lazy(cb) { return () => (defaultValue ??= cb()); } +/** + * Represents the credentials used for a given webhook + * @typedef {Object} WebhookCredentials + * @property {string} id The webhook's id + * @property {string} token The webhook's token + */ + +/** + * Parses a webhook URL for the id and token + * @param {string} url The URL to parse + * @returns {?WebhookCredentials} Null if the URL is invalid, otherwise the id and the token + */ +function parseWebhookURL(url) { + const matches = url.match( + /https?:\/\/(?:ptb\.|canary\.)?discord\.com\/api(?:\/v\d{1,2})?\/webhooks\/(\d{17,19})\/([\w-]{68})/i, + ); + + if (!matches || matches.length <= 2) return null; + + const [, id, token] = matches; + return { + id, + token, + }; +} + module.exports = { flatten, escapeMarkdown, @@ -554,6 +580,7 @@ module.exports = { cleanContent, cleanCodeBlockContent, lazy, + parseWebhookURL, }; // Fixes Circular diff --git a/packages/discord.js/typings/index.d.ts b/packages/discord.js/typings/index.d.ts index b5beeff3a..3d7cafe23 100644 --- a/packages/discord.js/typings/index.d.ts +++ b/packages/discord.js/typings/index.d.ts @@ -2659,6 +2659,7 @@ export function setPosition( route: string, reason?: string, ): Promise<{ id: Snowflake; position: number }[]>; +export function parseWebhookURL(url: string): WebhookClientDataIdWithToken | null; export interface MappedComponentBuilderTypes { [ComponentType.Button]: ButtonBuilder;