Merge branch 'develop' into 929_download_errors

This commit is contained in:
Micah Lee 2020-11-29 09:25:40 -08:00
commit 872dacb8e4
8 changed files with 148 additions and 95 deletions

View File

@ -22,7 +22,14 @@ from stem.control import Controller
from stem import ProtocolError, SocketClosed from stem import ProtocolError, SocketClosed
from stem.connection import MissingPassword, UnreadableCookieFile, AuthenticationFailure from stem.connection import MissingPassword, UnreadableCookieFile, AuthenticationFailure
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
import base64, os, sys, tempfile, shutil, urllib, platform, subprocess, time, shlex import base64
import os
import tempfile
import subprocess
import time
import shlex
import getpass
import psutil
from distutils.version import LooseVersion as Version from distutils.version import LooseVersion as Version
from . import common from . import common
@ -109,13 +116,6 @@ class TorTooOld(Exception):
pass pass
class BundledTorNotSupported(Exception):
"""
This exception is raised if onionshare is set to use the bundled Tor binary,
but it's not supported on that platform, or in dev mode.
"""
class BundledTorTimeout(Exception): class BundledTorTimeout(Exception):
""" """
This exception is raised if onionshare is set to use the bundled Tor binary, This exception is raised if onionshare is set to use the bundled Tor binary,
@ -158,14 +158,6 @@ class Onion(object):
self.use_tmp_dir = use_tmp_dir self.use_tmp_dir = use_tmp_dir
# Is bundled tor supported?
if (
self.common.platform == "Windows" or self.common.platform == "Darwin"
) and getattr(sys, "onionshare_dev_mode", False):
self.bundle_tor_supported = False
else:
self.bundle_tor_supported = True
# Set the path of the tor binary, for bundled tor # Set the path of the tor binary, for bundled tor
if not get_tor_paths: if not get_tor_paths:
get_tor_paths = self.common.get_tor_paths get_tor_paths = self.common.get_tor_paths
@ -221,12 +213,6 @@ class Onion(object):
self.c = None self.c = None
if self.settings.get("connection_type") == "bundled": if self.settings.get("connection_type") == "bundled":
if not self.bundle_tor_supported:
raise BundledTorNotSupported(
# strings._("settings_error_bundled_tor_not_supported")
"Using the Tor version that comes with OnionShare does not work in developer mode on Windows or macOS."
)
# Create a torrc for this session # Create a torrc for this session
if self.use_tmp_dir: if self.use_tmp_dir:
self.tor_data_directory = tempfile.TemporaryDirectory( self.tor_data_directory = tempfile.TemporaryDirectory(
@ -253,6 +239,26 @@ class Onion(object):
raise OSError("OnionShare port not available") raise OSError("OnionShare port not available")
self.tor_torrc = os.path.join(self.tor_data_directory_name, "torrc") self.tor_torrc = os.path.join(self.tor_data_directory_name, "torrc")
# If there is an existing OnionShare tor process, kill it
for proc in psutil.process_iter(["pid", "name", "username"]):
try:
cmdline = proc.cmdline()
if (
cmdline[0] == self.tor_path
and cmdline[1] == "-f"
and cmdline[2] == self.tor_torrc
):
self.common.log(
"Onion",
"connect",
"found a stale tor process, killing it",
)
proc.terminate()
proc.wait()
break
except:
pass
if self.common.platform == "Windows" or self.common.platform == "Darwin": if self.common.platform == "Windows" or self.common.platform == "Darwin":
# Windows doesn't support unix sockets, so it must use a network port. # Windows doesn't support unix sockets, so it must use a network port.
# macOS can't use unix sockets either because socket filenames are limited to # macOS can't use unix sockets either because socket filenames are limited to

View File

@ -1,55 +1,59 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<title>OnionShare</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 href="{{ static_url_path }}/css/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<header class="clearfix"> <head>
<img class="logo" src="{{ static_url_path }}/img/logo.png" title="OnionShare"> <title>OnionShare</title>
<h1>OnionShare</h1> <meta charset="utf-8" />
</header> <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 href="{{ static_url_path }}/css/style.css" rel="stylesheet" type="text/css" />
</head>
{% if breadcrumbs %} <body>
<ul class="breadcrumbs">
{% for breadcrumb in breadcrumbs %}<li><a href="{{ breadcrumb[1] }}">{{ breadcrumb[0] }}</a> <span class="sep">&#8227;</span></li>{% endfor %}<li>{{ breadcrumbs_leaf }}</li>
</ul>
{% endif %}
<table class="file-list" id="file-list"> <header class="clearfix">
<tr> <img class="logo" src="{{ static_url_path }}/img/logo.png" title="OnionShare">
<th id="filename-header">Filename</th> <h1>OnionShare</h1>
<th id="size-header">Size</th> </header>
<th></th>
</tr>
{% for info in dirs %} {% if breadcrumbs %}
<tr> <ul class="breadcrumbs">
<td> {% for breadcrumb in breadcrumbs %}<li><a href="{{ breadcrumb[1] }}">{{ breadcrumb[0] }}</a> <span
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_folder.png" /> class="sep">&#8227;</span></li>{% endfor %}<li>{{ breadcrumbs_leaf }}</li>
<a href="{{ info.basename }}"> </ul>
{{ info.basename }} {% endif %}
</a>
</td>
<td>&mdash;</td>
</tr>
{% endfor %}
{% for info in files %} <table class="file-list" id="file-list">
<tr> <tr>
<td> <th id="filename-header">Filename</th>
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_file.png" /> <th id="size-header">Size</th>
<a href="{{ info.basename }}"> <th></th>
{{ info.basename }} </tr>
</a>
</td> {% for info in dirs %}
<td>{{ info.size_human }}</td> <tr>
</tr> <td>
{% endfor %} <img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_folder.png" />
</table> <a href="{{ info.link }}">
</body> {{ info.basename }}
</html> </a>
</td>
<td>&mdash;</td>
</tr>
{% endfor %}
{% for info in files %}
<tr>
<td>
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_file.png" />
<a href="{{ info.link }}">
{{ info.basename }}
</a>
</td>
<td>{{ info.size_human }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>

View File

@ -85,7 +85,7 @@ class SendBaseModeWeb:
# If it's a directory, add it recursively # If it's a directory, add it recursively
elif os.path.isdir(filename): elif os.path.isdir(filename):
self.root_files[basename + "/"] = filename self.root_files[basename] = filename
for root, _, nested_filenames in os.walk(filename): for root, _, nested_filenames in os.walk(filename):
# Normalize the root path. So if the directory name is "/home/user/Documents/some_folder", # Normalize the root path. So if the directory name is "/home/user/Documents/some_folder",
@ -96,7 +96,7 @@ class SendBaseModeWeb:
).rstrip("/") ).rstrip("/")
# Add the dir itself # Add the dir itself
self.files[normalized_root + "/"] = root self.files[normalized_root] = root
# Add the files in this dir # Add the files in this dir
for nested_filename in nested_filenames: for nested_filename in nested_filenames:
@ -117,19 +117,21 @@ class SendBaseModeWeb:
) )
breadcrumbs = [("", "/")] breadcrumbs = [("", "/")]
parts = path.split("/")[:-1] parts = path.split("/")
if parts[-1] == "":
parts = parts[:-1]
for i in range(len(parts)): for i in range(len(parts)):
breadcrumbs.append((parts[i], f"/{'/'.join(parts[0 : i + 1])}/")) breadcrumbs.append((parts[i], f"/{'/'.join(parts[0 : i + 1])}"))
breadcrumbs_leaf = breadcrumbs.pop()[0] breadcrumbs_leaf = breadcrumbs.pop()[0]
# If filesystem_path is None, this is the root directory listing # If filesystem_path is None, this is the root directory listing
files, dirs = self.build_directory_listing(filenames, filesystem_path) files, dirs = self.build_directory_listing(path, filenames, filesystem_path)
r = self.directory_listing_template( r = self.directory_listing_template(
path, files, dirs, breadcrumbs, breadcrumbs_leaf path, files, dirs, breadcrumbs, breadcrumbs_leaf
) )
return self.web.add_security_headers(r) return self.web.add_security_headers(r)
def build_directory_listing(self, filenames, filesystem_path): def build_directory_listing(self, path, filenames, filesystem_path):
files = [] files = []
dirs = [] dirs = []
@ -142,11 +144,20 @@ class SendBaseModeWeb:
is_dir = os.path.isdir(this_filesystem_path) is_dir = os.path.isdir(this_filesystem_path)
if is_dir: if is_dir:
dirs.append({"basename": filename}) dirs.append(
{"link": os.path.join(f"/{path}", filename), "basename": filename}
)
else: else:
size = os.path.getsize(this_filesystem_path) size = os.path.getsize(this_filesystem_path)
size_human = self.common.human_readable_filesize(size) size_human = self.common.human_readable_filesize(size)
files.append({"basename": filename, "size_human": size_human}) files.append(
{
"link": os.path.join(f"/{path}", filename),
"basename": filename,
"size_human": size_human,
}
)
return files, dirs return files, dirs
def stream_individual_file(self, filesystem_path): def stream_individual_file(self, filesystem_path):

