From 98896de20b1201afc73a628f98789a98e31c8614 Mon Sep 17 00:00:00 2001 From: thororen1234 <78185467+thororen1234@users.noreply.github.com> Date: Tue, 8 Apr 2025 09:47:34 -0400 Subject: [PATCH] Fixes For CSP --- README.md | 3 +- src/components/ThemeSettings/ThemesTab.tsx | 6 + .../betterAudioPlayer/index.tsx | 312 ------------------ .../betterAudioPlayer/style.css | 10 - .../moreStickers/components/misc.tsx | 116 +------ .../moreStickers/lineEmojis.ts | 14 - .../moreStickers/lineStickers.ts | 14 - src/equicordplugins/moreStickers/testdata.ts | 77 ----- src/equicordplugins/moreStickers/types.ts | 1 - src/equicordplugins/moreStickers/utils.tsx | 4 - src/main/csp.ts | 10 + src/plugins/devCompanion.dev/initWs.tsx | 2 +- 12 files changed, 21 insertions(+), 548 deletions(-) delete mode 100644 src/equicordplugins/betterAudioPlayer/index.tsx delete mode 100644 src/equicordplugins/betterAudioPlayer/style.css delete mode 100644 src/equicordplugins/moreStickers/testdata.ts diff --git a/README.md b/README.md index fa18471a3..99c4c99a9 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch ### Extra included plugins
-153 additional plugins +152 additional plugins ### All Platforms @@ -23,7 +23,6 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch - AtSomeone by Joona - BannersEverywhere by ImLvna & AutumnVN - BetterActivities by D3SOX, Arjix, AutumnVN -- BetterAudioPlayer by Creations - BetterBanReasons by Inbestigator - BetterBlockedUsers by TheArmagan & Elvyra - BetterInvites by iamme diff --git a/src/components/ThemeSettings/ThemesTab.tsx b/src/components/ThemeSettings/ThemesTab.tsx index 0e752efc9..729705305 100644 --- a/src/components/ThemeSettings/ThemesTab.tsx +++ b/src/components/ThemeSettings/ThemesTab.tsx @@ -318,6 +318,12 @@ function ThemesTab() { If using the BD site, click on "Download" and place the downloaded .theme.css file into your themes folder. + + External Resources + For security reasons, loading resources (styles, fonts, images, ...) from most sites is blocked. + Make sure all your assets are hosted on GitHub, GitLab, Codeberg, Imgur, Discord or Google Fonts. + + <> diff --git a/src/equicordplugins/betterAudioPlayer/index.tsx b/src/equicordplugins/betterAudioPlayer/index.tsx deleted file mode 100644 index 86518258f..000000000 --- a/src/equicordplugins/betterAudioPlayer/index.tsx +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import "./style.css"; - -import { definePluginSettings } from "@api/Settings"; -import { EquicordDevs } from "@utils/constants"; -import definePlugin, { OptionType } from "@utils/types"; -import { showToast, Toasts } from "@webpack/common"; - -const fileSizeLimit = 12e6; - -function parseFileSize(size: string) { - const [value, unit] = size.split(" "); - const multiplier = { - B: 1, - KB: 1024, - MB: 1024 ** 2, - GB: 1024 ** 3, - TB: 1024 ** 4, - }[unit]; - if (!multiplier) return; - return parseFloat(value) * multiplier; -} - -function getMetadata(audioElement: HTMLElement) { - const metadataElement = audioElement.querySelector("[class^='metadataContent_']"); - const nameElement = metadataElement?.querySelector("a"); - const sizeElement = audioElement.querySelector("[class^='metadataContent_'] [class^='metadataSize_']"); - const url = nameElement?.getAttribute("href"); - const audioElementLink = audioElement.querySelector("audio"); - - if (!sizeElement?.textContent || !nameElement?.textContent || !url || !audioElementLink) return false; - - const name = nameElement.textContent; - const size = parseFileSize(sizeElement.textContent); - - if (size && size > fileSizeLimit) { - return false; - } - - const elements = [metadataElement?.parentElement, audioElement.querySelector("[class^='audioControls_']")]; - - const computedStyle = getComputedStyle(audioElement); - const parentBorderRadius = computedStyle.borderRadius; - - if (settings.store.forceMoveBelow) { - elements.forEach(element => { - if (element) (element as HTMLElement).style.zIndex = "2"; - }); - } - - return { - name, - size, - url, - audio: audioElementLink, - parentBorderRadius: parentBorderRadius, - }; -} - -async function addListeners(audioElement: HTMLAudioElement, url: string, parentBorderRadius: string) { - const madeURL = new URL(url); - madeURL.searchParams.set("t", Date.now().toString()); - - const { href } = madeURL; - const response = await fetch(href); - const blob = await response.blob(); - const blobUrl = URL.createObjectURL(blob); - - const audioContext = new AudioContext(); - const analyser = audioContext.createAnalyser(); - analyser.fftSize = 2048; - const bufferLength = analyser.frequencyBinCount; - const dataArray = new Uint8Array(bufferLength); - const frequencyData = new Uint8Array(bufferLength); - - const source = audioContext.createMediaElementSource(audioElement); - source.connect(analyser); - analyser.connect(audioContext.destination); - - const canvas = document.createElement("canvas"); - const canvasContext = canvas.getContext("2d"); - if (!canvasContext) return; - - canvas.classList.add("better-audio-visualizer"); - audioElement.parentElement?.appendChild(canvas); - - if (parentBorderRadius) canvas.style.borderRadius = parentBorderRadius; - - function drawVisualizer() { - if (!audioElement.paused) { - requestAnimationFrame(drawVisualizer); - } - - analyser.getByteTimeDomainData(dataArray); - analyser.getByteFrequencyData(frequencyData); - - if (!canvasContext) return; - canvasContext.clearRect(0, 0, canvas.width, canvas.height); - - if (settings.store.oscilloscope) drawOscilloscope(canvasContext, canvas, dataArray, bufferLength); - if (settings.store.spectrograph) drawSpectrograph(canvasContext, canvas, frequencyData, bufferLength); - } - - audioElement.src = blobUrl; - audioElement.addEventListener("play", () => { - if (audioContext.state === "suspended") { - audioContext.resume(); - } - drawVisualizer(); - }); - - audioElement.addEventListener("pause", () => { - audioContext.suspend(); - }); -} - -function drawOscilloscope(canvasContext, canvas, dataArray, bufferLength) { - const sliceWidth = canvas.width / bufferLength; - let x = 0; - - const { oscilloscopeSolidColor, oscilloscopeColor } = settings.store; - - const [r, g, b] = oscilloscopeColor.split(",").map(Number); - - canvasContext.lineWidth = 2; - canvasContext.clearRect(0, 0, canvas.width, canvas.height); - canvasContext.beginPath(); - - for (let i = 0; i < bufferLength; i++) { - const v = dataArray[i] / 128.0; - const y = (v * canvas.height) / 2; - - if (oscilloscopeSolidColor) { - canvasContext.strokeStyle = `rgb(${r}, ${g}, ${b})`; - } else { - const red = Math.min(r + (v * 100) + (i / bufferLength) * 155, 255); - const green = Math.min(g + (v * 50) + (i / bufferLength) * 155, 255); - const blue = Math.min(b + (v * 150) + (i / bufferLength) * 155, 255); - - canvasContext.strokeStyle = `rgb(${red}, ${green}, ${blue})`; - } - - if (i === 0) { - canvasContext.moveTo(x, y); - } else { - canvasContext.lineTo(x, y); - } - - x += sliceWidth; - } - - canvasContext.stroke(); -} - -function drawSpectrograph(canvasContext, canvas, frequencyData, bufferLength) { - const { spectrographSolidColor, spectrographColor } = settings.store; - const maxHeight = canvas.height; - const barWidth = canvas.width / bufferLength; - let x = 0; - - const maxFrequencyValue = Math.max(...frequencyData); - - if (maxFrequencyValue === 0 || !isFinite(maxFrequencyValue)) { - return; - } - - for (let i = 0; i < bufferLength; i++) { - const normalizedHeight = (frequencyData[i] / maxFrequencyValue) * maxHeight; - - if (spectrographSolidColor) { - canvasContext.fillStyle = `rgb(${spectrographColor})`; - } else { - const [r, g, b] = spectrographColor.split(",").map(Number); - - const red = Math.min(r + (i / bufferLength) * 155, 255); - const green = Math.min(g + (i / bufferLength) * 155, 255); - const blue = Math.min(b + (i / bufferLength) * 155, 255); - - const gradient = canvasContext.createLinearGradient(x, canvas.height - normalizedHeight, x, canvas.height); - gradient.addColorStop(0, `rgb(${red}, ${green}, ${blue})`); - - const darkerColor = `rgb(${Math.max(red - 50, 0)},${Math.max(green - 50, 0)},${Math.max(blue - 50, 0)})`; - - gradient.addColorStop(1, darkerColor); - canvasContext.fillStyle = gradient; - } - - canvasContext.fillRect(x, canvas.height - normalizedHeight, barWidth, normalizedHeight); - x += barWidth + 0.5; - } -} - -function scanForAudioElements(element: HTMLElement) { - element.querySelectorAll("[class^='wrapperAudio_']:not([data-better-audio-processed])").forEach(audioElement => { - (audioElement as HTMLElement).dataset.betterAudioProcessed = "true"; - const metadata = getMetadata(audioElement as HTMLElement); - - if (!metadata) return; - - addListeners(metadata.audio, metadata.url, metadata.parentBorderRadius); - }); -} - -function createObserver(targetNode: HTMLElement) { - const observer = new MutationObserver(mutations => { - mutations.forEach(mutation => { - if (mutation.type === "childList") { - mutation.addedNodes.forEach(addedNode => { - if (addedNode instanceof HTMLElement) { - scanForAudioElements(addedNode); - } - }); - } - }); - }); - observer.observe(targetNode, { - childList: true, - subtree: true, - }); -} - -function tryHexToRgb(hex) { - if (hex.startsWith("#")) { - const hexMatch = hex.match(/\w\w/g); - if (hexMatch) { - const [r, g, b] = hexMatch.map(x => parseInt(x, 16)); - return `${r}, ${g}, ${b}`; - } - } - return hex; -} - -function handleColorChange(value, settingKey, defaultValue) { - const rgbPattern = /^(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})$/; - - if (!value.match(rgbPattern)) { - const rgb = tryHexToRgb(value); - - if (rgb.match(rgbPattern)) { - settings.store[settingKey] = rgb; - } else { - showToast(`Invalid color format for ${settingKey}, make sure it's in the format 'R, G, B' or '#RRGGBB'`, Toasts.Type.FAILURE); - settings.store[settingKey] = defaultValue; - } - } else { - settings.store[settingKey] = value; - } -} - -const settings = definePluginSettings({ - oscilloscope: { - type: OptionType.BOOLEAN, - description: "Enable oscilloscope visualizer", - default: true, - }, - spectrograph: { - type: OptionType.BOOLEAN, - description: "Enable spectrograph visualizer", - default: true, - }, - oscilloscopeSolidColor: { - type: OptionType.BOOLEAN, - description: "Use solid color for oscilloscope", - default: false, - }, - oscilloscopeColor: { - type: OptionType.STRING, - description: "Color for oscilloscope", - default: "255, 255, 255", - onChange: value => handleColorChange(value, "oscilloscopeColor", "255, 255, 255"), - }, - spectrographSolidColor: { - type: OptionType.BOOLEAN, - description: "Use solid color for spectrograph", - default: false, - }, - spectrographColor: { - type: OptionType.STRING, - description: "Color for spectrograph", - default: "33, 150, 243", - onChange: value => handleColorChange(value, "spectrographColor", "33, 150, 243"), - }, - forceMoveBelow: { - type: OptionType.BOOLEAN, - description: "Force the visualizer below the audio player", - default: true, - }, -}); - -export default definePlugin({ - name: "BetterAudioPlayer", - description: "Adds a spectrograph and oscilloscope visualizer to audio attachment players", - authors: [EquicordDevs.creations], - settings, - start() { - const waitForContent = () => { - const targetNode = document.querySelector("[class^='content_']"); - if (targetNode) { - scanForAudioElements(targetNode as HTMLElement); - createObserver(targetNode as HTMLElement); - } else { - requestAnimationFrame(waitForContent); - } - }; - waitForContent(); - }, -}); diff --git a/src/equicordplugins/betterAudioPlayer/style.css b/src/equicordplugins/betterAudioPlayer/style.css deleted file mode 100644 index e96b9338d..000000000 --- a/src/equicordplugins/betterAudioPlayer/style.css +++ /dev/null @@ -1,10 +0,0 @@ -.better-audio-visualizer { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: 1; - border: none; -} \ No newline at end of file diff --git a/src/equicordplugins/moreStickers/components/misc.tsx b/src/equicordplugins/moreStickers/components/misc.tsx index d3a35983e..2d760c0bc 100644 --- a/src/equicordplugins/moreStickers/components/misc.tsx +++ b/src/equicordplugins/moreStickers/components/misc.tsx @@ -5,13 +5,12 @@ */ import * as DataStore from "@api/DataStore"; -import { CheckedTextInput } from "@components/CheckedTextInput"; import { Flex } from "@components/Flex"; import { Button, Forms, React, TabBar, Text, TextArea, Toasts } from "@webpack/common"; import { JSX } from "react"; -import { convert as convertLineEP, getIdFromUrl as getLineEmojiPackIdFromUrl, getStickerPackById as getLineEmojiPackById, isLineEmojiPackHtml, parseHtml as getLineEPFromHtml } from "../lineEmojis"; -import { convert as convertLineSP, getIdFromUrl as getLineStickerPackIdFromUrl, getStickerPackById as getLineStickerPackById, isLineStickerPackHtml, parseHtml as getLineSPFromHtml } from "../lineStickers"; +import { convert as convertLineEP, isLineEmojiPackHtml, parseHtml as getLineEPFromHtml } from "../lineEmojis"; +import { convert as convertLineSP, isLineStickerPackHtml, parseHtml as getLineSPFromHtml } from "../lineStickers"; import { isV1, migrate } from "../migrate-v1"; import { deleteStickerPack, getStickerPack, getStickerPackMetas, saveStickerPack } from "../stickers"; import { SettingsTabsKey, Sticker, StickerPack, StickerPackMeta } from "../types"; @@ -89,9 +88,8 @@ const StickerPackMetadata = ({ meta, hoveredStickerPackId, setHoveredStickerPack export const Settings = () => { const [stickerPackMetas, setstickerPackMetas] = React.useState([]); - const [addStickerUrl, setAddStickerUrl] = React.useState(""); const [addStickerHtml, setAddStickerHtml] = React.useState(""); - const [tab, setTab] = React.useState(SettingsTabsKey.ADD_STICKER_PACK_URL); + const [tab, setTab] = React.useState(SettingsTabsKey.ADD_STICKER_PACK_HTML); const [hoveredStickerPackId, setHoveredStickerPackId] = React.useState(null); const [_isV1, setV1] = React.useState(false); @@ -123,114 +121,6 @@ export const Settings = () => { } - {tab === SettingsTabsKey.ADD_STICKER_PACK_URL && -
- Add Sticker Pack from URL - -

