Register the 405 error handler properly. Enforce the appropriate methods for each route (GET or POST only, with OPTIONS disabled). Add tests for invalid methods. Add a friendlier 500 internal server error handler

This commit is contained in:
Miguel Jacq 2021-05-10 11:23:44 +10:00
parent 5226a3b671
commit 92027345d0
11 changed files with 120 additions and 13 deletions

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>OnionShare: An error occurred</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{{ static_url_path }}/img/favicon.ico" rel="icon" type="image/x-icon">
<link rel="stylesheet" rel="subresource" type="text/css" href="{{ static_url_path }}/css/style.css" media="all">
</head>
<body>
<div class="info-wrapper">
<div class="info">
<p><img class="logo" src="{{ static_url_path }}/img/logo_large.png" title="OnionShare"></p>
<p class="info-header">Sorry, an unexpected error seems to have occurred, and your request didn't succeed.</p>
</div>
</div>
</body>
</html>

View file

@ -46,7 +46,7 @@ class ChatModeWeb:
The web app routes for chatting
"""
@self.web.app.route("/")
@self.web.app.route("/", methods=["GET"], provide_automatic_options=False)
def index():
history_id = self.cur_history_id
self.cur_history_id += 1

View file

@ -71,7 +71,7 @@ class ReceiveModeWeb:
The web app routes for receiving files
"""
@self.web.app.route("/")
@self.web.app.route("/", methods=["GET"], provide_automatic_options=False)
def index():
history_id = self.cur_history_id
self.cur_history_id += 1
@ -93,7 +93,7 @@ class ReceiveModeWeb:
)
return self.web.add_security_headers(r)
@self.web.app.route("/upload", methods=["POST"])
@self.web.app.route("/upload", methods=["POST"], provide_automatic_options=False)
def upload(ajax=False):
"""
Handle the upload files POST request, though at this point, the files have
@ -225,7 +225,7 @@ class ReceiveModeWeb:
)
return self.web.add_security_headers(r)
@self.web.app.route("/upload-ajax", methods=["POST"])
@self.web.app.route("/upload-ajax", methods=["POST"], provide_automatic_options=False)
def upload_ajax_public():
if not self.can_upload:
return self.web.error403()

View file

@ -208,10 +208,6 @@ class SendBaseModeWeb:
history_id = self.cur_history_id
self.cur_history_id += 1
# Only GET requests are allowed, any other method should fail
if request.method != "GET":
return self.web.error405(history_id)
self.web.add_request(
self.web.REQUEST_INDIVIDUAL_FILE_STARTED,
path,

View file

@ -134,8 +134,8 @@ class ShareModeWeb(SendBaseModeWeb):
The web app routes for sharing files
"""
@self.web.app.route("/", defaults={"path": ""})
@self.web.app.route("/<path:path>")
@self.web.app.route("/", defaults={"path": ""}, methods=["GET"], provide_automatic_options=False)
@self.web.app.route("/<path:path>", methods=["GET"], provide_automatic_options=False)
def index(path):
"""
Render the template for the onionshare landing page.
@ -160,7 +160,7 @@ class ShareModeWeb(SendBaseModeWeb):
return self.render_logic(path)
@self.web.app.route("/download")
@self.web.app.route("/download", methods=["GET"], provide_automatic_options=False)
def download():
"""
Download the zip file.

View file

@ -229,6 +229,20 @@ class Web:
mode.cur_history_id += 1
return self.error404(history_id)
@self.app.errorhandler(405)
def method_not_allowed(e):
mode = self.get_mode()
history_id = mode.cur_history_id
mode.cur_history_id += 1
return self.error405(history_id)
@self.app.errorhandler(500)
def method_not_allowed(e):
mode = self.get_mode()
history_id = mode.cur_history_id
mode.cur_history_id += 1
return self.error500(history_id)
@self.app.route("/<password_candidate>/shutdown")
def shutdown(password_candidate):
"""
@ -305,6 +319,19 @@ class Web:
)
return self.add_security_headers(r)
def error500(self, history_id):
self.add_request(
self.REQUEST_INDIVIDUAL_FILE_STARTED,
request.path,
{"id": history_id, "status_code": 500},
)
self.add_request(Web.REQUEST_OTHER, request.path)
r = make_response(
render_template("500.html", static_url_path=self.static_url_path), 405
)
return self.add_security_headers(r)
def add_security_headers(self, r):
"""
Add security headers to a request

View file

@ -37,8 +37,8 @@ class WebsiteModeWeb(SendBaseModeWeb):
The web app routes for sharing a website
"""
@self.web.app.route("/", defaults={"path": ""})
@self.web.app.route("/<path:path>")
@self.web.app.route("/", defaults={"path": ""}, methods=["GET", "POST"], provide_automatic_options=False)
@self.web.app.route("/<path:path>", methods=["GET", "POST"], provide_automatic_options=False)
def path_public(path):
return path_logic(path)