From 7eeeab182ea7499ada844cd6d25fa314d84515da Mon Sep 17 00:00:00 2001 From: Ghislain B Date: Mon, 6 Nov 2023 21:54:21 -0500 Subject: [PATCH] chore: add TrustedHTML to sanitizer output to fix build errors for CSP (#151) * chore: add TrustedHTML to sanitizer output to fix build errors for CSP --- .github/workflows/main.yml | 3 +++ demo/src/examples/example13.ts | 2 ++ demo/src/options/options27.ts | 3 +++ demo/src/options/options28.ts | 2 ++ demo/src/options/options30.ts | 4 ++++ demo/src/options/options31.ts | 2 ++ demo/src/options/options32.ts | 2 +- lib/package.json | 1 + lib/src/MultipleSelectInstance.ts | 2 +- lib/src/interfaces/interfaces.ts | 2 +- lib/src/interfaces/multipleSelectOption.interface.ts | 2 +- package.json | 2 +- playwright/playwright.config.ts | 8 +------- pnpm-lock.yaml | 3 +++ 14 files changed, 26 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5c7a23c0..7fea88a2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -52,6 +52,9 @@ jobs: - name: Install Playwright Browsers (chromium) run: pnpm exec playwright install chromium + - name: Start HTTP Server + run: pnpm serve:demo & + - name: Find Playwright Summary Comment (when exist) if: ${{ github.event.pull_request.number }} uses: peter-evans/find-comment@v2 diff --git a/demo/src/examples/example13.ts b/demo/src/examples/example13.ts index 56158ba5..a97a1254 100644 --- a/demo/src/examples/example13.ts +++ b/demo/src/examples/example13.ts @@ -1,3 +1,4 @@ +import DOMPurify from 'dompurify'; import { multipleSelect, MultipleSelectInstance } from 'multiple-select-vanilla'; export default class Example { @@ -17,6 +18,7 @@ export default class Example { name: 'my-select', single: false, useSelectOptionLabelToHtml: true, + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }), data: [ { text: ' January', diff --git a/demo/src/options/options27.ts b/demo/src/options/options27.ts index c763f4de..bfec5045 100644 --- a/demo/src/options/options27.ts +++ b/demo/src/options/options27.ts @@ -1,3 +1,4 @@ +import DOMPurify from 'dompurify'; import { multipleSelect, MultipleSelectInstance, TextFilter } from 'multiple-select-vanilla'; export default class Example { @@ -20,6 +21,7 @@ export default class Example { divElm.innerHTML = text; return divElm.textContent?.includes(search) ?? true; }, + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }), }) as MultipleSelectInstance; this.ms2 = multipleSelect('#from-data', { @@ -31,6 +33,7 @@ export default class Example { { value: `44'`, text: `44'` }, { value: `33`, text: `33` }, ], + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }) as unknown as string, }) as MultipleSelectInstance; this.btnEnableElm = document.querySelector('#enableRenderHtml') as HTMLButtonElement; diff --git a/demo/src/options/options28.ts b/demo/src/options/options28.ts index 933601e9..9b72e637 100644 --- a/demo/src/options/options28.ts +++ b/demo/src/options/options28.ts @@ -1,3 +1,4 @@ +import DOMPurify from 'dompurify'; import { multipleSelect, MultipleSelectInstance } from 'multiple-select-vanilla'; export default class Example { @@ -9,6 +10,7 @@ export default class Example { labelTemplate: (el) => { return `${el.getAttribute('label')}`; }, + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }), }) as MultipleSelectInstance; } diff --git a/demo/src/options/options30.ts b/demo/src/options/options30.ts index 46641f35..7a5afd5a 100644 --- a/demo/src/options/options30.ts +++ b/demo/src/options/options30.ts @@ -1,3 +1,4 @@ +import DOMPurify from 'dompurify'; import { multipleSelect, MultipleSelectInstance } from 'multiple-select-vanilla'; export default class Example { @@ -12,18 +13,21 @@ export default class Example { autoAdjustDropHeight: true, position: 'top', showOkButton: true, + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }), }) as MultipleSelectInstance; this.ms2 = multipleSelect('#select2', { autoAdjustDropHeight: true, position: 'top', showOkButton: true, + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }), }) as MultipleSelectInstance; this.ms3 = multipleSelect('#select3', { autoAdjustDropHeight: true, filter: true, position: 'top', + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }) as unknown as string, }) as MultipleSelectInstance; this.ms4 = multipleSelect('#select4') as MultipleSelectInstance; diff --git a/demo/src/options/options31.ts b/demo/src/options/options31.ts index 09ae09ba..035419c7 100644 --- a/demo/src/options/options31.ts +++ b/demo/src/options/options31.ts @@ -1,3 +1,4 @@ +import DOMPurify from 'dompurify'; import { multipleSelect, MultipleSelectInstance } from 'multiple-select-vanilla'; export default class Example { @@ -11,6 +12,7 @@ export default class Example { this.ms2 = multipleSelect('#select2', { useSelectOptionLabelToHtml: true, + sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }), data: [ { text: ' January', diff --git a/demo/src/options/options32.ts b/demo/src/options/options32.ts index 1282ccbe..d4b41bd4 100644 --- a/demo/src/options/options32.ts +++ b/demo/src/options/options32.ts @@ -13,7 +13,7 @@ export default class Example { : dirtyHtml, // or even better, use dedicated libraries like DOM Purify: https://github.com/cure53/DOMPurify - // sanitizer: (dirtyHtml) => DOMPurify.sanitize(dirtyHtml || '') + // sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }), }) as MultipleSelectInstance; } diff --git a/lib/package.json b/lib/package.json index 217f33b4..bdcb52e3 100644 --- a/lib/package.json +++ b/lib/package.json @@ -67,6 +67,7 @@ "sass:copy": "cross-env copyfiles -u 2 src/styles/**/*.scss dist/styles/sass" }, "devDependencies": { + "@types/trusted-types": "^2.0.5", "autoprefixer": "^10.4.16", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/lib/src/MultipleSelectInstance.ts b/lib/src/MultipleSelectInstance.ts index ec330013..7e8c26e9 100644 --- a/lib/src/MultipleSelectInstance.ts +++ b/lib/src/MultipleSelectInstance.ts @@ -972,7 +972,7 @@ export class MultipleSelectInstance { */ protected renderAsTextOrHtmlWhenEnabled(elm: HTMLElement, value: string) { if (this.isRenderAsHtml) { - elm.innerHTML = this.options.sanitizer ? this.options.sanitizer(value) : value; + elm.innerHTML = (typeof this.options.sanitizer === 'function' ? this.options.sanitizer(value) : value) as unknown as string; } else { elm.textContent = value; } diff --git a/lib/src/interfaces/interfaces.ts b/lib/src/interfaces/interfaces.ts index 24acba75..34f38489 100644 --- a/lib/src/interfaces/interfaces.ts +++ b/lib/src/interfaces/interfaces.ts @@ -27,7 +27,7 @@ export interface VirtualScrollOption { scrollEl: HTMLElement; contentEl: HTMLElement; callback: () => void; - sanitizer?: (dirtyHtml: string) => string; + sanitizer?: (html: string) => string | TrustedHTML; } export interface MultipleSelectLocale { diff --git a/lib/src/interfaces/multipleSelectOption.interface.ts b/lib/src/interfaces/multipleSelectOption.interface.ts index 68124fdd..38d2b129 100644 --- a/lib/src/interfaces/multipleSelectOption.interface.ts +++ b/lib/src/interfaces/multipleSelectOption.interface.ts @@ -255,5 +255,5 @@ export interface MultipleSelectOption extends MultipleSelectLocale { * Sanitizes HTML code, for example `