- Currently LINE stickers/emojis supported only.
- - Get Telegram stickers with VencordNative.native.openExternal("https://github.com/lekoOwO/MoreStickersConverter")}> MoreStickersConverter. -

-
- - - { - try { - getLineStickerPackIdFromUrl(v); - return true; - } catch (e: any) { } - try { - getLineEmojiPackIdFromUrl(v); - return true; - } catch (e: any) { } - - return "Invalid URL"; - }} - placeholder="Sticker Pack URL" - /> - - - -
- } {tab === SettingsTabsKey.ADD_STICKER_PACK_HTML &&
Add Sticker Pack from HTML diff --git a/src/equicordplugins/moreStickers/lineEmojis.ts b/src/equicordplugins/moreStickers/lineEmojis.ts index de631bfb9..f8bb681d8 100644 --- a/src/equicordplugins/moreStickers/lineEmojis.ts +++ b/src/equicordplugins/moreStickers/lineEmojis.ts @@ -5,7 +5,6 @@ */ import { LineEmoji, LineEmojiPack, Sticker, StickerPack } from "./types"; -import { lineFetch } from "./utils"; export interface StickerCategory { title: string; @@ -123,16 +122,3 @@ export function parseHtml(html: string): LineEmojiPack { export function isLineEmojiPackHtml(html: string): boolean { return html.includes("data-test=\"emoji-name-title\""); } - -/** - * Get stickers from LINE - * - * @param {string} id The id of the sticker pack. - * @return {Promise} The sticker pack. - */ -export async function getStickerPackById(id: string, region = "en"): Promise { - const res = await lineFetch(`https://store.line.me/emojishop/product/${id}/${region}`); - const html = await res.text(); - - return parseHtml(html); -} diff --git a/src/equicordplugins/moreStickers/lineStickers.ts b/src/equicordplugins/moreStickers/lineStickers.ts index ee4988ca1..9b6a58d80 100644 --- a/src/equicordplugins/moreStickers/lineStickers.ts +++ b/src/equicordplugins/moreStickers/lineStickers.ts @@ -5,7 +5,6 @@ */ import { LineSticker, LineStickerPack, Sticker, StickerPack } from "./types"; -import { lineFetch } from "./utils"; export interface StickerCategory { title: string; @@ -123,16 +122,3 @@ export function parseHtml(html: string): LineStickerPack { export function isLineStickerPackHtml(html: string): boolean { return html.includes("data-test=\"sticker-name-title\""); } - -/** - * Get stickers from LINE - * - * @param {string} id The id of the sticker pack. - * @return {Promise} The sticker pack. - */ -export async function getStickerPackById(id: string, region = "en"): Promise { - const res = await lineFetch(`https://store.line.me/stickershop/product/${id}/${region}`); - const html = await res.text(); - - return parseHtml(html); -} diff --git a/src/equicordplugins/moreStickers/testdata.ts b/src/equicordplugins/moreStickers/testdata.ts deleted file mode 100644 index 9a6f4f70c..000000000 --- a/src/equicordplugins/moreStickers/testdata.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { setRecentStickers } from "./components"; -import { - convert, - getStickerPackById -} from "./lineStickers"; -import { - deleteStickerPack, - getStickerPackMetas, - saveStickerPack -} from "./stickers"; -import { StickerPack } from "./types"; - -export async function initTest() { - console.log("initTest."); - - console.log("Clearing recent stickers."); - setRecentStickers([]); - - // Clear all sticker packs - console.log("Clearing all sticker packs."); - const stickerPackMetas = await getStickerPackMetas(); - for (const meta of stickerPackMetas) { - await deleteStickerPack(meta.id); - } - - // Add test sticker packs - console.log("Adding test sticker packs."); - const lineStickerPackIds = [ - "22814489", // LV.47 - "22567773", // LV.46 - "22256215", // LV.45 - "21936635", // LV.44 - "21836565", // LV.43 - ]; - const ps: Promise[] = []; - for (const id of lineStickerPackIds) { - ps.push((async () => { - try { - const lsp = await getStickerPackById(id); - const sp = convert(lsp); - return sp; - } catch (e) { - console.error("Failed to fetch sticker pack: " + id); - console.error(e); - return null; - } - })()); - } - const stickerPacks = (await Promise.all(ps)).filter(sp => sp !== null) as StickerPack[]; - - console.log("Saving test sticker packs."); - for (const sp of stickerPacks) { - await saveStickerPack(sp); - } - - console.log(await getStickerPackMetas()); -} - -export async function clearTest() { - console.log("clearTest."); - - console.log("Clearing recent stickers."); - setRecentStickers([]); - - // Clear all sticker packs - console.log("Clearing all sticker packs."); - const stickerPackMetas = await getStickerPackMetas(); - for (const meta of stickerPackMetas) { - await deleteStickerPack(meta.id); - } -} diff --git a/src/equicordplugins/moreStickers/types.ts b/src/equicordplugins/moreStickers/types.ts index 5d545bdf0..e675f8594 100644 --- a/src/equicordplugins/moreStickers/types.ts +++ b/src/equicordplugins/moreStickers/types.ts @@ -97,7 +97,6 @@ export interface PickerContentRowGrid { } export enum SettingsTabsKey { - ADD_STICKER_PACK_URL = "Add from URL", ADD_STICKER_PACK_HTML = "Add from HTML", ADD_STICKER_PACK_FILE = "Add from File", MISC = "Misc", diff --git a/src/equicordplugins/moreStickers/utils.tsx b/src/equicordplugins/moreStickers/utils.tsx index cb928aeee..e2e4b707b 100644 --- a/src/equicordplugins/moreStickers/utils.tsx +++ b/src/equicordplugins/moreStickers/utils.tsx @@ -14,10 +14,6 @@ import { FFmpegState } from "./types"; export const cl = classNameFactory("vc-more-stickers-"); export const clPicker = (className: string, ...args: any[]) => cl("picker-" + className, ...args); -export function lineFetch(url: string | URL, init?: RequestInit | undefined) { - return fetch(url, init); -} - export class Mutex { current = Promise.resolve(); lock() { diff --git a/src/main/csp.ts b/src/main/csp.ts index a9cb635ac..dbeb4a42b 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -53,6 +53,16 @@ export const CspPolicies: PolicyMap = { "dearrow-thumb.ajay.app": MediaSrc, // Dearrow Thumbnail CDN "usrbg.is-hardly.online": MediaSrc, // USRBG API "icons.duckduckgo.com": MediaSrc, // DuckDuckGo Favicon API (Reverse Image Search) + + // Equicord + "cdn.nest.rip": MediaSrc, // Nest CDN + "*.equicord.org": MediaSrc, // Equicord CDN + "discord-themes.com": MediaAndCssSrc, // Discord Themes CDN + "fonts.google.com": ConnectSrc, + "store.line.me": MediaSrc, // Line Store + "lrclib.net": ConnectSrc, // Lrclib API + "spotify-lyrics-api-pi.vercel.app": ConnectSrc, // Spotify Lyrics API + "stats.fm": MediaSrc, // Stats.fm API }; const findHeader = (headers: PolicyMap, headerName: Lowercase) => { diff --git a/src/plugins/devCompanion.dev/initWs.tsx b/src/plugins/devCompanion.dev/initWs.tsx index 36ee47780..2a81120ef 100644 --- a/src/plugins/devCompanion.dev/initWs.tsx +++ b/src/plugins/devCompanion.dev/initWs.tsx @@ -28,7 +28,7 @@ export let socket: WebSocket | undefined; export function initWs(isManual = false) { let wasConnected = isManual; let hasErrored = false; - const ws = socket = new WebSocket(`ws://localhost:${PORT}`); + const ws = socket = new WebSocket(`ws://127.0.0.1:${PORT}`); function replyData(data: OutgoingMessage) { ws.send(JSON.stringify(data));