fix(lesson): sanitize lesson client side

This commit is contained in:
Raizaaa
2026-05-01 01:17:01 +05:30
parent 07ca95caa8
commit ad037e5f90
4 changed files with 44 additions and 6 deletions
+4 -1
View File
@@ -57,7 +57,7 @@
>
</iframe>
</div>
<div v-else v-html="markdown.render(block)"></div>
<div v-else v-html="renderSafe(block)"></div>
</div>
<div v-if="quizId">
<Quiz :quiz="quizId" />
@@ -66,6 +66,7 @@
<script setup>
import Quiz from '@/components/QuizBlock.vue'
import MarkdownIt from 'markdown-it'
import DOMPurify from 'dompurify'
import { useScreenSize } from '@/utils/composables'
const screenSize = useScreenSize()
@@ -75,6 +76,8 @@ const markdown = new MarkdownIt({
linkify: true,
})
const renderSafe = (block) => DOMPurify.sanitize(markdown.render(block))
const props = defineProps({
content: {
type: String,
+7 -2
View File
@@ -365,7 +365,12 @@ import {
MessageCircleQuestion,
TrendingUp,
} from 'lucide-vue-next'
import { getEditorTools, enablePlyr, highlightText } from '@/utils'
import {
getEditorTools,
enablePlyr,
highlightText,
sanitizeEditorJs,
} from '@/utils'
import { sessionStore } from '@/stores/session'
import { useSidebar } from '@/stores/sidebar'
import EditorJS from '@editorjs/editorjs'
@@ -511,7 +516,7 @@ const renderEditor = (holder, content) => {
return new EditorJS({
holder: holder,
tools: getEditorTools(),
data: JSON.parse(content),
data: sanitizeEditorJs(JSON.parse(content)),
readOnly: true,
defaultBlock: 'embed',
i18n: {
+5 -3
View File
@@ -104,7 +104,7 @@ import { sessionStore } from '../stores/session'
import EditorJS from '@editorjs/editorjs'
import LessonHelp from '@/components/LessonHelp.vue'
import { ChevronRight } from 'lucide-vue-next'
import { getEditorTools, enablePlyr } from '@/utils'
import { getEditorTools, enablePlyr, sanitizeEditorJs } from '@/utils'
import { useOnboarding, useTelemetry } from 'frappe-ui/frappe'
const { brand } = sessionStore()
@@ -191,7 +191,7 @@ const lessonDetails = createResource({
const addLessonContent = (data) => {
editor.value.isReady.then(() => {
if (data.lesson.content) {
editor.value.render(JSON.parse(data.lesson.content))
editor.value.render(sanitizeEditorJs(JSON.parse(data.lesson.content)))
} else if (data.lesson.body) {
let blocks = convertToJSON(data.lesson)
editor.value.render({
@@ -204,7 +204,9 @@ const addLessonContent = (data) => {
const addInstructorNotes = (data) => {
instructorEditor.value.isReady.then(() => {
if (data.lesson.instructor_content) {
instructorEditor.value.render(JSON.parse(data.lesson.instructor_content))
instructorEditor.value.render(
sanitizeEditorJs(JSON.parse(data.lesson.instructor_content))
)
} else if (data.lesson.instructor_notes) {
let blocks = convertToJSON(data.lesson)
instructorEditor.value.render({
+28
View File
@@ -706,6 +706,34 @@ export const escapeHTML = (text) => {
)
}
const sanitizeJSON = (node) => {
if (Array.isArray(node)) return node.map(sanitizeJSON)
if (node && typeof node === 'object') {
const temp = {}
for (const n in node) {
temp[n] = sanitizeJSON(node[n])
}
return temp
}
if (
typeof node === 'string' &&
(node.includes('<') || node.includes('>'))
) {
return DOMPurify.sanitize(node)
}
return node
}
export const sanitizeEditorJs = (data) => {
if (!data || !Array.isArray(data.blocks)) return data
for (const node of data.blocks) {
if (node && node.type !== 'code') {
node.data = sanitizeJSON(node.data)
}
}
return data
}
export const sanitizeHTML = (text) => {
text = DOMPurify.sanitize(decodeEntities(text), {
ALLOWED_TAGS: [