From 47b5b603c74144903dc13873224db80e50991748 Mon Sep 17 00:00:00 2001 From: Raizaaa <89463672+raizasafeel@users.noreply.github.com> Date: Fri, 1 May 2026 01:15:50 +0530 Subject: [PATCH 1/3] fix(lesson): sanitize lesson server side --- .../doctype/course_lesson/course_lesson.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lms/lms/doctype/course_lesson/course_lesson.py b/lms/lms/doctype/course_lesson/course_lesson.py index 2b23a3af..c988840f 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.py +++ b/lms/lms/doctype/course_lesson/course_lesson.py @@ -7,6 +7,7 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.realtime import get_website_room +from frappe.utils.html_utils import sanitize_html from frappe.utils.telemetry import capture from lms.lms.utils import get_course_progress, is_demo_course, recalculate_course_progress @@ -21,6 +22,10 @@ class CourseLesson(Document): def after_delete(self): self.validate_progress_recalculation() + def validate(self): + self.content = sanitize_editorjs(self.content) + self.instructor_content = sanitize_editorjs(self.instructor_content) + def on_update(self): self.validate_quiz_id() @@ -69,6 +74,24 @@ class CourseLesson(Document): ) +def sanitize_editorjs(raw): + try: + data = json.loads(raw) + except (TypeError, ValueError): + return raw + return json.dumps(sanitize_json(data), separators=(",", ":")) + + +def sanitize_json(node): + if isinstance(node, dict): + return {k: sanitize_json(v) for k, v in node.items()} + if isinstance(node, list): + return [sanitize_json(v) for v in node] + if isinstance(node, str) and ("<" in node or ">" in node): + return sanitize_html(node, always_sanitize=True) + return node + + @frappe.whitelist() def save_progress(lesson: str, course: str, scorm_details: dict = None): """ From 07ca95caa87650ceb1e2cbc13036c06f832fe266 Mon Sep 17 00:00:00 2001 From: Raizaaa <89463672+raizasafeel@users.noreply.github.com> Date: Fri, 1 May 2026 01:34:05 +0530 Subject: [PATCH 2/3] fix(lesson): sanitize lesson server side --- .../doctype/course_lesson/course_lesson.py | 21 +------------------ lms/lms/utils.py | 19 +++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lms/lms/doctype/course_lesson/course_lesson.py b/lms/lms/doctype/course_lesson/course_lesson.py index c988840f..74d2eecd 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.py +++ b/lms/lms/doctype/course_lesson/course_lesson.py @@ -7,10 +7,9 @@ import frappe from frappe import _ from frappe.model.document import Document from frappe.realtime import get_website_room -from frappe.utils.html_utils import sanitize_html from frappe.utils.telemetry import capture -from lms.lms.utils import get_course_progress, is_demo_course, recalculate_course_progress +from lms.lms.utils import get_course_progress, is_demo_course, recalculate_course_progress, sanitize_editorjs from ...md import find_macros @@ -74,24 +73,6 @@ class CourseLesson(Document): ) -def sanitize_editorjs(raw): - try: - data = json.loads(raw) - except (TypeError, ValueError): - return raw - return json.dumps(sanitize_json(data), separators=(",", ":")) - - -def sanitize_json(node): - if isinstance(node, dict): - return {k: sanitize_json(v) for k, v in node.items()} - if isinstance(node, list): - return [sanitize_json(v) for v in node] - if isinstance(node, str) and ("<" in node or ">" in node): - return sanitize_html(node, always_sanitize=True) - return node - - @frappe.whitelist() def save_progress(lesson: str, course: str, scorm_details: dict = None): """ diff --git a/lms/lms/utils.py b/lms/lms/utils.py index cde978cb..c44942fa 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -25,6 +25,7 @@ from frappe.utils import ( rounded, validate_email_address, ) +from frappe.utils.html_utils import sanitize_html from pypika import Case from pypika import functions as fn @@ -2398,3 +2399,21 @@ def get_field_meta(doctype, fieldnames): def is_demo_course(course: str) -> bool: title = frappe.db.get_value("LMS Course", course, "title") return title == "A guide to Frappe Learning" + + +def sanitize_editorjs(raw): + try: + data = json.loads(raw) + except (TypeError, ValueError): + return raw + return json.dumps(sanitize_json(data), separators=(",", ":")) + + +def sanitize_json(node): + if isinstance(node, dict): + return {k: sanitize_json(v) for k, v in node.items()} + if isinstance(node, list): + return [sanitize_json(v) for v in node] + if isinstance(node, str) and ("<" in node or ">" in node): + return sanitize_html(node, always_sanitize=True) + return node From ad037e5f905020fcbfd8c53d16d65d7d463ca322 Mon Sep 17 00:00:00 2001 From: Raizaaa <89463672+raizasafeel@users.noreply.github.com> Date: Fri, 1 May 2026 01:17:01 +0530 Subject: [PATCH 3/3] fix(lesson): sanitize lesson client side --- frontend/src/components/LessonContent.vue | 5 +++- frontend/src/pages/Lesson.vue | 9 ++++++-- frontend/src/pages/LessonForm.vue | 8 ++++--- frontend/src/utils/index.js | 28 +++++++++++++++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/LessonContent.vue b/frontend/src/components/LessonContent.vue index 2bb686c4..5f294073 100644 --- a/frontend/src/components/LessonContent.vue +++ b/frontend/src/components/LessonContent.vue @@ -57,7 +57,7 @@ > -
+
@@ -66,6 +66,7 @@