summaryrefslogtreecommitdiff
path: root/cli/onionshare_cli/web/web.py
diff options
context:
space:
mode:
authorMicah Lee <micah@micahflee.com>2021-08-20 14:43:21 -0700
committerGitHub <noreply@github.com>2021-08-20 14:43:21 -0700
commitb66e742bc20ae977232fc53f22d485c10173ac2f (patch)
treec6eb66c340c34b45bac5525350c5eb5c43fe33a6 /cli/onionshare_cli/web/web.py
parent76104671c3eacbef53ad96fffd8a57512ab2d093 (diff)
parent02254b13bb4818745193092f2144fd83726d79e7 (diff)
downloadonionshare-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.py118
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 = []