From 516fbff3d7e9ab92502fb1a9cfe168331be622f0 Mon Sep 17 00:00:00 2001 From: JellyBrick Date: Sun, 3 Nov 2024 18:16:36 +0900 Subject: [PATCH] fix: innerHTML trusted-types --- src/plugins/downloader/renderer.ts | 6 +++++- src/plugins/lyrics-genius/renderer.ts | 7 ++++++- src/plugins/playback-speed/renderer.ts | 7 ++++++- src/plugins/utils/renderer/html.ts | 6 +++++- src/renderer.ts | 21 +++++++++------------ src/utils/trusted-types.ts | 20 ++++++++++++++++++++ 6 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 src/utils/trusted-types.ts diff --git a/src/plugins/downloader/renderer.ts b/src/plugins/downloader/renderer.ts index fb8a3d0a..5fe8aa33 100644 --- a/src/plugins/downloader/renderer.ts +++ b/src/plugins/downloader/renderer.ts @@ -8,6 +8,8 @@ import { LoggerPrefix } from '@/utils'; import { t } from '@/i18n'; +import { defaultTrustedTypePolicy } from '@/utils/trusted-types'; + import { ElementFromHtml } from '../utils/renderer'; import type { RendererContext } from '@/types/contexts'; @@ -108,7 +110,9 @@ export const onRendererLoad = ({ ipc.on('downloader-feedback', (feedback: string) => { if (progress) { const targetHtml = feedback || t('plugins.downloader.templates.button'); - progress.innerHTML = window.trustedTypes?.defaultPolicy ? window.trustedTypes.defaultPolicy.createHTML(targetHtml) : targetHtml; + (progress.innerHTML as string | TrustedHTML) = defaultTrustedTypePolicy + ? defaultTrustedTypePolicy.createHTML(targetHtml) + : targetHtml; } else { console.warn( LoggerPrefix, diff --git a/src/plugins/lyrics-genius/renderer.ts b/src/plugins/lyrics-genius/renderer.ts index a0b4269b..bb710702 100644 --- a/src/plugins/lyrics-genius/renderer.ts +++ b/src/plugins/lyrics-genius/renderer.ts @@ -2,6 +2,8 @@ import { LoggerPrefix } from '@/utils'; import { t } from '@/i18n'; +import { defaultTrustedTypePolicy } from '@/utils/trusted-types'; + import type { SongInfo } from '@/providers/song-info'; import type { RendererContext } from '@/types/contexts'; import type { LyricsGeniusPluginConfig } from '@/plugins/lyrics-genius/index'; @@ -20,7 +22,10 @@ export const onRendererLoad = ({ `; - lyricsContainer.innerHTML = window.trustedTypes?.defaultPolicy ? window.trustedTypes.defaultPolicy.createHTML(targetHtml) : targetHtml; + (lyricsContainer.innerHTML as string | TrustedHTML) = + defaultTrustedTypePolicy + ? defaultTrustedTypePolicy.createHTML(targetHtml) + : targetHtml; if (lyrics) { const footer = lyricsContainer.querySelector('.footer'); diff --git a/src/plugins/playback-speed/renderer.ts b/src/plugins/playback-speed/renderer.ts index 4e41d7b4..a8c9502c 100644 --- a/src/plugins/playback-speed/renderer.ts +++ b/src/plugins/playback-speed/renderer.ts @@ -3,6 +3,8 @@ import sliderHTML from './templates/slider.html?raw'; import { getSongMenu } from '@/providers/dom-elements'; import { singleton } from '@/providers/decorators'; +import { defaultTrustedTypePolicy } from '@/utils/trusted-types'; + import { ElementFromHtml } from '../utils/renderer'; const slider = ElementFromHtml(sliderHTML); @@ -23,7 +25,10 @@ const updatePlayBackSpeed = () => { const playbackSpeedElement = document.querySelector('#playback-speed-value'); if (playbackSpeedElement) { const targetHtml = String(playbackSpeed); - playbackSpeedElement.innerHTML = window.trustedTypes?.defaultPolicy ? trustedTypes.defaultPolicy.createHTML(targetHtml) : targetHtml; + (playbackSpeedElement.innerHTML as string | TrustedHTML) = + defaultTrustedTypePolicy + ? defaultTrustedTypePolicy.createHTML(targetHtml) + : targetHtml; } }; diff --git a/src/plugins/utils/renderer/html.ts b/src/plugins/utils/renderer/html.ts index 6f9c906a..517df864 100644 --- a/src/plugins/utils/renderer/html.ts +++ b/src/plugins/utils/renderer/html.ts @@ -1,3 +1,5 @@ +import { defaultTrustedTypePolicy } from '@/utils/trusted-types'; + /** * Creates a DOM element from an HTML string * @param html The HTML string @@ -6,7 +8,9 @@ export const ElementFromHtml = (html: string): HTMLElement => { const template = document.createElement('template'); html = html.trim(); // Never return a text node of whitespace as the result - template.innerHTML = window.trustedTypes?.defaultPolicy ? window.trustedTypes.defaultPolicy.createHTML(html) : html; + (template.innerHTML as string | TrustedHTML) = defaultTrustedTypePolicy + ? defaultTrustedTypePolicy.createHTML(html) + : html; return template.content.firstElementChild as HTMLElement; }; diff --git a/src/renderer.ts b/src/renderer.ts index 2a263109..bdffd265 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -13,6 +13,11 @@ import { import { loadI18n, setLanguage, t as i18t } from '@/i18n'; +import { + defaultTrustedTypePolicy, + registerWindowDefaultTrustedTypePolicy, +} from '@/utils/trusted-types'; + import type { PluginConfig } from '@/types/plugins'; import type { YoutubePlayer } from '@/types/youtube-player'; import type { QueueElement } from '@/types/queue'; @@ -23,17 +28,7 @@ let isPluginLoaded = false; let isApiLoaded = false; let firstDataLoaded = false; -if ( - window.trustedTypes && - window.trustedTypes.createPolicy && - !window.trustedTypes.defaultPolicy -) { - window.trustedTypes.createPolicy('default', { - createHTML: (input) => input, - createScriptURL: (input) => input, - createScript: (input) => input, - }); -} +registerWindowDefaultTrustedTypePolicy(); async function listenForApiLoad() { if (!isApiLoaded) { @@ -270,7 +265,9 @@ const defineYTMDTransElements = () => { const key = that.getAttribute('key'); if (key) { const targetHtml = i18t(key); - that.innerHTML = window.trustedTypes?.defaultPolicy ? window.trustedTypes.defaultPolicy.createHTML(targetHtml) : targetHtml; + (that.innerHTML as string | TrustedHTML) = defaultTrustedTypePolicy + ? defaultTrustedTypePolicy.createHTML(targetHtml) + : targetHtml; } }; customElements.define( diff --git a/src/utils/trusted-types.ts b/src/utils/trusted-types.ts new file mode 100644 index 00000000..2f4a148d --- /dev/null +++ b/src/utils/trusted-types.ts @@ -0,0 +1,20 @@ +import type { TrustedTypePolicy } from 'trusted-types/lib'; + +export let defaultTrustedTypePolicy: Pick< + TrustedTypePolicy<{ + createHTML: (input: string) => string; + createScriptURL: (input: string) => string; + createScript: (input: string) => string; + }>, + 'name' | 'createHTML' | 'createScript' | 'createScriptURL' +>; + +export const registerWindowDefaultTrustedTypePolicy = () => { + if (window.trustedTypes && window.trustedTypes.createPolicy) { + defaultTrustedTypePolicy = window.trustedTypes.createPolicy('default', { + createHTML: (input) => input, + createScriptURL: (input) => input, + createScript: (input) => input, + }); + } +};