mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
fix: purify content in externalObjects
This commit is contained in:
parent
d8be321021
commit
bcd029d178
3 changed files with 45 additions and 5 deletions
|
|
@ -1,9 +1,10 @@
|
||||||
import { NodeViewWrapper } from '@tiptap/react'
|
import { NodeViewWrapper } from '@tiptap/react'
|
||||||
import React, { useState, useRef } from 'react'
|
import React, { useState, useRef, useEffect } from 'react'
|
||||||
import { Upload, Link as LinkIcon, GripVertical, GripHorizontal, AlignCenter, Cuboid, Code } from 'lucide-react'
|
import { Upload, Link as LinkIcon, GripVertical, GripHorizontal, AlignCenter, Cuboid, Code } from 'lucide-react'
|
||||||
import { useEditorProvider } from '@components/Contexts/Editor/EditorContext'
|
import { useEditorProvider } from '@components/Contexts/Editor/EditorContext'
|
||||||
import { SiGithub, SiReplit, SiSpotify, SiLoom, SiGooglemaps, SiCodepen, SiCanva, SiNotion, SiGoogledocs, SiGitlab, SiX, SiFigma, SiGiphy } from '@icons-pack/react-simple-icons'
|
import { SiGithub, SiReplit, SiSpotify, SiLoom, SiGooglemaps, SiCodepen, SiCanva, SiNotion, SiGoogledocs, SiGitlab, SiX, SiFigma, SiGiphy } from '@icons-pack/react-simple-icons'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
|
import DOMPurify from 'dompurify'
|
||||||
|
|
||||||
function EmbedObjectsComponent(props: any) {
|
function EmbedObjectsComponent(props: any) {
|
||||||
const [embedType, setEmbedType] = useState<'url' | 'code'>(props.node.attrs.embedType || 'url')
|
const [embedType, setEmbedType] = useState<'url' | 'code'>(props.node.attrs.embedType || 'url')
|
||||||
|
|
@ -33,6 +34,18 @@ function EmbedObjectsComponent(props: any) {
|
||||||
{ name: 'Giphy', icon: SiGiphy, color: '#FF6666', guide: 'https://developers.giphy.com/docs/embed/' },
|
{ name: 'Giphy', icon: SiGiphy, color: '#FF6666', guide: 'https://developers.giphy.com/docs/embed/' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const [sanitizedEmbedCode, setSanitizedEmbedCode] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (embedType === 'code' && embedCode) {
|
||||||
|
const sanitized = DOMPurify.sanitize(embedCode, {
|
||||||
|
ADD_TAGS: ['iframe'],
|
||||||
|
ADD_ATTR: ['*']
|
||||||
|
})
|
||||||
|
setSanitizedEmbedCode(sanitized)
|
||||||
|
}
|
||||||
|
}, [embedCode, embedType])
|
||||||
|
|
||||||
const handleEmbedTypeChange = (type: 'url' | 'code') => {
|
const handleEmbedTypeChange = (type: 'url' | 'code') => {
|
||||||
setEmbedType(type)
|
setEmbedType(type)
|
||||||
props.updateAttributes({ embedType: type })
|
props.updateAttributes({ embedType: type })
|
||||||
|
|
@ -40,9 +53,11 @@ function EmbedObjectsComponent(props: any) {
|
||||||
|
|
||||||
const handleUrlChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleUrlChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const newUrl = event.target.value;
|
const newUrl = event.target.value;
|
||||||
setEmbedUrl(newUrl);
|
// Sanitize the URL
|
||||||
|
const sanitizedUrl = DOMPurify.sanitize(newUrl);
|
||||||
|
setEmbedUrl(sanitizedUrl);
|
||||||
props.updateAttributes({
|
props.updateAttributes({
|
||||||
embedUrl: newUrl,
|
embedUrl: sanitizedUrl,
|
||||||
embedType: 'url',
|
embedType: 'url',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -113,8 +128,8 @@ function EmbedObjectsComponent(props: any) {
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
allowFullScreen
|
allowFullScreen
|
||||||
/>
|
/>
|
||||||
) : embedType === 'code' && embedCode ? (
|
) : embedType === 'code' && sanitizedEmbedCode ? (
|
||||||
<div dangerouslySetInnerHTML={{ __html: embedCode }} className="w-full h-full" />
|
<div dangerouslySetInnerHTML={{ __html: sanitizedEmbedCode }} className="w-full h-full" />
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full h-full flex flex-col items-center justify-center p-6">
|
<div className="w-full h-full flex flex-col items-center justify-center p-6">
|
||||||
<p className="text-gray-500 mb-4 font-medium tracking-tighter text-lg">Add an embed from :</p>
|
<p className="text-gray-500 mb-4 font-medium tracking-tighter text-lg">Add an embed from :</p>
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,13 @@
|
||||||
"@tiptap/pm": "^2.6.6",
|
"@tiptap/pm": "^2.6.6",
|
||||||
"@tiptap/react": "^2.6.6",
|
"@tiptap/react": "^2.6.6",
|
||||||
"@tiptap/starter-kit": "^2.6.6",
|
"@tiptap/starter-kit": "^2.6.6",
|
||||||
|
"@types/dompurify": "^3.0.5",
|
||||||
"@types/randomcolor": "^0.5.9",
|
"@types/randomcolor": "^0.5.9",
|
||||||
"avvvatars-react": "^0.4.2",
|
"avvvatars-react": "^0.4.2",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"dompurify": "^3.1.7",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"framer-motion": "^10.18.0",
|
"framer-motion": "^10.18.0",
|
||||||
"get-youtube-id": "^1.0.1",
|
"get-youtube-id": "^1.0.1",
|
||||||
|
|
|
||||||
23
apps/web/pnpm-lock.yaml
generated
23
apps/web/pnpm-lock.yaml
generated
|
|
@ -71,6 +71,9 @@ importers:
|
||||||
'@tiptap/starter-kit':
|
'@tiptap/starter-kit':
|
||||||
specifier: ^2.6.6
|
specifier: ^2.6.6
|
||||||
version: 2.6.6
|
version: 2.6.6
|
||||||
|
'@types/dompurify':
|
||||||
|
specifier: ^3.0.5
|
||||||
|
version: 3.0.5
|
||||||
'@types/randomcolor':
|
'@types/randomcolor':
|
||||||
specifier: ^0.5.9
|
specifier: ^0.5.9
|
||||||
version: 0.5.9
|
version: 0.5.9
|
||||||
|
|
@ -86,6 +89,9 @@ importers:
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.13
|
specifier: ^1.11.13
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
|
dompurify:
|
||||||
|
specifier: ^3.1.7
|
||||||
|
version: 3.1.7
|
||||||
formik:
|
formik:
|
||||||
specifier: ^2.4.6
|
specifier: ^2.4.6
|
||||||
version: 2.4.6(react@18.3.1)
|
version: 2.4.6(react@18.3.1)
|
||||||
|
|
@ -1520,6 +1526,9 @@ packages:
|
||||||
'@types/connect@3.4.36':
|
'@types/connect@3.4.36':
|
||||||
resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==}
|
resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==}
|
||||||
|
|
||||||
|
'@types/dompurify@3.0.5':
|
||||||
|
resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==}
|
||||||
|
|
||||||
'@types/estree@1.0.5':
|
'@types/estree@1.0.5':
|
||||||
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
||||||
|
|
||||||
|
|
@ -1580,6 +1589,9 @@ packages:
|
||||||
'@types/stylis@4.2.5':
|
'@types/stylis@4.2.5':
|
||||||
resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==}
|
resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==}
|
||||||
|
|
||||||
|
'@types/trusted-types@2.0.7':
|
||||||
|
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
||||||
|
|
||||||
'@types/unist@3.0.3':
|
'@types/unist@3.0.3':
|
||||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
||||||
|
|
||||||
|
|
@ -2066,6 +2078,9 @@ packages:
|
||||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
dompurify@3.1.7:
|
||||||
|
resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==}
|
||||||
|
|
||||||
dotenv@16.4.5:
|
dotenv@16.4.5:
|
||||||
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
|
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
@ -5326,6 +5341,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.2
|
'@types/node': 20.12.2
|
||||||
|
|
||||||
|
'@types/dompurify@3.0.5':
|
||||||
|
dependencies:
|
||||||
|
'@types/trusted-types': 2.0.7
|
||||||
|
|
||||||
'@types/estree@1.0.5': {}
|
'@types/estree@1.0.5': {}
|
||||||
|
|
||||||
'@types/hast@3.0.4':
|
'@types/hast@3.0.4':
|
||||||
|
|
@ -5401,6 +5420,8 @@ snapshots:
|
||||||
|
|
||||||
'@types/stylis@4.2.5': {}
|
'@types/stylis@4.2.5': {}
|
||||||
|
|
||||||
|
'@types/trusted-types@2.0.7': {}
|
||||||
|
|
||||||
'@types/unist@3.0.3': {}
|
'@types/unist@3.0.3': {}
|
||||||
|
|
||||||
'@types/use-sync-external-store@0.0.6': {}
|
'@types/use-sync-external-store@0.0.6': {}
|
||||||
|
|
@ -5945,6 +5966,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
||||||
|
dompurify@3.1.7: {}
|
||||||
|
|
||||||
dotenv@16.4.5: {}
|
dotenv@16.4.5: {}
|
||||||
|
|
||||||
eastasianwidth@0.2.0: {}
|
eastasianwidth@0.2.0: {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue