diff options
author | Micah Lee <micah@micahflee.com> | 2021-08-20 14:43:21 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-20 14:43:21 -0700 |
commit | b66e742bc20ae977232fc53f22d485c10173ac2f (patch) | |
tree | c6eb66c340c34b45bac5525350c5eb5c43fe33a6 /cli/onionshare_cli/web/web.py | |
parent | 76104671c3eacbef53ad96fffd8a57512ab2d093 (diff) | |
parent | 02254b13bb4818745193092f2144fd83726d79e7 (diff) | |
download | onionshare-b66e742bc20ae977232fc53f22d485c10173ac2f.tar.gz onionshare-b66e742bc20ae977232fc53f22d485c10173ac2f.zip |
Merge pull request #1395 from onionshare/developv2.3.3
Version 2.3.3, merge develop into stable
Diffstat (limited to 'cli/onionshare_cli/web/web.py')
-rw-r--r-- | cli/onionshare_cli/web/web.py | 118 |
1 files changed, 86 insertions, 32 deletions
diff --git a/cli/onionshare_cli/web/web.py b/cli/onionshare_cli/web/web.py index 6f4986e7..04919185 100644 --- a/cli/onionshare_cli/web/web.py +++ b/cli/onionshare_cli/web/web.py @@ -17,17 +17,12 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ - -import hmac import logging import os import queue -import socket -import sys -import tempfile import requests +import shutil from distutils.version import LooseVersion as Version -from urllib.request import urlopen import flask from flask import ( @@ -47,6 +42,7 @@ from .receive_mode import ReceiveModeWeb, ReceiveModeWSGIMiddleware, ReceiveMode from .website_mode import WebsiteModeWeb from .chat_mode import ChatModeWeb + # Stub out flask's show_server_banner function, to avoiding showing warnings that # are not applicable to OnionShare def stubbed_show_server_banner(env, debug, app_import_path, eager_loading): @@ -55,7 +51,7 @@ def stubbed_show_server_banner(env, debug, app_import_path, eager_loading): try: flask.cli.show_server_banner = stubbed_show_server_banner -except: +except Exception: pass @@ -69,16 +65,17 @@ class Web: REQUEST_PROGRESS = 2 REQUEST_CANCELED = 3 REQUEST_RATE_LIMIT = 4 - REQUEST_UPLOAD_FILE_RENAMED = 5 - REQUEST_UPLOAD_SET_DIR = 6 - REQUEST_UPLOAD_FINISHED = 7 - REQUEST_UPLOAD_CANCELED = 8 - REQUEST_INDIVIDUAL_FILE_STARTED = 9 - REQUEST_INDIVIDUAL_FILE_PROGRESS = 10 - REQUEST_INDIVIDUAL_FILE_CANCELED = 11 - REQUEST_ERROR_DATA_DIR_CANNOT_CREATE = 12 - REQUEST_OTHER = 13 - REQUEST_INVALID_PASSWORD = 14 + REQUEST_UPLOAD_INCLUDES_MESSAGE = 5 + REQUEST_UPLOAD_FILE_RENAMED = 6 + REQUEST_UPLOAD_SET_DIR = 7 + REQUEST_UPLOAD_FINISHED = 8 + REQUEST_UPLOAD_CANCELED = 9 + REQUEST_INDIVIDUAL_FILE_STARTED = 10 + REQUEST_INDIVIDUAL_FILE_PROGRESS = 11 + REQUEST_INDIVIDUAL_FILE_CANCELED = 12 + REQUEST_ERROR_DATA_DIR_CANNOT_CREATE = 13 + REQUEST_OTHER = 14 + REQUEST_INVALID_PASSWORD = 15 def __init__(self, common, is_gui, mode_settings, mode="share"): self.common = common @@ -166,6 +163,8 @@ class Web: self.socketio.init_app(self.app) self.chat_mode = ChatModeWeb(self.common, self) + self.cleanup_filenames = [] + def get_mode(self): if self.mode == "share": return self.share_mode @@ -192,7 +191,6 @@ class Web: self.app.static_url_path = self.static_url_path self.app.add_url_rule( self.static_url_path + "/<path:filename>", - endpoint="static", view_func=self.app.send_static_file, ) @@ -230,6 +228,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): """ @@ -281,11 +293,13 @@ class Web: return self.add_security_headers(r) def error404(self, history_id): - self.add_request( - self.REQUEST_INDIVIDUAL_FILE_STARTED, - request.path, - {"id": history_id, "status_code": 404}, - ) + mode = self.get_mode() + if mode.supports_file_requests: + self.add_request( + self.REQUEST_INDIVIDUAL_FILE_STARTED, + request.path, + {"id": history_id, "status_code": 404}, + ) self.add_request(Web.REQUEST_OTHER, request.path) r = make_response( @@ -294,11 +308,13 @@ class Web: return self.add_security_headers(r) def error405(self, history_id): - self.add_request( - self.REQUEST_INDIVIDUAL_FILE_STARTED, - request.path, - {"id": history_id, "status_code": 405}, - ) + mode = self.get_mode() + if mode.supports_file_requests: + self.add_request( + self.REQUEST_INDIVIDUAL_FILE_STARTED, + request.path, + {"id": history_id, "status_code": 405}, + ) self.add_request(Web.REQUEST_OTHER, request.path) r = make_response( @@ -306,6 +322,21 @@ class Web: ) return self.add_security_headers(r) + def error500(self, history_id): + mode = self.get_mode() + if mode.supports_file_requests: + 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), 500 + ) + return self.add_security_headers(r) + def add_security_headers(self, r): """ Add security headers to a request @@ -316,7 +347,7 @@ class Web: if not self.settings.get("website", "disable_csp") or self.mode != "website": r.headers.set( "Content-Security-Policy", - "default-src 'self'; style-src 'self'; script-src 'self'; img-src 'self' data:;", + "default-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; img-src 'self' data:;", ) return r @@ -333,7 +364,7 @@ class Web: def generate_password(self, saved_password=None): self.common.log("Web", "generate_password", f"saved_password={saved_password}") - if saved_password != None and saved_password != "": + if saved_password is not None and saved_password != "": self.password = saved_password self.common.log( "Web", @@ -366,13 +397,18 @@ class Web: # Shutdown the flask service try: func = request.environ.get("werkzeug.server.shutdown") - if func is None: + if func is None and self.mode != "chat": raise RuntimeError("Not running with the Werkzeug Server") func() - except: + except Exception: pass + self.running = False + # If chat, shutdown the socket server + if self.mode == "chat": + self.socketio.stop() + def start(self, port): """ Start the flask web server. @@ -422,3 +458,21 @@ class Web: # Reset any password that was in use self.password = None + + def cleanup(self): + """ + Shut everything down and clean up temporary files, etc. + """ + self.common.log("Web", "cleanup") + + # Cleanup files + try: + for filename in self.cleanup_filenames: + if os.path.isfile(filename): + os.remove(filename) + elif os.path.isdir(filename): + shutil.rmtree(filename) + except Exception: + # Don't crash if file is still in use + pass + self.cleanup_filenames = [] |