From 941e11b6fda84defba25792547c787fb2153684d Mon Sep 17 00:00:00 2001 From: nin0 Date: Sat, 6 Dec 2025 14:54:13 -0500 Subject: [PATCH 1/5] MessageClickActions: allow deleting one's own user app messages (#3806) --- .../src/common/messages/Message.d.ts | 15 ++++++++++++++- src/plugins/messageClickActions/index.ts | 10 ++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/discord-types/src/common/messages/Message.d.ts b/packages/discord-types/src/common/messages/Message.d.ts index c2af24962..4a6f3e8b5 100644 --- a/packages/discord-types/src/common/messages/Message.d.ts +++ b/packages/discord-types/src/common/messages/Message.d.ts @@ -2,7 +2,7 @@ import { CommandOption } from './Commands'; import { User, UserJSON } from '../User'; import { Embed, EmbedJSON } from './Embed'; import { DiscordRecord } from "../Record"; -import { MessageFlags, MessageType, StickerFormatType } from "../../../enums"; +import { ApplicationIntegrationType, MessageFlags, MessageType, StickerFormatType } from "../../../enums"; /* * TODO: looks like discord has moved over to Date instead of Moment; @@ -71,6 +71,19 @@ export class Message extends DiscordRecord { type: number; version: string; }[]; + interactionMetadata?: { + id: string; + type: number; + name?: string; + command_type?: number; + ephemerality_reason?: number; + user: User; + authorizing_integration_owners: Record; + original_response_message_id?: string; + interacted_message_id?: string; + target_user?: User; + target_message_id?: string; + }; interactionError: unknown[]; isSearchHit: boolean; loggingName: unknown; diff --git a/src/plugins/messageClickActions/index.ts b/src/plugins/messageClickActions/index.ts index 6404bd6f3..b9eb718d1 100644 --- a/src/plugins/messageClickActions/index.ts +++ b/src/plugins/messageClickActions/index.ts @@ -21,9 +21,9 @@ import { definePluginSettings } from "@api/Settings"; import NoReplyMentionPlugin from "@plugins/noReplyMention"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import { MessageFlags } from "@vencord/discord-types/enums"; +import { ApplicationIntegrationType, MessageFlags } from "@vencord/discord-types/enums"; import { findByPropsLazy } from "@webpack"; -import { FluxDispatcher, MessageTypeSets, PermissionsBits, PermissionStore, UserStore, WindowStore } from "@webpack/common"; +import { AuthenticationStore, FluxDispatcher, MessageTypeSets, PermissionsBits, PermissionStore, WindowStore } from "@webpack/common"; const MessageActions = findByPropsLazy("deleteMessage", "startEditMessage"); const EditStore = findByPropsLazy("isEditing", "isEditingAny"); @@ -76,7 +76,9 @@ export default definePlugin({ }, onMessageClick(msg, channel, event) { - const isMe = msg.author.id === UserStore.getCurrentUser().id; + const myId = AuthenticationStore.getId(); + const isMe = msg.author.id === myId; + const isSelfInvokedUserApp = msg.interactionMetadata?.authorizing_integration_owners[ApplicationIntegrationType.USER_INSTALL] === myId; if (!isDeletePressed) { if (event.detail < 2) return; if (settings.store.requireModifier && !event.ctrlKey && !event.shiftKey) return; @@ -106,7 +108,7 @@ export default definePlugin({ showMentionToggle: channel.guild_id !== null }); } - } else if (settings.store.enableDeleteOnClick && (isMe || PermissionStore.can(PermissionsBits.MANAGE_MESSAGES, channel))) { + } else if (settings.store.enableDeleteOnClick && (isMe || PermissionStore.can(PermissionsBits.MANAGE_MESSAGES, channel) || isSelfInvokedUserApp)) { if (msg.deleted) { FluxDispatcher.dispatch({ type: "MESSAGE_DELETE", From 45ba1350340e11102701b991d2be4c1b5201b16a Mon Sep 17 00:00:00 2001 From: Vendicated Date: Sat, 6 Dec 2025 21:11:41 +0100 Subject: [PATCH 2/5] LastFM: add api key guide back. our shared key may get ratelimited --- src/plugins/lastfmRichPresence/index.tsx | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/plugins/lastfmRichPresence/index.tsx b/src/plugins/lastfmRichPresence/index.tsx index b6164b196..4848b7438 100644 --- a/src/plugins/lastfmRichPresence/index.tsx +++ b/src/plugins/lastfmRichPresence/index.tsx @@ -17,6 +17,11 @@ */ import { definePluginSettings } from "@api/Settings"; +import { LinkButton } from "@components/Button"; +import { Card } from "@components/Card"; +import { Heading } from "@components/Heading"; +import { Margins } from "@components/margins"; +import { Paragraph } from "@components/Paragraph"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; import definePlugin, { OptionType } from "@utils/types"; @@ -61,6 +66,10 @@ function setActivity(activity: Activity | null) { } const settings = definePluginSettings({ + apiKey: { + description: "Custom Last.fm API key. Not required but highly recommended to avoid rate limiting with our shared key", + type: OptionType.STRING, + }, username: { description: "Last.fm username", type: OptionType.STRING, @@ -165,10 +174,6 @@ const settings = definePluginSettings({ type: OptionType.BOOLEAN, default: true, }, - apiKey: { - description: "Custom Last.fm API key. You shouldn't need to set this", - type: OptionType.STRING, - }, }); export default definePlugin({ @@ -178,6 +183,16 @@ export default definePlugin({ settings, + settingsAboutComponent() { + return ( + + How to create an API key + Set Application name and Application description to anything and leave the rest blank. + Create API Key + + ); + }, + start() { this.updatePresence(); this.updateInterval = setInterval(() => { this.updatePresence(); }, 16000); From fa46c4c4d2f19114bc87842ae46b988e39e6a0e7 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Sat, 6 Dec 2025 21:33:58 +0100 Subject: [PATCH 3/5] settings sync: disallow possibly insecure settings realistically this shouldn't matter too much, but still good to have --- src/api/SettingsSync/offline.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/api/SettingsSync/offline.ts b/src/api/SettingsSync/offline.ts index aced11e81..5ff509caf 100644 --- a/src/api/SettingsSync/offline.ts +++ b/src/api/SettingsSync/offline.ts @@ -24,6 +24,21 @@ const toastFailure = (err: any) => const logger = new Logger("SettingsSync:Offline", "#39b7e0"); +function isSafeObject(obj: any) { + if (obj == null || typeof obj !== "object") return true; + + for (const key in obj) { + if (["__proto__", "constructor", "prototype"].includes(key)) { + return false; + } + if (!isSafeObject(obj[key])) { + return false; + } + } + + return true; +} + export async function importSettings(data: string) { try { var parsed = JSON.parse(data); @@ -32,6 +47,9 @@ export async function importSettings(data: string) { throw new Error("Failed to parse JSON: " + String(err)); } + if (!isSafeObject(parsed)) + throw new Error("Unsafe Settings"); + if ("settings" in parsed && "quickCss" in parsed) { Object.assign(PlainSettings, parsed.settings); await VencordNative.settings.set(parsed.settings); From ed51391efca92578aec94bed18baeaf4deb69452 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Sat, 6 Dec 2025 21:43:25 +0100 Subject: [PATCH 4/5] fix ShowHiddenChannels patch --- src/plugins/showHiddenChannels/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index 5f83a3f5d..2cbd9552a 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -457,11 +457,11 @@ export default definePlugin({ // Filter hidden channels from GuildChannelStore.getChannels unless told otherwise match: /(?<=getChannels\(\i)(\){.*?)return (.+?)}/, replace: (_, rest, channels) => `,shouldIncludeHidden${rest}return $self.resolveGuildChannels(${channels},shouldIncludeHidden??arguments[0]==="@favorites");}` - } + }, ] }, { - find: "#{intl::FORM_LABEL_MUTED}", + find: ".invitesDisabledTooltip", replacement: { // Make GuildChannelStore.getChannels return hidden channels match: /(?<=getChannels\(\i)(?=\))/, From 960f49bab683d23f716462768dbb1f431cd9edc5 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Sat, 6 Dec 2025 21:58:13 +0100 Subject: [PATCH 5/5] bump to 1.13.7 --- package.json | 2 +- packages/vencord-types/package.json | 2 +- src/webpack/common/utils.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e267b04c1..f2dd8870c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.13.6", + "version": "1.13.7", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": { diff --git a/packages/vencord-types/package.json b/packages/vencord-types/package.json index ae12354cd..7fd3345f8 100644 --- a/packages/vencord-types/package.json +++ b/packages/vencord-types/package.json @@ -1,7 +1,7 @@ { "name": "@vencord/types", "private": false, - "version": "1.13.2", + "version": "1.13.7", "description": "", "types": "index.d.ts", "scripts": { diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index 0223c2e74..ff4c0b29a 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -18,6 +18,7 @@ import type * as t from "@vencord/discord-types"; import { _resolveReady, filters, findByCodeLazy, findByPropsLazy, findLazy, mapMangledModuleLazy, waitFor } from "@webpack"; +import type * as TSPattern from "ts-pattern"; export let FluxDispatcher: t.FluxDispatcher; waitFor(["dispatch", "subscribe"], m => { @@ -47,7 +48,7 @@ export const moment: typeof import("moment") = findByPropsLazy("parseTwoDigitYea export const hljs: typeof import("highlight.js").default = findByPropsLazy("highlight", "registerLanguage"); -export const { match, P }: Pick = mapMangledModuleLazy("@ts-pattern/matcher", { +export const { match, P }: { match: typeof TSPattern["match"], P: typeof TSPattern["P"]; } = mapMangledModuleLazy("@ts-pattern/matcher", { match: filters.byCode("return new"), P: filters.byProps("when") });