mirror of
https://github.com/frappe/lms.git
synced 2026-04-19 22:52:29 +03:00
fix: prevent path traversal in scorm file
This commit is contained in:
@@ -16,41 +16,49 @@ class SCORMRenderer(BaseRenderer):
|
||||
def can_render(self):
|
||||
return "scorm/" in self.path
|
||||
|
||||
def _is_safe_path(self, path):
|
||||
scorm_root = os.path.realpath(os.path.join(frappe.local.site_path, "public", "scorm"))
|
||||
resolved = os.path.realpath(path)
|
||||
return resolved.startswith(scorm_root + os.sep) or resolved == scorm_root
|
||||
|
||||
def _serve_file(self, path):
|
||||
f = open(path, "rb")
|
||||
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
|
||||
response.mimetype = mimetypes.guess_type(path)[0]
|
||||
return response
|
||||
|
||||
def render(self):
|
||||
path = os.path.join(frappe.local.site_path, "public", self.path.lstrip("/"))
|
||||
|
||||
if not self._is_safe_path(path):
|
||||
raise frappe.PermissionError
|
||||
|
||||
extension = os.path.splitext(path)[1]
|
||||
if not extension:
|
||||
path = f"{path}.html"
|
||||
|
||||
# check if path exists and is actually a file and not a folder
|
||||
if os.path.exists(path) and os.path.isfile(path):
|
||||
f = open(path, "rb")
|
||||
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
|
||||
response.mimetype = mimetypes.guess_type(path)[0]
|
||||
return response
|
||||
return self._serve_file(path)
|
||||
else:
|
||||
path = path.replace(".html", "")
|
||||
if os.path.exists(path) and os.path.isdir(path):
|
||||
index_path = os.path.join(path, "index.html")
|
||||
if os.path.exists(index_path):
|
||||
f = open(index_path, "rb")
|
||||
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
|
||||
response.mimetype = mimetypes.guess_type(index_path)[0]
|
||||
return response
|
||||
return self._serve_file(index_path)
|
||||
elif not os.path.exists(path):
|
||||
chapter_folder = "/".join(self.path.split("/")[:3])
|
||||
chapter_folder_path = os.path.realpath(frappe.get_site_path("public", chapter_folder))
|
||||
file = path.split("/")[-1]
|
||||
correct_file_path = None
|
||||
|
||||
if not self._is_safe_path(chapter_folder_path):
|
||||
raise frappe.PermissionError
|
||||
|
||||
for root, _dirs, files in os.walk(chapter_folder_path):
|
||||
if file in files:
|
||||
correct_file_path = os.path.join(root, file)
|
||||
break
|
||||
|
||||
if correct_file_path:
|
||||
f = open(correct_file_path, "rb")
|
||||
response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True)
|
||||
response.mimetype = mimetypes.guess_type(correct_file_path)[0]
|
||||
return response
|
||||
if correct_file_path and self._is_safe_path(correct_file_path):
|
||||
return self._serve_file(correct_file_path)
|
||||
|
||||
Reference in New Issue
Block a user