diff --git a/libs/designer-ui/package.json b/libs/designer-ui/package.json index 81d1e298c14..c5af550a254 100644 --- a/libs/designer-ui/package.json +++ b/libs/designer-ui/package.json @@ -69,7 +69,11 @@ "@lexical/html": "0.12.4", "@monaco-editor/react": "4.6.0", "react-infinite-scroll-component": "6.1.0", - "@fluentui/utilities": "8.13.16" + "@fluentui/utilities": "8.13.16", + "dompurify": "3.0.11" + }, + "devDependencies": { + "@types/dompurify": "3.0.5" }, "peerDependencies": { "react": "^16.4.0 || ^17.0.0 || ^18.0.0", diff --git a/libs/designer-ui/src/lib/html/plugins/toolbar/helper/util.ts b/libs/designer-ui/src/lib/html/plugins/toolbar/helper/util.ts index 6d9d7b8ce01..a787b64e21a 100644 --- a/libs/designer-ui/src/lib/html/plugins/toolbar/helper/util.ts +++ b/libs/designer-ui/src/lib/html/plugins/toolbar/helper/util.ts @@ -1,5 +1,6 @@ import { encodeStringSegmentTokensInDomContext } from '../../../../editor/base/utils/parsesegments'; import type { ValueSegment } from '@microsoft/logic-apps-shared'; +import DomPurify from 'dompurify'; const htmlUnsafeCharacters = ['<', '>']; const htmlUnsafeCharacterEncodingMap: Record = htmlUnsafeCharacters.reduce( @@ -95,12 +96,17 @@ export const encodeOrDecodeSegmentValue = (value: string, encodingMap: Record): HTMLElement => { - const encodedHtmlEditorString = encodeStringSegmentTokensInDomContext(htmlEditorString, nodeMap); + // Comments at the start of a DOM are lost when parsing HTML strings, so we wrap the HTML string in a
. + const wrappedHtmlEditorString = `
${htmlEditorString}
`; - const tempElement = document.createElement('div'); + const purifiedHtmlEditorString = DomPurify.sanitize(wrappedHtmlEditorString, { ADD_TAGS: ['#comment'] }); + const encodedHtmlEditorString = encodeStringSegmentTokensInDomContext(purifiedHtmlEditorString, nodeMap); + + const tempElement = document.createElement('div', {}); tempElement.innerHTML = encodedHtmlEditorString; - return tempElement; + // Unwrap the wrapper
. + return tempElement.children[0] as HTMLElement; }; export const isAttributeSupportedByHtmlEditor = (tagName: string, attribute: string): boolean => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8dbacfc29c6..e90b1cafd14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -682,6 +682,9 @@ importers: '@react-hookz/web': specifier: 22.0.0 version: 22.0.0(react-dom@18.2.0)(react@18.2.0) + dompurify: + specifier: 3.0.11 + version: 3.0.11 fuse.js: specifier: 6.6.2 version: 6.6.2 @@ -721,6 +724,10 @@ importers: reactflow: specifier: 11.8.2 version: 11.8.2(@types/react@18.2.73)(immer@9.0.15)(react-dom@18.2.0)(react@18.2.0) + devDependencies: + '@types/dompurify': + specifier: 3.0.5 + version: 3.0.5 libs/logic-apps-shared: dependencies: @@ -10783,6 +10790,12 @@ packages: dependencies: '@types/ms': 0.7.34 + /@types/dompurify@3.0.5: + resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==} + dependencies: + '@types/trusted-types': 2.0.7 + dev: true + /@types/eslint-scope@3.7.7: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} dependencies: @@ -11112,6 +11125,10 @@ packages: resolution: {integrity: sha512-JWCy93Z2bM/xYRcKjC2SOeU1PRYNOdZhD5ZUG8T1si9Tlau1M6UZ1wm7yR+avqdy51Du4BLEIaEB4axfPC4UKg==} dev: true + /@types/trusted-types@2.0.7: + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + dev: true + /@types/tunnel@0.0.3: resolution: {integrity: sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==} dependencies: @@ -14019,6 +14036,10 @@ packages: domelementtype: 2.3.0 dev: false + /dompurify@3.0.11: + resolution: {integrity: sha512-Fan4uMuyB26gFV3ovPoEoQbxRRPfTu3CvImyZnhGq5fsIEO+gEFLp45ISFt+kQBWsK5ulDdT0oV28jS1UrwQLg==} + dev: false + /domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} dependencies: