diff --git a/openmetadata-ui/src/main/resources/ui/package.json b/openmetadata-ui/src/main/resources/ui/package.json index 39c29bf3615..8c092d98d00 100644 --- a/openmetadata-ui/src/main/resources/ui/package.json +++ b/openmetadata-ui/src/main/resources/ui/package.json @@ -87,6 +87,7 @@ "cronstrue": "^1.122.0", "crypto-random-string-with-promisify-polyfill": "^5.0.0", "diff": "^5.0.0", + "dompurify": "^3.1.5", "eventemitter3": "^5.0.1", "fast-json-patch": "^3.1.1", "history": "4.5.1", @@ -166,6 +167,7 @@ "@types/codemirror": "^0.0.104", "@types/dagre": "^0.7.47", "@types/diff": "^5.0.2", + "@types/dompurify": "^3.0.5", "@types/jest": "^26.0.23", "@types/lodash": "^4.14.167", "@types/luxon": "^3.0.1", diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/FeedEditor/FeedEditor.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/FeedEditor/FeedEditor.tsx index 1945312f266..359cfa5700c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/FeedEditor/FeedEditor.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/FeedEditor/FeedEditor.tsx @@ -44,6 +44,7 @@ import { } from '../../../utils/FeedUtils'; import { LinkBlot } from '../../../utils/QuillLink/QuillLink'; import { insertMention, insertRef } from '../../../utils/QuillUtils'; +import { getSanitizeContent } from '../../../utils/sanitize.utils'; import { getEntityIcon } from '../../../utils/TableUtils'; import { editorRef } from '../../common/RichTextEditor/RichTextEditor.interface'; import './feed-editor.less'; @@ -72,7 +73,9 @@ export const FeedEditor = forwardRef( ) => { const { t, i18n } = useTranslation(); const editorRef = useRef(null); - const [value, setValue] = useState(defaultValue ?? ''); + const [value, setValue] = useState(() => + getSanitizeContent(defaultValue ?? '') + ); const [isMentionListOpen, toggleMentionList] = useState(false); const [isFocused, toggleFocus] = useState(false); @@ -246,11 +249,14 @@ export const FeedEditor = forwardRef( /** * Handle onChange logic and set updated value to state - * @param value - updated value + * @param updatedValue - updated value */ - const handleOnChange = (value: string) => { - setValue(value); - onChangeHandler?.(value); + const handleOnChange = (updatedValue: string) => { + setValue(updatedValue); + + // sanitize the content before sending it to the parent component + const sanitizedContent = getSanitizeContent(updatedValue); + onChangeHandler?.(sanitizedContent); }; /** @@ -260,7 +266,8 @@ export const FeedEditor = forwardRef( getEditorValue() { setValue(''); - return HTMLToMarkdown.turndown(value); + // sanitize the content before sending it to the parent component + return HTMLToMarkdown.turndown(getSanitizeContent(value)); }, clearEditorValue() { setValue(''); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/sanitize.utils.test.ts b/openmetadata-ui/src/main/resources/ui/src/utils/sanitize.utils.test.ts new file mode 100644 index 00000000000..3ecaaac4079 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/utils/sanitize.utils.test.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { getSanitizeContent } from './sanitize.utils'; + +describe('getSanitizeContent', () => { + it('should sanitize the input 1', () => { + const mockHtml = `
`; + const result = getSanitizeContent(mockHtml); + + expect(result).toBe(`
`); + }); + + it('should sanitize the input 2', () => { + const mockHtml = ``; + const result = getSanitizeContent(mockHtml); + + expect(result).toBe(``); + }); + + it('should sanitize the input 3', () => { + const mockHtml = ``; + const result = getSanitizeContent(mockHtml); + + expect(result).toBe(``); + }); + + it('should sanitize the input 4', () => { + const mockHtml = `

abc