View File

@ -71,6 +71,9 @@ class WebsiteModeWeb(SendBaseModeWeb):
self.web.cancel_compression = True self.web.cancel_compression = True
def render_logic(self, path=""): def render_logic(self, path=""):
# Strip trailing slash
path = path.rstrip("/")
if path in self.files: if path in self.files:
filesystem_path = self.files[path] filesystem_path = self.files[path]
@ -86,10 +89,7 @@ class WebsiteModeWeb(SendBaseModeWeb):
# Otherwise, render directory listing # Otherwise, render directory listing
filenames = [] filenames = []
for filename in os.listdir(filesystem_path): for filename in os.listdir(filesystem_path):
if os.path.isdir(os.path.join(filesystem_path, filename)): filenames.append(filename)
filenames.append(filename + "/")
else:
filenames.append(filename)
filenames.sort() filenames.sort()
return self.directory_listing(filenames, path, filesystem_path) return self.directory_listing(filenames, path, filesystem_path)

46
cli/poetry.lock generated
View File

@ -98,7 +98,7 @@ dotenv = ["python-dotenv"]
[[package]] [[package]]
name = "flask-httpauth" name = "flask-httpauth"
version = "4.1.0" version = "4.2.0"
description = "Basic and Digest HTTP authentication for Flask routes" description = "Basic and Digest HTTP authentication for Flask routes"
category = "main" category = "main"
optional = false optional = false
@ -214,6 +214,17 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
[package.extras] [package.extras]
dev = ["pre-commit", "tox"] dev = ["pre-commit", "tox"]
[[package]]
name = "psutil"
version = "5.7.3"
description = "Cross-platform lib for process and system monitoring in Python."
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"]
[[package]] [[package]]
name = "py" name = "py"
version = "1.9.0" version = "1.9.0"
@ -302,7 +313,7 @@ client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
[[package]] [[package]]
name = "requests" name = "requests"
version = "2.24.0" version = "2.25.0"
description = "Python HTTP for Humans." description = "Python HTTP for Humans."
category = "main" category = "main"
optional = false optional = false
@ -312,7 +323,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
certifi = ">=2017.4.17" certifi = ">=2017.4.17"
chardet = ">=3.0.2,<4" chardet = ">=3.0.2,<4"
idna = ">=2.5,<3" idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" urllib3 = ">=1.21.1,<1.27"
[package.extras] [package.extras]
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
@ -344,7 +355,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "1.25.11" version = "1.26.2"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main" category = "main"
optional = false optional = false
@ -382,7 +393,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.6" python-versions = "^3.6"
content-hash = "3947b230139f4b699f40c97e0b90d8c8ab6d3d7ef9093d16d2acb507131e14da" content-hash = "38f69a7cfa72b1da17d995e8c33dcceb0568ebfb065439927a5a007f3c8bd873"
[metadata.files] [metadata.files]
atomicwrites = [ atomicwrites = [
@ -422,8 +433,8 @@ flask = [
{file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
] ]
flask-httpauth = [ flask-httpauth = [
{file = "Flask-HTTPAuth-4.1.0.tar.gz", hash = "sha256:9e028e4375039a49031eb9ecc40be4761f0540476040f6eff329a31dabd4d000"}, {file = "Flask-HTTPAuth-4.2.0.tar.gz", hash = "sha256:8c7e49e53ce7dc14e66fe39b9334e4b7ceb8d0b99a6ba1c3562bb528ef9da84a"},
{file = "Flask_HTTPAuth-4.1.0-py2.py3-none-any.whl", hash = "sha256:29e0288869a213c7387f0323b6bf2c7191584fb1da8aa024d9af118e5cd70de7"}, {file = "Flask_HTTPAuth-4.2.0-py2.py3-none-any.whl", hash = "sha256:3fcedb99a03985915335a38c35bfee6765cbd66d7f46440fa3b42ae94a90fac7"},
] ]
flask-socketio = [ flask-socketio = [
{file = "Flask-SocketIO-4.3.1.tar.gz", hash = "sha256:36c1d5765010d1f4e4f05b4cc9c20c289d9dc70698c88d1addd0afcfedc5b062"}, {file = "Flask-SocketIO-4.3.1.tar.gz", hash = "sha256:36c1d5765010d1f4e4f05b4cc9c20c289d9dc70698c88d1addd0afcfedc5b062"},
@ -512,6 +523,19 @@ pluggy = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
] ]
psutil = [
{file = "psutil-5.7.3-cp27-none-win32.whl", hash = "sha256:1cd6a0c9fb35ece2ccf2d1dd733c1e165b342604c67454fd56a4c12e0a106787"},
{file = "psutil-5.7.3-cp27-none-win_amd64.whl", hash = "sha256:e02c31b2990dcd2431f4524b93491941df39f99619b0d312dfe1d4d530b08b4b"},
{file = "psutil-5.7.3-cp35-cp35m-win32.whl", hash = "sha256:56c85120fa173a5d2ad1d15a0c6e0ae62b388bfb956bb036ac231fbdaf9e4c22"},
{file = "psutil-5.7.3-cp35-cp35m-win_amd64.whl", hash = "sha256:fa38ac15dbf161ab1e941ff4ce39abd64b53fec5ddf60c23290daed2bc7d1157"},
{file = "psutil-5.7.3-cp36-cp36m-win32.whl", hash = "sha256:01bc82813fbc3ea304914581954979e637bcc7084e59ac904d870d6eb8bb2bc7"},
{file = "psutil-5.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:6a3e1fd2800ca45083d976b5478a2402dd62afdfb719b30ca46cd28bb25a2eb4"},
{file = "psutil-5.7.3-cp37-cp37m-win32.whl", hash = "sha256:fbcac492cb082fa38d88587d75feb90785d05d7e12d4565cbf1ecc727aff71b7"},
{file = "psutil-5.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:5d9106ff5ec2712e2f659ebbd112967f44e7d33f40ba40530c485cc5904360b8"},
{file = "psutil-5.7.3-cp38-cp38-win32.whl", hash = "sha256:ade6af32eb80a536eff162d799e31b7ef92ddcda707c27bbd077238065018df4"},
{file = "psutil-5.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:2cb55ef9591b03ef0104bedf67cc4edb38a3edf015cf8cf24007b99cb8497542"},
{file = "psutil-5.7.3.tar.gz", hash = "sha256:af73f7bcebdc538eda9cc81d19db1db7bf26f103f91081d780bbacfcb620dee2"},
]
py = [ py = [
{file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"},
{file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"},
@ -575,8 +599,8 @@ python-socketio = [
{file = "python_socketio-4.6.0-py2.py3-none-any.whl", hash = "sha256:d437f797c44b6efba2f201867cf02b8c96b97dff26d4e4281ac08b45817cd522"}, {file = "python_socketio-4.6.0-py2.py3-none-any.whl", hash = "sha256:d437f797c44b6efba2f201867cf02b8c96b97dff26d4e4281ac08b45817cd522"},
] ]
requests = [ requests = [
{file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"}, {file = "requests-2.25.0-py2.py3-none-any.whl", hash = "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998"},
{file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"}, {file = "requests-2.25.0.tar.gz", hash = "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8"},
] ]
six = [ six = [
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
@ -590,8 +614,8 @@ toml = [
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
] ]
urllib3 = [ urllib3 = [
{file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"}, {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"},
{file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"}, {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"},
] ]
werkzeug = [ werkzeug = [
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},

View File

@ -21,6 +21,7 @@ click = "*"
flask = "*" flask = "*"
flask-httpauth = "*" flask-httpauth = "*"
flask-socketio = "*" flask-socketio = "*"
psutil = "*"
pycryptodome = "*" pycryptodome = "*"
pysocks = "*" pysocks = "*"
requests = "*" requests = "*"

View File

@ -14,7 +14,6 @@ icon = "src/onionshare/resources/onionshare"
sources = ['src/onionshare'] sources = ['src/onionshare']
requires = [ requires = [
"./onionshare_cli-2.3.dev2-py3-none-any.whl", "./onionshare_cli-2.3.dev2-py3-none-any.whl",
"psutil",
"pyside2==5.15.1", "pyside2==5.15.1",
"qrcode" "qrcode"
] ]

View File

@ -128,7 +128,15 @@ class GuiCommon:
""", """,
"server_status_url_buttons": """ "server_status_url_buttons": """
QPushButton { QPushButton {
color: #3f7fcf; border: 1px solid #d3d3d3;
border-radius: 4px;
background-color: #ffffff;
padding: 8px 16px;
text-align: center;
color: #4e0d4e;
}
QPushButton:pressed {
background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(239, 239, 240, 255))
} }
""", """,
"server_status_button_stopped": """ "server_status_button_stopped": """