seitime-frappe/frappe/handler.py
Chinmay D. Pai 23b3f65b3b
fix: limit file upload mimetype if user has no desk access
limits file upload mimetype to jpg, png, and pdf in case the user does
not have desk access, to prevent abuse of the servers as a file storage
system

Signed-off-by: Chinmay D. Pai <chinmaydpai@gmail.com>
2020-04-16 14:09:59 +05:30

217 lines
5.9 KiB
Python
Executable file

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
import frappe.utils
import frappe.sessions
import frappe.desk.form.run_method
from frappe.utils.response import build_response
from frappe.api import validate_auth
from frappe.utils import cint
from frappe.core.doctype.server_script.server_script_utils import run_server_script_api
from werkzeug.wrappers import Response
from six import string_types
def handle():
"""handle request"""
validate_auth()
cmd = frappe.local.form_dict.cmd
data = None
if cmd!='login':
data = execute_cmd(cmd)
# data can be an empty string or list which are valid responses
if data is not None:
if isinstance(data, Response):
# method returns a response object, pass it on
return data
# add the response to `message` label
frappe.response['message'] = data
return build_response("json")
def execute_cmd(cmd, from_async=False):
"""execute a request as python module"""
for hook in frappe.get_hooks("override_whitelisted_methods", {}).get(cmd, []):
# override using the first hook
cmd = hook
break
# via server script
if run_server_script_api(cmd):
return None
try:
method = get_attr(cmd)
except Exception as e:
if frappe.local.conf.developer_mode:
raise e
else:
frappe.respond_as_web_page(title='Invalid Method', html='Method not found',
indicator_color='red', http_status_code=404)
return
if from_async:
method = method.queue
is_whitelisted(method)
return frappe.call(method, **frappe.form_dict)
def is_whitelisted(method):
# check if whitelisted
if frappe.session['user'] == 'Guest':
if (method not in frappe.guest_methods):
frappe.msgprint(_("Not permitted"))
raise frappe.PermissionError('Not Allowed, {0}'.format(method))
if method not in frappe.xss_safe_methods:
# strictly sanitize form_dict
# escapes html characters like <> except for predefined tags like a, b, ul etc.
for key, value in frappe.form_dict.items():
if isinstance(value, string_types):
frappe.form_dict[key] = frappe.utils.sanitize_html(value)
else:
if not method in frappe.whitelisted:
frappe.msgprint(_("Not permitted"))
raise frappe.PermissionError('Not Allowed, {0}'.format(method))
@frappe.whitelist(allow_guest=True)
def version():
return frappe.__version__
@frappe.whitelist()
def runserverobj(method, docs=None, dt=None, dn=None, arg=None, args=None):
frappe.desk.form.run_method.runserverobj(method, docs=docs, dt=dt, dn=dn, arg=arg, args=args)
@frappe.whitelist(allow_guest=True)
def logout():
frappe.local.login_manager.logout()
frappe.db.commit()
@frappe.whitelist(allow_guest=True)
def web_logout():
frappe.local.login_manager.logout()
frappe.db.commit()
frappe.respond_as_web_page(_("Logged Out"), _("You have been successfully logged out"),
indicator_color='green')
@frappe.whitelist(allow_guest=True)
def run_custom_method(doctype, name, custom_method):
"""cmd=run_custom_method&doctype={doctype}&name={name}&custom_method={custom_method}"""
doc = frappe.get_doc(doctype, name)
if getattr(doc, custom_method, frappe._dict()).is_whitelisted:
frappe.call(getattr(doc, custom_method), **frappe.local.form_dict)
else:
frappe.throw(_("Not permitted"), frappe.PermissionError)
@frappe.whitelist()
def uploadfile():
ret = None
try:
if frappe.form_dict.get('from_form'):
try:
ret = frappe.get_doc({
"doctype": "File",
"attached_to_name": frappe.form_dict.docname,
"attached_to_doctype": frappe.form_dict.doctype,
"attached_to_field": frappe.form_dict.docfield,
"file_url": frappe.form_dict.file_url,
"file_name": frappe.form_dict.filename,
"is_private": frappe.utils.cint(frappe.form_dict.is_private),
"content": frappe.form_dict.filedata,
"decode": True
})
ret.save()
except frappe.DuplicateEntryError:
# ignore pass
ret = None
frappe.db.rollback()
else:
if frappe.form_dict.get('method'):
method = frappe.get_attr(frappe.form_dict.method)
is_whitelisted(method)
ret = method()
except Exception:
frappe.errprint(frappe.utils.get_traceback())
frappe.response['http_status_code'] = 500
ret = None
return ret
@frappe.whitelist(allow_guest=True)
def upload_file():
user = None
if frappe.session.user == 'Guest':
if frappe.get_system_settings('allow_guests_to_upload_files'):
ignore_permissions = True
else:
return
else:
user = frappe.get_doc("User", frappe.session.user)
ignore_permissions = False
files = frappe.request.files
is_private = frappe.form_dict.is_private
doctype = frappe.form_dict.doctype
docname = frappe.form_dict.docname
fieldname = frappe.form_dict.fieldname
file_url = frappe.form_dict.file_url
folder = frappe.form_dict.folder or 'Home'
method = frappe.form_dict.method
content = None
filename = None
if 'file' in files:
file = files['file']
content = file.stream.read()
filename = file.filename
frappe.local.uploaded_file = content
frappe.local.uploaded_filename = filename
if frappe.session.user == 'Guest' or (user and not user.has_desk_access()):
import mimetypes
filetype = mimetypes.guess_type(filename)[0]
if filetype not in ['image/png', 'image/jpeg', 'application/pdf']:
frappe.throw("You can only upload JPG, PNG or PDF files.")
if method:
method = frappe.get_attr(method)
is_whitelisted(method)
return method()
else:
ret = frappe.get_doc({
"doctype": "File",
"attached_to_doctype": doctype,
"attached_to_name": docname,
"attached_to_field": fieldname,
"folder": folder,
"file_name": filename,
"file_url": file_url,
"is_private": cint(is_private),
"content": content
})
ret.save(ignore_permissions=ignore_permissions)
return ret
def get_attr(cmd):
"""get method object from cmd"""
if '.' in cmd:
method = frappe.get_attr(cmd)
else:
method = globals()[cmd]
frappe.log("method:" + cmd)
return method
@frappe.whitelist(allow_guest = True)
def ping():
return "pong"