From 5ac3912bc62c6c018ec6634718359da7962894fc Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Thu, 20 Feb 2025 11:21:33 +0100 Subject: [PATCH] feat: bump dompurify (#591) # Motivation Resolve security warning [#39 ](https://github.com/dfinity/gix-components/security/dependabot/39) # Changes - Bump dompurify to v3.2.4 - Use renamed function `beforeSanitizeAttributes` - Remove dompurify types - Adapt test by casting and remove optional argument for contructor to resolve below issues # Issues to adapt for tests ``` src/lib/utils/html.utils.ts:54:32 - error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. 54 } else if (typeof global.DOMPurify.sanitize === "function") { ~~~~~~~~~ src/lib/utils/html.utils.ts:56:28 - error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. 56 domPurify = global.DOMPurify; ~~~~~~~~~ src/lib/utils/html.utils.ts:60:26 - error TS2769: No overload matches this call. The last overload gave the following error. Argument of type '"beforeSanitizeElements"' is not assignable to parameter of type 'DocumentFragmentHookName'. 60 domPurify?.addHook("beforeSanitizeElements", flagTargetAttributeHook); ~~~~~~~~~~~~~~~~~~~~~~~~ node_modules/dompurify/dist/purify.es.d.mts:315:5 315 addHook(entryPoint: DocumentFragmentHookName, hookFunction: DocumentFragmentHook): void; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The last overload is declared here. vitest.setup.ts:23:26 - error TS2345: Argument of type 'Window' is not assignable to parameter of type 'WindowLike'. Type 'Window' is missing the following properties from type 'Pick': NodeFilter, DOMParser, DocumentFragment, Element, and 4 more. 23 const purify = DOMPurify(window as unknown as Window); ``` --- package-lock.json | 58 +++++++++++++++---------------------- package.json | 3 +- src/lib/utils/html.utils.ts | 7 +++-- vitest.setup.ts | 4 +-- 4 files changed, 29 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 043332c1..f376810c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "5.1.0", "license": "Apache-2.0", "dependencies": { - "dompurify": "^3.1.6", + "dompurify": "^3.2.4", "html5-qrcode": "^2.3.8", "marked": "^9.1.0", "qr-creator": "^1.0.0" @@ -23,7 +23,6 @@ "@sveltejs/vite-plugin-svelte": "^3.1.2", "@testing-library/jest-dom": "^6.5.0", "@testing-library/svelte": "^5.2.1", - "@types/dompurify": "^3.0.5", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "autoprefixer": "^10.4.20", @@ -1774,15 +1773,6 @@ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "dev": true }, - "node_modules/@types/dompurify": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", - "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", - "dev": true, - "dependencies": { - "@types/trusted-types": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -1854,10 +1844,11 @@ "dev": true }, "node_modules/@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", - "dev": true + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true }, "node_modules/@types/unist": { "version": "2.0.9", @@ -3020,10 +3011,13 @@ } }, "node_modules/dompurify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", - "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", - "license": "(MPL-2.0 OR Apache-2.0)" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/electron-to-chromium": { "version": "1.5.4", @@ -7424,15 +7418,6 @@ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", "dev": true }, - "@types/dompurify": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", - "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", - "dev": true, - "requires": { - "@types/trusted-types": "*" - } - }, "@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -7504,10 +7489,10 @@ "dev": true }, "@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", - "dev": true + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "optional": true }, "@types/unist": { "version": "2.0.9", @@ -8285,9 +8270,12 @@ } }, "dompurify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", - "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", + "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "requires": { + "@types/trusted-types": "^2.0.7" + } }, "electron-to-chromium": { "version": "1.5.4", diff --git a/package.json b/package.json index 619ed8ae..b13bab28 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "@sveltejs/vite-plugin-svelte": "^3.1.2", "@testing-library/jest-dom": "^6.5.0", "@testing-library/svelte": "^5.2.1", - "@types/dompurify": "^3.0.5", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", "autoprefixer": "^10.4.20", @@ -72,7 +71,7 @@ "vitest": "^2.1.9" }, "dependencies": { - "dompurify": "^3.1.6", + "dompurify": "^3.2.4", "html5-qrcode": "^2.3.8", "marked": "^9.1.0", "qr-creator": "^1.0.0" diff --git a/src/lib/utils/html.utils.ts b/src/lib/utils/html.utils.ts index 49deb8dc..99760725 100644 --- a/src/lib/utils/html.utils.ts +++ b/src/lib/utils/html.utils.ts @@ -51,13 +51,14 @@ export const sanitize = (text: string): string => { if (isNullish(domPurify)) { if (typeof DOMPurify.sanitize === "function") { domPurify = DOMPurify; + // @ts-expect-error For testing purpose only. } else if (typeof global.DOMPurify.sanitize === "function") { - // utilize NodeJS version - domPurify = global.DOMPurify; + // @ts-expect-error For testing purpose only. + domPurify = global.DOMPurify as unknown as typeof DOMPurify; } // Preserve target="blank" workaround - domPurify?.addHook("beforeSanitizeElements", flagTargetAttributeHook); + domPurify?.addHook("beforeSanitizeAttributes", flagTargetAttributeHook); domPurify?.addHook("afterSanitizeAttributes", restoreTargetAttributeHook); } diff --git a/vitest.setup.ts b/vitest.setup.ts index 57fc77ec..d6728282 100644 --- a/vitest.setup.ts +++ b/vitest.setup.ts @@ -18,9 +18,7 @@ configure({ // make `DOMPurify` available for unit tests import DOMPurify from "dompurify"; -import { JSDOM } from "jsdom"; -const { window } = new JSDOM(""); -const purify = DOMPurify(window as unknown as Window); +const purify = DOMPurify(); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: used for testing only global.DOMPurify = purify;