diff --git a/index.tsx b/index.tsx index 3697090..6d1617a 100644 --- a/index.tsx +++ b/index.tsx @@ -14,7 +14,7 @@ import { findByPropsLazy } from "@webpack"; import { UserStore } from "@webpack/common"; import { settings } from "./settings"; -import type { ClaimRequest, FinderProfile, WebhookResult } from "./types"; +import type { ClaimRequest, WebhookResult } from "./types"; import { sendClaimWebhook } from "./webhook"; const GIFT_LINK_REGEX = /(?:discord\.gift\/|discord\.com\/gifts?\/)([a-zA-Z0-9]{16,24})/; @@ -32,6 +32,10 @@ function resetState() { claiming = false; } +function toError(error: unknown) { + return error instanceof Error ? error : new Error(String(error)); +} + function isOwnMessage(message: Message) { return message.author?.id === UserStore.getCurrentUser()?.id; } @@ -52,32 +56,26 @@ function createClaimRequest(message: Message): ClaimRequest | null { const code = message.content ? extractGiftCode(message.content) : null; if (!code) return null; + const authorId = message.author?.id; + const authorAvatar = message.author?.avatar; + return { code, - authorId: message.author?.id, + authorId, authorName: message.author?.globalName ?? message.author?.username, authorUsername: message.author?.username, + authorAvatarUrl: authorId && authorAvatar + ? `https://cdn.discordapp.com/avatars/${authorId}/${authorAvatar}.png?size=128` + : undefined, channelId: message.channel_id, guildId: message.guild_id, messageId: message.id }; } -function getFinderProfile(): FinderProfile { - const currentUser = UserStore.getCurrentUser(); - - return { - name: currentUser?.globalName ?? currentUser?.username ?? "NitroSniper", - iconUrl: currentUser?.avatar - ? `https://cdn.discordapp.com/avatars/${currentUser.id}/${currentUser.avatar}.png?size=128` - : undefined - }; -} - function notifyClaim(result: WebhookResult, request: ClaimRequest) { void sendClaimWebhook( settings.store.webhookUrl, - getFinderProfile(), result, request ).catch(webhookError => { @@ -112,7 +110,7 @@ function processQueue() { GiftActions.redeemGiftCode({ code: request.code, onRedeemed: () => handleClaimSuccess(request), - onError: (error: Error) => handleClaimFailure(request, error) + onError: (error: unknown) => handleClaimFailure(request, toError(error)) }); } diff --git a/native.ts b/native.ts index 0622410..1739a3d 100644 --- a/native.ts +++ b/native.ts @@ -22,7 +22,7 @@ export async function sendWebhook(_: IpcMainInvokeEvent, webhookUrl: string, pay } catch (error) { return { status: -1, - data: String(error) + data: error instanceof Error ? error.message : String(error) }; } } diff --git a/settings.tsx b/settings.tsx index 0ffb965..ec6580b 100644 --- a/settings.tsx +++ b/settings.tsx @@ -4,6 +4,12 @@ import { Button, showToast, Toasts } from "@webpack/common"; import { sendTestWebhook } from "./webhook"; +function getToastErrorMessage(error: unknown) { + return error instanceof Error + ? error.message + : "Failed to send test webhook."; +} + function TestWebhookButton() { const { webhookUrl } = settings.use(["webhookUrl"]); const disabled = webhookUrl.trim().length === 0; @@ -16,8 +22,8 @@ function TestWebhookButton() { .then(() => { showToast("Test webhook sent successfully.", Toasts.Type.SUCCESS); }) - .catch((error: Error) => { - showToast(error.message, Toasts.Type.FAILURE); + .catch((error: unknown) => { + showToast(getToastErrorMessage(error), Toasts.Type.FAILURE); }); }} > diff --git a/types.ts b/types.ts index 157a973..6b6f304 100644 --- a/types.ts +++ b/types.ts @@ -3,16 +3,12 @@ export interface ClaimRequest { authorId?: string; authorName?: string; authorUsername?: string; + authorAvatarUrl?: string; channelId?: string; guildId?: string; messageId?: string; } -export interface FinderProfile { - name: string; - iconUrl?: string; -} - export type WebhookResult = "claimed" | "failed"; export interface WebhookField { diff --git a/webhook.ts b/webhook.ts index 499f0c2..2ca6002 100644 --- a/webhook.ts +++ b/webhook.ts @@ -2,7 +2,6 @@ import type { PluginNative } from "@utils/types"; import type { ClaimRequest, - FinderProfile, WebhookEmbed, WebhookField, WebhookPayload, @@ -54,6 +53,10 @@ function buildMessageUrl(request: ClaimRequest) { return `https://discordapp.com/channels/${request.guildId ?? "@me"}/${request.channelId}/${request.messageId}`; } +function escapeMarkdown(value: string) { + return value.replace(/([\\`*_{}\[\]()#+\-.!|>~])/g, "\\$1"); +} + function buildAuthorField(request: ClaimRequest): WebhookField | null { const label = request.authorName ?? request.authorUsername ?? request.authorId; if (!label) return null; @@ -61,7 +64,7 @@ function buildAuthorField(request: ClaimRequest): WebhookField | null { const profileUrl = buildUserProfileUrl(request.authorId); return { name: "Code sent by:", - value: profileUrl ? `[${label}](${profileUrl})` : label, + value: profileUrl ? `[${escapeMarkdown(label)}](${profileUrl})` : escapeMarkdown(label), inline: false }; } @@ -100,7 +103,17 @@ function getResultPresentation(result: WebhookResult) { } } -function buildClaimEmbed(finder: FinderProfile, result: WebhookResult, request: ClaimRequest): WebhookEmbed { +function buildEmbedAuthor(request: ClaimRequest) { + const name = request.authorName ?? request.authorUsername; + if (!name) return undefined; + + return { + name, + icon_url: request.authorAvatarUrl + }; +} + +function buildClaimEmbed(result: WebhookResult, request: ClaimRequest): WebhookEmbed { const presentation = getResultPresentation(result); return { @@ -108,10 +121,7 @@ function buildClaimEmbed(finder: FinderProfile, result: WebhookResult, request: color: presentation.color, fields: buildClaimFields(request), timestamp: new Date().toISOString(), - author: { - name: finder.name, - icon_url: finder.iconUrl - }, + author: buildEmbedAuthor(request), footer: { text: WEBHOOK_NAME } @@ -132,9 +142,9 @@ function buildTestWebhookPayload(): WebhookPayload { ]); } -function buildClaimWebhookPayload(finder: FinderProfile, result: WebhookResult, request: ClaimRequest): WebhookPayload { +function buildClaimWebhookPayload(result: WebhookResult, request: ClaimRequest): WebhookPayload { return createPayload([ - buildClaimEmbed(finder, result, request) + buildClaimEmbed(result, request) ]); } @@ -170,14 +180,13 @@ async function postWebhook(url: URL, payload: WebhookPayload) { export async function sendClaimWebhook( webhookUrl: string, - finder: FinderProfile, result: WebhookResult, request: ClaimRequest ) { const url = parseWebhookUrl(webhookUrl); if (!url) return; - await postWebhook(url, buildClaimWebhookPayload(finder, result, request)); + await postWebhook(url, buildClaimWebhookPayload(result, request)); } export async function sendTestWebhook(webhookUrl: string) {