diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 91090bdd77..adf10b9a03 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -29,6 +29,7 @@ from frappe import _, conf, safe_decode from frappe.model.document import Document from frappe.utils import call_hook_method, cint, cstr, encode, get_files_path, get_hook_method, random_string, strip from frappe.utils.image import strip_exif_data, optimize_image +from frappe.utils.file_manager import safe_b64decode class MaxFileSizeReachedError(frappe.ValidationError): pass @@ -436,7 +437,7 @@ class File(Document): if b"," in self.content: self.content = self.content.split(b",")[1] - self.content = base64.b64decode(self.content) + self.content = safe_b64decode(self.content) if not self.is_private: self.is_private = 0 @@ -852,7 +853,7 @@ def extract_images_from_html(doc, content, is_private=False): content = content.encode("utf-8") if b"," in content: content = content.split(b",")[1] - content = base64.b64decode(content) + content = safe_b64decode(content) content = optimize_image(content, mtype) diff --git a/frappe/utils/file_manager.py b/frappe/utils/file_manager.py index 56394442f3..1e654d7881 100644 --- a/frappe/utils/file_manager.py +++ b/frappe/utils/file_manager.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE import frappe @@ -17,6 +17,20 @@ class MaxFileSizeReachedError(frappe.ValidationError): pass +def safe_b64decode(binary: bytes) -> bytes: + """Adds padding if doesn't already exist before decoding. + + This attempts to avoid the `binascii.Error: Incorrect padding` error raised + when the number of trailing = is simply not enough :crie:. Although, it may + be an indication of corrupted data. + + Refs: + * https://en.wikipedia.org/wiki/Base64 + * https://stackoverflow.com/questions/2941995/python-ignore-incorrect-padding-error-when-base64-decoding + """ + return base64.b64decode(binary + b"===") + + def get_file_url(file_data_name): data = frappe.db.get_value("File", file_data_name, ["file_name", "file_url"], as_dict=True) return data.file_url or data.file_name @@ -112,7 +126,7 @@ def get_uploaded_content(): if 'filedata' in frappe.form_dict: if "," in frappe.form_dict.filedata: frappe.form_dict.filedata = frappe.form_dict.filedata.rsplit(",", 1)[1] - frappe.uploaded_content = base64.b64decode(frappe.form_dict.filedata) + frappe.uploaded_content = safe_b64decode(frappe.form_dict.filedata) frappe.uploaded_filename = frappe.form_dict.filename return frappe.uploaded_filename, frappe.uploaded_content else: @@ -126,7 +140,7 @@ def save_file(fname, content, dt, dn, folder=None, decode=False, is_private=0, d if b"," in content: content = content.split(b",")[1] - content = base64.b64decode(content) + content = safe_b64decode(content) file_size = check_max_file_size(content) content_hash = get_content_hash(content)