mirror of
https://github.com/onionshare/onionshare.git
synced 2025-05-02 14:36:15 -04:00
Merge branch 'develop' of github.com:onionshare/onionshare into ros-fixes
This commit is contained in:
commit
9e99ad8b8d
328 changed files with 8237 additions and 3165 deletions
|
@ -59,28 +59,13 @@ pip install --user onionshare-cli
|
|||
|
||||
#### Set path
|
||||
|
||||
When you install programs with pip and use the --user flag, it installs them into ~/.local/bin, which isn't in your path by default. To add ~/.local/bin to your path automatically for the next time you reopen the terminal or source your shell configuration file, do the following:
|
||||
When you install programs with pip and use the `--user` flag, it installs them into *~/.local/bin*, which isn't in your path by default. To add *~/.local/bin* to your path automatically for the next time you reopen the terminal or source your shell configuration file, do the following:
|
||||
|
||||
First, discover what shell you are using:
|
||||
Apply the path to your shell file:
|
||||
|
||||
```sh
|
||||
echo $SHELL
|
||||
```
|
||||
|
||||
Then apply the path to your shell file:
|
||||
|
||||
bash:
|
||||
|
||||
```sh
|
||||
echo "PATH=\$PATH:~/.local/bin" >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
zsh:
|
||||
|
||||
```sh
|
||||
echo "PATH=\$PATH:~/.local/bin" >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
printf "PATH=\$PATH:~/.local/bin\n" >> ~/.${SHELL##*/}rc
|
||||
. ~/.${SHELL##*/}rc
|
||||
```
|
||||
|
||||
#### Usage
|
||||
|
@ -112,11 +97,3 @@ To run tests:
|
|||
```sh
|
||||
poetry run pytest -v ./tests
|
||||
```
|
||||
|
||||
## Build a wheel package
|
||||
|
||||
```sh
|
||||
poetry build
|
||||
```
|
||||
|
||||
This will create `dist/onionshare_cli-$VERSION-py3-none-any.whl`.
|
||||
|
|
|
@ -25,21 +25,46 @@ from .meek import MeekNotRunning
|
|||
class CensorshipCircumvention(object):
|
||||
"""
|
||||
Connect to the Tor Moat APIs to retrieve censorship
|
||||
circumvention recommendations, over the Meek client.
|
||||
circumvention recommendations or the latest bridges.
|
||||
|
||||
We support reaching this API over Tor, or Meek
|
||||
(domain fronting) if Tor is not connected.
|
||||
"""
|
||||
|
||||
def __init__(self, common, meek, domain_fronting=True):
|
||||
def __init__(self, common, meek=None, onion=None):
|
||||
"""
|
||||
Set up the CensorshipCircumvention object to hold
|
||||
common and meek objects.
|
||||
"""
|
||||
self.common = common
|
||||
self.meek = meek
|
||||
self.common.log("CensorshipCircumvention", "__init__")
|
||||
|
||||
# Bail out if we requested domain fronting but we can't use meek
|
||||
if domain_fronting and not self.meek.meek_proxies:
|
||||
raise MeekNotRunning()
|
||||
self.api_proxies = {}
|
||||
if meek:
|
||||
self.meek = meek
|
||||
if not self.meek.meek_proxies:
|
||||
raise MeekNotRunning()
|
||||
else:
|
||||
self.common.log(
|
||||
"CensorshipCircumvention",
|
||||
"__init__",
|
||||
"Using Meek with CensorShipCircumvention API",
|
||||
)
|
||||
self.api_proxies = self.meek.meek_proxies
|
||||
if onion:
|
||||
self.onion = onion
|
||||
if not self.onion.is_authenticated:
|
||||
return False
|
||||
else:
|
||||
self.common.log(
|
||||
"CensorshipCircumvention",
|
||||
"__init__",
|
||||
"Using Tor with CensorShipCircumvention API",
|
||||
)
|
||||
(socks_address, socks_port) = self.onion.get_tor_socks_port()
|
||||
self.api_proxies = {
|
||||
"http": f"socks5h://{socks_address}:{socks_port}",
|
||||
"https": f"socks5h://{socks_address}:{socks_port}",
|
||||
}
|
||||
|
||||
def request_map(self, country=False):
|
||||
"""
|
||||
|
@ -52,6 +77,8 @@ class CensorshipCircumvention(object):
|
|||
Note that this API endpoint doesn't return actual bridges,
|
||||
it just returns the recommended bridge type countries.
|
||||
"""
|
||||
if not self.api_proxies:
|
||||
return False
|
||||
endpoint = "https://bridges.torproject.org/moat/circumvention/map"
|
||||
data = {}
|
||||
if country:
|
||||
|
@ -61,7 +88,7 @@ class CensorshipCircumvention(object):
|
|||
endpoint,
|
||||
json=data,
|
||||
headers={"Content-Type": "application/vnd.api+json"},
|
||||
proxies=self.meek.meek_proxies,
|
||||
proxies=self.api_proxies,
|
||||
)
|
||||
if r.status_code != 200:
|
||||
self.common.log(
|
||||
|
@ -95,6 +122,8 @@ class CensorshipCircumvention(object):
|
|||
Optionally, a list of transports can be specified in order to
|
||||
return recommended settings for just that transport type.
|
||||
"""
|
||||
if not self.api_proxies:
|
||||
return False
|
||||
endpoint = "https://bridges.torproject.org/moat/circumvention/settings"
|
||||
data = {}
|
||||
if country:
|
||||
|
@ -105,7 +134,7 @@ class CensorshipCircumvention(object):
|
|||
endpoint,
|
||||
json=data,
|
||||
headers={"Content-Type": "application/vnd.api+json"},
|
||||
proxies=self.meek.meek_proxies,
|
||||
proxies=self.api_proxies,
|
||||
)
|
||||
if r.status_code != 200:
|
||||
self.common.log(
|
||||
|
@ -142,11 +171,13 @@ class CensorshipCircumvention(object):
|
|||
"""
|
||||
Retrieves the list of built-in bridges from the Tor Project.
|
||||
"""
|
||||
if not self.api_proxies:
|
||||
return False
|
||||
endpoint = "https://bridges.torproject.org/moat/circumvention/builtin"
|
||||
r = requests.post(
|
||||
endpoint,
|
||||
headers={"Content-Type": "application/vnd.api+json"},
|
||||
proxies=self.meek.meek_proxies,
|
||||
proxies=self.api_proxies,
|
||||
)
|
||||
if r.status_code != 200:
|
||||
self.common.log(
|
||||
|
|
|
@ -329,23 +329,49 @@ class Common:
|
|||
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
|
||||
elif self.platform == "Windows":
|
||||
# In Windows, the Tor binaries are in the onionshare package, not the onionshare_cli package
|
||||
base_path = self.get_resource_path("tor")
|
||||
base_path = base_path.replace("onionshare_cli", "onionshare")
|
||||
tor_path = os.path.join(base_path, "Tor", "tor.exe")
|
||||
|
||||
# If tor.exe isn't there, mayber we're running from the source tree
|
||||
if not os.path.exists(tor_path):
|
||||
base_path = os.path.join(os.getcwd(), "onionshare", "resources", "tor")
|
||||
|
||||
tor_path = os.path.join(base_path, "Tor", "tor.exe")
|
||||
if not os.path.exists(tor_path):
|
||||
raise CannotFindTor()
|
||||
|
||||
obfs4proxy_file_path = os.path.join(base_path, "Tor", "obfs4proxy.exe")
|
||||
snowflake_file_path = os.path.join(base_path, "Tor", "snowflake-client.exe")
|
||||
meek_client_file_path = os.path.join(base_path, "Tor", "meek-client.exe")
|
||||
tor_geo_ip_file_path = os.path.join(base_path, "Data", "Tor", "geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(base_path, "Data", "Tor", "geoip6")
|
||||
|
||||
elif self.platform == "Darwin":
|
||||
tor_path = shutil.which("tor")
|
||||
if not tor_path:
|
||||
raise CannotFindTor()
|
||||
obfs4proxy_file_path = shutil.which("obfs4proxy")
|
||||
snowflake_file_path = shutil.which("snowflake-client")
|
||||
meek_client_file_path = shutil.which("meek-client")
|
||||
prefix = os.path.dirname(os.path.dirname(tor_path))
|
||||
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
|
||||
# Let's see if we have tor binaries in the onionshare GUI package
|
||||
base_path = self.get_resource_path("tor")
|
||||
base_path = base_path.replace("onionshare_cli", "onionshare")
|
||||
tor_path = os.path.join(base_path, "tor")
|
||||
if os.path.exists(tor_path):
|
||||
obfs4proxy_file_path = os.path.join(base_path, "obfs4proxy")
|
||||
snowflake_file_path = os.path.join(base_path, "snowflake-client")
|
||||
meek_client_file_path = os.path.join(base_path, "meek-client")
|
||||
tor_geo_ip_file_path = os.path.join(base_path, "geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(base_path, "geoip6")
|
||||
else:
|
||||
# Fallback to looking in the path
|
||||
tor_path = shutil.which("tor")
|
||||
if not os.path.exists(tor_path):
|
||||
raise CannotFindTor()
|
||||
|
||||
obfs4proxy_file_path = shutil.which("obfs4proxy")
|
||||
snowflake_file_path = shutil.which("snowflake-client")
|
||||
meek_client_file_path = shutil.which("meek-client")
|
||||
prefix = os.path.dirname(os.path.dirname(tor_path))
|
||||
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
|
||||
tor_geo_ipv6_file_path = os.path.join(prefix, "share/tor/geoip6")
|
||||
|
||||
elif self.platform == "BSD":
|
||||
tor_path = "/usr/local/bin/tor"
|
||||
tor_geo_ip_file_path = "/usr/local/share/tor/geoip"
|
||||
|
|
|
@ -20,8 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from queue import Queue, Empty
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class Meek(object):
|
||||
|
@ -67,14 +65,6 @@ class Meek(object):
|
|||
Start the Meek Client and populate the SOCKS proxies dict
|
||||
for use with requests to the Tor Moat API.
|
||||
"""
|
||||
# Small method to read stdout from the subprocess.
|
||||
# We use this to obtain the random port that Meek
|
||||
# started on
|
||||
def enqueue_output(out, queue):
|
||||
for line in iter(out.readline, b""):
|
||||
queue.put(line)
|
||||
out.close()
|
||||
|
||||
# Abort early if we can't find the Meek client
|
||||
if self.meek_client_file_path is None or not os.path.exists(
|
||||
self.meek_client_file_path
|
||||
|
@ -124,34 +114,22 @@ class Meek(object):
|
|||
universal_newlines=True,
|
||||
)
|
||||
|
||||
# Queue up the stdout from the subprocess for polling later
|
||||
q = Queue()
|
||||
t = Thread(target=enqueue_output, args=(self.meek_proc.stdout, q))
|
||||
t.daemon = True # thread dies with the program
|
||||
t.start()
|
||||
# Obtain the host and port that meek is running on
|
||||
for line in iter(self.meek_proc.stdout.readline, b""):
|
||||
if "CMETHOD meek socks5" in line:
|
||||
self.meek_host = line.split(" ")[3].split(":")[0]
|
||||
self.meek_port = line.split(" ")[3].split(":")[1]
|
||||
self.common.log(
|
||||
"Meek",
|
||||
"start",
|
||||
f"Meek running on {self.meek_host}:{self.meek_port}",
|
||||
)
|
||||
break
|
||||
|
||||
while True:
|
||||
# read stdout without blocking
|
||||
try:
|
||||
line = q.get_nowait()
|
||||
self.common.log("Meek", "start", line.strip())
|
||||
except Empty:
|
||||
# no stdout yet?
|
||||
pass
|
||||
else: # we got stdout
|
||||
if "CMETHOD meek socks5" in line:
|
||||
self.meek_host = line.split(" ")[3].split(":")[0]
|
||||
self.meek_port = line.split(" ")[3].split(":")[1]
|
||||
self.common.log(
|
||||
"Meek",
|
||||
"start",
|
||||
f"Meek running on {self.meek_host}:{self.meek_port}",
|
||||
)
|
||||
break
|
||||
|
||||
if "CMETHOD-ERROR" in line:
|
||||
self.cleanup()
|
||||
raise MeekNotRunning()
|
||||
if "CMETHOD-ERROR" in line:
|
||||
self.cleanup()
|
||||
raise MeekNotRunning()
|
||||
break
|
||||
|
||||
if self.meek_port:
|
||||
self.meek_proxies = {
|
||||
|
|
|
@ -18,17 +18,19 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from .censorship import CensorshipCircumvention
|
||||
from .meek import Meek
|
||||
from stem.control import Controller
|
||||
from stem import ProtocolError, SocketClosed
|
||||
from stem.connection import MissingPassword, UnreadableCookieFile, AuthenticationFailure
|
||||
import base64
|
||||
import nacl.public
|
||||
import os
|
||||
import tempfile
|
||||
import subprocess
|
||||
import time
|
||||
import shlex
|
||||
import psutil
|
||||
import shlex
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from distutils.version import LooseVersion as Version
|
||||
|
@ -258,9 +260,7 @@ class Onion(object):
|
|||
and cmdline[2] == self.tor_torrc
|
||||
):
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"connect",
|
||||
"found a stale tor process, killing it",
|
||||
"Onion", "connect", "found a stale tor process, killing it"
|
||||
)
|
||||
proc.terminate()
|
||||
proc.wait()
|
||||
|
@ -317,49 +317,75 @@ class Onion(object):
|
|||
)
|
||||
|
||||
with open(self.tor_torrc, "w") as f:
|
||||
self.common.log("Onion", "connect", "Writing torrc template file")
|
||||
f.write(torrc_template)
|
||||
|
||||
# Bridge support
|
||||
if self.settings.get("bridges_enabled"):
|
||||
f.write("\nUseBridges 1\n")
|
||||
if self.settings.get("bridges_type") == "built-in":
|
||||
if self.settings.get("bridges_builtin_pt") == "obfs4":
|
||||
with open(
|
||||
self.common.get_resource_path("torrc_template-obfs4")
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
elif self.settings.get("bridges_builtin_pt") == "meek-azure":
|
||||
with open(
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-meek_lite_azure"
|
||||
use_torrc_bridge_templates = False
|
||||
builtin_bridge_type = self.settings.get("bridges_builtin_pt")
|
||||
# Use built-inbridges stored in settings, if they are there already.
|
||||
# They are probably newer than that of our hardcoded copies.
|
||||
if self.settings.get("bridges_builtin"):
|
||||
try:
|
||||
for line in self.settings.get("bridges_builtin")[
|
||||
builtin_bridge_type
|
||||
]:
|
||||
if line.strip() != "":
|
||||
f.write(f"Bridge {line}\n")
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"connect",
|
||||
"Wrote in the built-in bridges from OnionShare settings",
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
elif self.settings.get("bridges_builtin_pt") == "snowflake":
|
||||
with open(
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-snowflake"
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
|
||||
except KeyError:
|
||||
# Somehow we had built-in bridges in our settings, but
|
||||
# not for this bridge type. Fall back to using the hard-
|
||||
# coded templates.
|
||||
use_torrc_bridge_templates = True
|
||||
else:
|
||||
use_torrc_bridge_templates = True
|
||||
if use_torrc_bridge_templates:
|
||||
if builtin_bridge_type == "obfs4":
|
||||
with open(
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-obfs4"
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
elif builtin_bridge_type == "meek-azure":
|
||||
with open(
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-meek_lite_azure"
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
elif builtin_bridge_type == "snowflake":
|
||||
with open(
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-snowflake"
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"connect",
|
||||
"Wrote in the built-in bridges from torrc templates",
|
||||
)
|
||||
elif self.settings.get("bridges_type") == "moat":
|
||||
for line in self.settings.get("bridges_moat").split("\n"):
|
||||
if line.strip() != "":
|
||||
f.write(f"Bridge {line}\n")
|
||||
f.write("\nUseBridges 1\n")
|
||||
|
||||
elif self.settings.get("bridges_type") == "custom":
|
||||
for line in self.settings.get("bridges_custom").split("\n"):
|
||||
if line.strip() != "":
|
||||
f.write(f"Bridge {line}\n")
|
||||
f.write("\nUseBridges 1\n")
|
||||
|
||||
# Execute a tor subprocess
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"connect",
|
||||
f"starting {self.tor_path} subprocess",
|
||||
)
|
||||
self.common.log("Onion", "connect", f"starting {self.tor_path} subprocess")
|
||||
start_ts = time.time()
|
||||
if self.common.platform == "Windows":
|
||||
# In Windows, hide console window when opening tor.exe subprocess
|
||||
|
@ -385,19 +411,15 @@ class Onion(object):
|
|||
)
|
||||
|
||||
# Wait for the tor controller to start
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"connect",
|
||||
f"tor pid: {self.tor_proc.pid}",
|
||||
)
|
||||
self.common.log("Onion", "connect", f"tor pid: {self.tor_proc.pid}")
|
||||
time.sleep(2)
|
||||
|
||||
return_code = self.tor_proc.poll()
|
||||
if return_code != None:
|
||||
self.common.log("Onion", "connect", f"tor process has terminated early: {return_code}")
|
||||
|
||||
# Connect to the controller
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"connect",
|
||||
"authenticating to tor controller",
|
||||
)
|
||||
self.common.log("Onion", "connect", "authenticating to tor controller")
|
||||
try:
|
||||
if (
|
||||
self.common.platform == "Windows"
|
||||
|
@ -638,6 +660,14 @@ class Onion(object):
|
|||
# https://trac.torproject.org/projects/tor/ticket/28619
|
||||
self.supports_v3_onions = self.tor_version >= Version("0.3.5.7")
|
||||
|
||||
# Now that we are connected to Tor, if we are using built-in bridges,
|
||||
# update them with the latest copy available from the Tor API
|
||||
if (
|
||||
self.settings.get("bridges_enabled")
|
||||
and self.settings.get("bridges_type") == "built-in"
|
||||
):
|
||||
self.update_builtin_bridges()
|
||||
|
||||
def is_authenticated(self):
|
||||
"""
|
||||
Returns True if the Tor connection is still working, or False otherwise.
|
||||
|
@ -881,3 +911,68 @@ class Onion(object):
|
|||
return ("127.0.0.1", 9150)
|
||||
else:
|
||||
return (self.settings.get("socks_address"), self.settings.get("socks_port"))
|
||||
|
||||
def update_builtin_bridges(self):
|
||||
"""
|
||||
Use the CensorshipCircumvention API to fetch the latest built-in bridges
|
||||
and update them in settings.
|
||||
"""
|
||||
builtin_bridges = False
|
||||
meek = None
|
||||
# Try obtaining bridges over Tor, if we're connected to it.
|
||||
if self.is_authenticated:
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"update_builtin_bridges",
|
||||
"Updating the built-in bridges. Trying over Tor first",
|
||||
)
|
||||
self.censorship_circumvention = CensorshipCircumvention(
|
||||
self.common, None, self
|
||||
)
|
||||
builtin_bridges = self.censorship_circumvention.request_builtin_bridges()
|
||||
|
||||
if not builtin_bridges:
|
||||
# Tor was not running or it failed to hit the Tor API.
|
||||
# Fall back to using Meek (domain-fronting).
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"update_builtin_bridges",
|
||||
"Updating the built-in bridges. Trying via Meek (no Tor)",
|
||||
)
|
||||
meek = Meek(self.common)
|
||||
meek.start()
|
||||
self.censorship_circumvention = CensorshipCircumvention(
|
||||
self.common, meek, None
|
||||
)
|
||||
builtin_bridges = self.censorship_circumvention.request_builtin_bridges()
|
||||
meek.cleanup()
|
||||
|
||||
if builtin_bridges:
|
||||
# If we got to this point, we have bridges
|
||||
self.common.log(
|
||||
"Onion",
|
||||
"update_builtin_bridges",
|
||||
f"Obtained bridges: {builtin_bridges}",
|
||||
)
|
||||
if builtin_bridges["meek"]:
|
||||
# Meek bridge needs to be defined as "meek_lite", not "meek",
|
||||
# for it to work with obfs4proxy.
|
||||
# We also refer to this bridge type as 'meek-azure' in our settings.
|
||||
# So first, rename the key in the dict
|
||||
builtin_bridges["meek-azure"] = builtin_bridges.pop("meek")
|
||||
new_meek_bridges = []
|
||||
# Now replace the values. They also need the url/front params appended
|
||||
for item in builtin_bridges["meek-azure"]:
|
||||
newline = item.replace("meek", "meek_lite")
|
||||
new_meek_bridges.append(
|
||||
f"{newline} url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com"
|
||||
)
|
||||
builtin_bridges["meek-azure"] = new_meek_bridges
|
||||
# Save the new settings
|
||||
self.settings.set("bridges_builtin", builtin_bridges)
|
||||
self.settings.save()
|
||||
else:
|
||||
self.common.log(
|
||||
"Onion", "update_builtin_bridges", "Error getting built-in bridges"
|
||||
)
|
||||
return False
|
||||
|
|
|
@ -40,9 +40,6 @@ class OnionShare(object):
|
|||
self.onion_host = None
|
||||
self.port = None
|
||||
|
||||
# files and dirs to delete on shutdown
|
||||
self.cleanup_filenames = []
|
||||
|
||||
# do not use tor -- for development
|
||||
self.local_only = local_only
|
||||
|
||||
|
@ -75,7 +72,9 @@ class OnionShare(object):
|
|||
if self.local_only:
|
||||
self.onion_host = f"127.0.0.1:{self.port}"
|
||||
if not mode_settings.get("general", "public"):
|
||||
self.auth_string = "E2GOT5LTUTP3OAMRCRXO4GSH6VKJEUOXZQUC336SRKAHTTT5OVSA"
|
||||
self.auth_string = (
|
||||
"E2GOT5LTUTP3OAMRCRXO4GSH6VKJEUOXZQUC336SRKAHTTT5OVSA"
|
||||
)
|
||||
return
|
||||
|
||||
self.onion_host = self.onion.start_onion_service(
|
||||
|
|
|
@ -320,15 +320,15 @@ div#uploads .upload .upload-status {
|
|||
}
|
||||
|
||||
div#uploads .upload input.cancel {
|
||||
color: #d0011b;
|
||||
color: #d0011b;
|
||||
border: 0;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
border-radius: 0px;
|
||||
cursor: pointer;
|
||||
font-family: sans-serif;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
font-family: sans-serif;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
float:right;
|
||||
}
|
||||
|
@ -398,4 +398,4 @@ a {
|
|||
|
||||
a:visited {
|
||||
color: #601ca0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ var getScrollDiffBefore = function () {
|
|||
|
||||
var scrollBottomMaybe = function (scrollDiff) {
|
||||
// Scrolls to bottom if the user is scrolled at bottom
|
||||
// if the user has scrolled upp, it wont scroll at bottom.
|
||||
// if the user has scrolled up, it won't scroll at bottom.
|
||||
// Note: when a user themselves send a message, it will still
|
||||
// scroll to the bottom even if they had scrolled up before.
|
||||
if (scrollDiff > 0) {
|
||||
|
|
|
@ -11,7 +11,7 @@ function unhumanize(text) {
|
|||
}
|
||||
}
|
||||
function sortTable(n) {
|
||||
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
|
||||
var table, rows, switching, i, x, y, valX, valY, shouldSwitch, dir, switchcount = 0;
|
||||
table = document.getElementById("file-list");
|
||||
switching = true;
|
||||
// Set the sorting direction to ascending:
|
||||
|
@ -21,7 +21,7 @@ function sortTable(n) {
|
|||
while (switching) {
|
||||
// Start by saying: no switching is done:
|
||||
switching = false;
|
||||
rows = table.getElementsByTagName("TR");
|
||||
rows = table.getElementsByClassName("row");
|
||||
/* Loop through all table rows (except the
|
||||
first, which contains table headers): */
|
||||
for (i = 1; i < (rows.length - 1); i++) {
|
||||
|
@ -29,18 +29,22 @@ function sortTable(n) {
|
|||
shouldSwitch = false;
|
||||
/* Get the two elements you want to compare,
|
||||
one from current row and one from the next: */
|
||||
x = rows[i].getElementsByTagName("TD")[n];
|
||||
y = rows[i + 1].getElementsByTagName("TD")[n];
|
||||
x = rows[i].getElementsByClassName("cell-data")[n];
|
||||
y = rows[i + 1].getElementsByClassName("cell-data")[n];
|
||||
|
||||
valX = x.classList.contains("size") ? unhumanize(x.innerHTML.toLowerCase()) : x.innerHTML;
|
||||
valY = y.classList.contains("size") ? unhumanize(y.innerHTML.toLowerCase()) : y.innerHTML;
|
||||
|
||||
/* Check if the two rows should switch place,
|
||||
based on the direction, asc or desc: */
|
||||
if (dir == "asc") {
|
||||
if (unhumanize(x.innerHTML.toLowerCase()) > unhumanize(y.innerHTML.toLowerCase())) {
|
||||
// If so, mark as a switch and break the loop:
|
||||
shouldSwitch= true;
|
||||
break;
|
||||
}
|
||||
if (valX > valY) {
|
||||
// If so, mark as a switch and break the loop:
|
||||
shouldSwitch= true;
|
||||
break;
|
||||
}
|
||||
} else if (dir == "desc") {
|
||||
if (unhumanize(x.innerHTML.toLowerCase()) < unhumanize(y.innerHTML.toLowerCase())) {
|
||||
if (valX < valY) {
|
||||
// If so, mark as a switch and break the loop:
|
||||
shouldSwitch= true;
|
||||
break;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<head>
|
||||
<title>OnionShare: 403 Forbidden</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<head>
|
||||
<title>OnionShare: 404 Not Found</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<head>
|
||||
<title>OnionShare: 405 Method Not Allowed</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<head>
|
||||
<title>OnionShare: An error occurred</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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>
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
{% endif %}
|
||||
|
||||
<div class="file-list" id="file-list">
|
||||
<div class="d-flex">
|
||||
<div class="d-flex row">
|
||||
<div id="filename-header" class="heading">Filename</div>
|
||||
<div id="size-header" class="heading">Size</div>
|
||||
</div>
|
||||
|
@ -41,26 +41,26 @@
|
|||
<div>
|
||||
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_folder.png" />
|
||||
<a href="{{ info.link }}">
|
||||
<span>{{ info.basename }}</span>
|
||||
<span class="cell-data">{{ info.basename }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div>—</div>
|
||||
<div class="cell-data">—</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for info in files %}
|
||||
<div class="d-flex">
|
||||
<div class="d-flex row">
|
||||
<div>
|
||||
<img width="30" height="30" title="" alt="" src="{{ static_url_path }}/img/web_file.png" />
|
||||
{% if download_individual_files %}
|
||||
<a href="{{ info.link }}">
|
||||
<span>{{ info.basename }}</span>
|
||||
<span class="cell-data">{{ info.basename }}</span>
|
||||
</a>
|
||||
{% else %}
|
||||
<span>{{ info.basename }}</span>
|
||||
<span class="cell-data">{{ info.basename }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>{{ info.size_human }}</div>
|
||||
<div class="cell-data size">{{ info.size_human }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
# Enable built-in meek-azure bridge
|
||||
Bridge meek_lite 0.0.2.0:3 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
|
||||
UseBridges 1
|
||||
# Enable built-in meek bridge
|
||||
Bridge meek_lite 0.0.2.0:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
# Enable built-in obfs4-bridge
|
||||
Bridge obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1
|
||||
Bridge obfs4 38.229.1.78:80 C8CBDB2464FC9804A69531437BCF2BE31FDD2EE4 cert=Hmyfd2ev46gGY7NoVxA9ngrPF2zCZtzskRTzoWXbxNkzeVnGFPWmrTtILRyqCTjHR+s9dg iat-mode=1
|
||||
Bridge obfs4 38.229.33.83:80 0BAC39417268B96B9F514E7F63FA6FBA1A788955 cert=VwEFpk9F/UN9JED7XpG1XOjm/O8ZCXK80oPecgWnNDZDv5pdkhq1OpbAH0wNqOT6H6BmRQ iat-mode=1
|
||||
Bridge obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0
|
||||
Bridge obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0
|
||||
Bridge obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0
|
||||
# Enable built-in obfs4 bridge
|
||||
Bridge obfs4 144.217.20.138:80 FB70B257C162BF1038CA669D568D76F5B7F0BABB cert=vYIV5MgrghGQvZPIi1tJwnzorMgqgmlKaB77Y3Z9Q/v94wZBOAXkW+fdx4aSxLVnKO+xNw iat-mode=0
|
||||
Bridge obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0
|
||||
Bridge obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1
|
||||
Bridge obfs4 193.11.166.194:27015 2D82C2E354D531A68469ADF7F878FA6060C6BACA cert=4TLQPJrTSaDffMK7Nbao6LC7G9OW/NHkUwIdjLSS3KYf0Nv4/nQiiI8dY2TcsQx01NniOg iat-mode=0
|
||||
Bridge obfs4 193.11.166.194:27020 86AC7B8D430DAC4117E9F42C9EAED18133863AAF cert=0LDeJH4JzMDtkJJrFphJCiPqKx7loozKN7VNfuukMGfHO0Z8OGdzHVkhVAOfo1mUdv9cMg iat-mode=0
|
||||
Bridge obfs4 193.11.166.194:27025 1AE2C08904527FEA90C4C4F8C1083EA59FBC6FAF cert=ItvYZzW5tn6v3G4UnQa6Qz04Npro6e81AP70YujmK/KXwDFPTs3aHXcHp4n8Vt6w/bv8cA iat-mode=0
|
||||
Bridge obfs4 209.148.46.65:443 74FAD13168806246602538555B5521A0383A1875 cert=ssH+9rP8dG2NLDN2XuFw63hIO/9MNNinLmxQDpVa+7kTOa9/m+tGWT1SmSYpQ9uTBGa6Hw iat-mode=0
|
||||
Bridge obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0
|
||||
Bridge obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0
|
||||
Bridge obfs4 38.229.1.78:80 C8CBDB2464FC9804A69531437BCF2BE31FDD2EE4 cert=Hmyfd2ev46gGY7NoVxA9ngrPF2zCZtzskRTzoWXbxNkzeVnGFPWmrTtILRyqCTjHR+s9dg iat-mode=1
|
||||
Bridge obfs4 38.229.33.83:80 0BAC39417268B96B9F514E7F63FA6FBA1A788955 cert=VwEFpk9F/UN9JED7XpG1XOjm/O8ZCXK80oPecgWnNDZDv5pdkhq1OpbAH0wNqOT6H6BmRQ iat-mode=1
|
||||
Bridge obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0
|
||||
Bridge obfs4 [2a0c:4d80:42:702::1]:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0
|
||||
Bridge obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0
|
||||
UseBridges 1
|
||||
Bridge obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0
|
||||
Bridge obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0
|
||||
Bridge obfs4 [2a0c:4d80:42:702::1]:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
# Enable built-in snowflake bridge
|
||||
Bridge snowflake 192.0.2.3:1 2B280B23E1107BB62ABFC40DDCC8824814F80A72
|
||||
UseBridges 1
|
||||
Bridge snowflake 0.0.3.0:1 2B280B23E1107BB62ABFC40DDCC8824814F80A72
|
||||
|
|
|
@ -110,6 +110,7 @@ class Settings(object):
|
|||
"bridges_builtin_pt": "obfs4", # "obfs4", "meek-azure", or "snowflake"
|
||||
"bridges_moat": "",
|
||||
"bridges_custom": "",
|
||||
"bridges_builtin": {},
|
||||
"persistent_tabs": [],
|
||||
"locale": None, # this gets defined in fill_in_defaults()
|
||||
"theme": 0,
|
||||
|
|
|
@ -42,10 +42,11 @@ class SendBaseModeWeb:
|
|||
self.is_zipped = False
|
||||
self.download_filename = None
|
||||
self.download_filesize = None
|
||||
self.gzip_filename = None
|
||||
self.gzip_filesize = None
|
||||
self.zip_writer = None
|
||||
|
||||
# Store the tempfile objects here, so when they're garbage collected the files are deleted
|
||||
self.gzip_files = []
|
||||
|
||||
# If autostop_sharing, only allow one download at a time
|
||||
self.download_in_progress = False
|
||||
|
||||
|
@ -192,12 +193,15 @@ class SendBaseModeWeb:
|
|||
# gzip compress the individual file, if it hasn't already been compressed
|
||||
if use_gzip:
|
||||
if filesystem_path not in self.gzip_individual_files:
|
||||
gzip_filename = tempfile.mkstemp("wb+")[1]
|
||||
self._gzip_compress(filesystem_path, gzip_filename, 6, None)
|
||||
self.gzip_individual_files[filesystem_path] = gzip_filename
|
||||
self.gzip_files.append(
|
||||
tempfile.NamedTemporaryFile("wb+", dir=self.common.build_tmp_dir())
|
||||
)
|
||||
gzip_file = self.gzip_files[-1]
|
||||
self._gzip_compress(filesystem_path, gzip_file.name, 6, None)
|
||||
self.gzip_individual_files[filesystem_path] = gzip_file.name
|
||||
|
||||
# Make sure the gzip file gets cleaned up when onionshare stops
|
||||
self.web.cleanup_filenames.append(gzip_filename)
|
||||
# Cleanup this temp file
|
||||
self.web.cleanup_tempfiles.append(gzip_file)
|
||||
|
||||
file_to_download = self.gzip_individual_files[filesystem_path]
|
||||
filesize = os.path.getsize(self.gzip_individual_files[filesystem_path])
|
||||
|
|
|
@ -134,8 +134,12 @@ class ShareModeWeb(SendBaseModeWeb):
|
|||
The web app routes for sharing files
|
||||
"""
|
||||
|
||||
@self.web.app.route("/", defaults={"path": ""}, methods=["GET"], provide_automatic_options=False)
|
||||
@self.web.app.route("/<path:path>", methods=["GET"], provide_automatic_options=False)
|
||||
@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.
|
||||
|
@ -159,7 +163,9 @@ class ShareModeWeb(SendBaseModeWeb):
|
|||
|
||||
return self.render_logic(path)
|
||||
|
||||
@self.web.app.route("/download", methods=["GET"], provide_automatic_options=False)
|
||||
@self.web.app.route(
|
||||
"/download", methods=["GET"], provide_automatic_options=False
|
||||
)
|
||||
def download():
|
||||
"""
|
||||
Download the zip file.
|
||||
|
@ -286,7 +292,9 @@ class ShareModeWeb(SendBaseModeWeb):
|
|||
if if_unmod:
|
||||
if_date = parse_date(if_unmod)
|
||||
if if_date and not if_date.tzinfo:
|
||||
if_date = if_date.replace(tzinfo=timezone.utc) # Compatible with Flask < 2.0.0
|
||||
if_date = if_date.replace(
|
||||
tzinfo=timezone.utc
|
||||
) # Compatible with Flask < 2.0.0
|
||||
if if_date and if_date > last_modified:
|
||||
abort(412)
|
||||
elif range_header is None:
|
||||
|
@ -459,7 +467,7 @@ class ShareModeWeb(SendBaseModeWeb):
|
|||
return self.web.error404(history_id)
|
||||
|
||||
def build_zipfile_list(self, filenames, processed_size_callback=None):
|
||||
self.common.log("ShareModeWeb", "build_zipfile_list")
|
||||
self.common.log("ShareModeWeb", "build_zipfile_list", f"filenames={filenames}")
|
||||
for filename in filenames:
|
||||
info = {
|
||||
"filename": filename,
|
||||
|
@ -484,7 +492,10 @@ class ShareModeWeb(SendBaseModeWeb):
|
|||
self.download_etag = make_etag(f)
|
||||
|
||||
# Compress the file with gzip now, so we don't have to do it on each request
|
||||
self.gzip_filename = tempfile.mkstemp("wb+")[1]
|
||||
self.gzip_tmp_dir = tempfile.TemporaryDirectory(
|
||||
dir=self.common.build_tmp_dir()
|
||||
)
|
||||
self.gzip_filename = os.path.join(self.gzip_tmp_dir.name, "file.gz")
|
||||
self._gzip_compress(
|
||||
self.download_filename, self.gzip_filename, 6, processed_size_callback
|
||||
)
|
||||
|
@ -492,15 +503,15 @@ class ShareModeWeb(SendBaseModeWeb):
|
|||
with open(self.gzip_filename, "rb") as f:
|
||||
self.gzip_etag = make_etag(f)
|
||||
|
||||
# Make sure the gzip file gets cleaned up when onionshare stops
|
||||
self.web.cleanup_filenames.append(self.gzip_filename)
|
||||
|
||||
self.is_zipped = False
|
||||
|
||||
# Cleanup this tempfile
|
||||
self.web.cleanup_tempdirs.append(self.gzip_tmp_dir)
|
||||
|
||||
else:
|
||||
# Zip up the files and folders
|
||||
self.zip_writer = ZipWriter(
|
||||
self.common, processed_size_callback=processed_size_callback
|
||||
self.common, self.web, processed_size_callback=processed_size_callback
|
||||
)
|
||||
self.download_filename = self.zip_writer.zip_filename
|
||||
for info in self.file_info["files"]:
|
||||
|
@ -519,10 +530,6 @@ class ShareModeWeb(SendBaseModeWeb):
|
|||
with open(self.download_filename, "rb") as f:
|
||||
self.download_etag = make_etag(f)
|
||||
|
||||
# Make sure the zip file gets cleaned up when onionshare stops
|
||||
self.web.cleanup_filenames.append(self.zip_writer.zip_filename)
|
||||
self.web.cleanup_filenames.append(self.zip_writer.zip_temp_dir)
|
||||
|
||||
self.is_zipped = True
|
||||
|
||||
return True
|
||||
|
@ -535,17 +542,24 @@ class ZipWriter(object):
|
|||
filename.
|
||||
"""
|
||||
|
||||
def __init__(self, common, zip_filename=None, processed_size_callback=None):
|
||||
def __init__(
|
||||
self, common, web=None, zip_filename=None, processed_size_callback=None
|
||||
):
|
||||
self.common = common
|
||||
self.web = web
|
||||
self.cancel_compression = False
|
||||
|
||||
if zip_filename:
|
||||
self.zip_filename = zip_filename
|
||||
else:
|
||||
self.zip_temp_dir = tempfile.mkdtemp()
|
||||
self.zip_filename = (
|
||||
f"{self.zip_temp_dir}/onionshare_{self.common.random_string(4, 6)}.zip"
|
||||
self.zip_temp_dir = tempfile.TemporaryDirectory(
|
||||
dir=self.common.build_tmp_dir()
|
||||
)
|
||||
self.zip_filename = f"{self.zip_temp_dir.name}/onionshare_{self.common.random_string(4, 6)}.zip"
|
||||
|
||||
# Cleanup this temp dir
|
||||
if self.web:
|
||||
self.web.cleanup_tempdirs.append(self.zip_temp_dir)
|
||||
|
||||
self.z = zipfile.ZipFile(self.zip_filename, "w", allowZip64=True)
|
||||
self.processed_size_callback = processed_size_callback
|
||||
|
|
|
@ -18,6 +18,7 @@ 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 logging
|
||||
import mimetypes
|
||||
import os
|
||||
import queue
|
||||
import requests
|
||||
|
@ -80,6 +81,16 @@ class Web:
|
|||
|
||||
self.settings = mode_settings
|
||||
|
||||
# Flask guesses the MIME type of files from a database on the operating
|
||||
# system.
|
||||
# Some operating systems, or applications that can modify the database
|
||||
# (such as the Windows Registry) can treat .js files as text/plain,
|
||||
# which breaks the chat app due to X-Content-Type-Options: nosniff.
|
||||
#
|
||||
# It's probably #notourbug but we can fix it by forcing the mimetype.
|
||||
# https://github.com/onionshare/onionshare/issues/1443
|
||||
mimetypes.add_type("text/javascript", ".js")
|
||||
|
||||
# The flask app
|
||||
self.app = Flask(
|
||||
__name__,
|
||||
|
@ -151,11 +162,17 @@ class Web:
|
|||
elif self.mode == "website":
|
||||
self.website_mode = WebsiteModeWeb(self.common, self)
|
||||
elif self.mode == "chat":
|
||||
self.socketio = SocketIO()
|
||||
if self.common.verbose:
|
||||
self.socketio = SocketIO(
|
||||
async_mode="gevent", logger=True, engineio_logger=True
|
||||
)
|
||||
else:
|
||||
self.socketio = SocketIO(async_mode="gevent")
|
||||
self.socketio.init_app(self.app)
|
||||
self.chat_mode = ChatModeWeb(self.common, self)
|
||||
|
||||
self.cleanup_filenames = []
|
||||
self.cleanup_tempfiles = []
|
||||
self.cleanup_tempdirs = []
|
||||
|
||||
def get_mode(self):
|
||||
if self.mode == "share":
|
||||
|
@ -198,18 +215,19 @@ class Web:
|
|||
"""
|
||||
for header, value in self.security_headers:
|
||||
r.headers.set(header, value)
|
||||
|
||||
# Set a CSP header unless in website mode and the user has disabled it
|
||||
default_csp = "default-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; img-src 'self' data:;"
|
||||
if self.mode != "website" or (not self.settings.get("website", "disable_csp") and not self.settings.get("website", "custom_csp")):
|
||||
r.headers.set(
|
||||
"Content-Security-Policy",
|
||||
default_csp
|
||||
)
|
||||
if self.mode != "website" or (
|
||||
not self.settings.get("website", "disable_csp")
|
||||
and not self.settings.get("website", "custom_csp")
|
||||
):
|
||||
r.headers.set("Content-Security-Policy", default_csp)
|
||||
else:
|
||||
if self.settings.get("website", "custom_csp"):
|
||||
r.headers.set(
|
||||
"Content-Security-Policy",
|
||||
self.settings.get("website", "custom_csp")
|
||||
self.settings.get("website", "custom_csp"),
|
||||
)
|
||||
return r
|
||||
|
||||
|
@ -387,14 +405,13 @@ class Web:
|
|||
"""
|
||||
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 = []
|
||||
# Close all of the tempfile.NamedTemporaryFile
|
||||
for file in self.cleanup_tempfiles:
|
||||
file.close()
|
||||
|
||||
# Clean up the tempfile.NamedTemporaryDirectory objects
|
||||
for dir in self.cleanup_tempdirs:
|
||||
dir.cleanup()
|
||||
|
||||
self.cleanup_tempfiles = []
|
||||
self.cleanup_tempdirs = []
|
||||
|
|
217
cli/poetry.lock
generated
217
cli/poetry.lock
generated
|
@ -57,7 +57,7 @@ pycparser = "*"
|
|||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "2.0.7"
|
||||
version = "2.0.9"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "main"
|
||||
optional = false
|
||||
|
@ -99,7 +99,7 @@ trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"]
|
|||
|
||||
[[package]]
|
||||
name = "eventlet"
|
||||
version = "0.32.0"
|
||||
version = "0.33.0"
|
||||
description = "Highly concurrent networking library"
|
||||
category = "main"
|
||||
optional = false
|
||||
|
@ -141,6 +141,38 @@ python-versions = "*"
|
|||
Flask = ">=0.9"
|
||||
python-socketio = ">=5.0.2"
|
||||
|
||||
[[package]]
|
||||
name = "gevent"
|
||||
version = "21.12.0"
|
||||
description = "Coroutine-based network library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5"
|
||||
|
||||
[package.dependencies]
|
||||
cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""}
|
||||
greenlet = {version = ">=1.1.0,<2.0", markers = "platform_python_implementation == \"CPython\""}
|
||||
"zope.event" = "*"
|
||||
"zope.interface" = "*"
|
||||
|
||||
[package.extras]
|
||||
dnspython = ["dnspython (>=1.16.0,<2.0)", "idna"]
|
||||
docs = ["repoze.sphinx.autointerface", "sphinxcontrib-programoutput", "zope.schema"]
|
||||
monitor = ["psutil (>=5.7.0)"]
|
||||
recommended = ["cffi (>=1.12.2)", "dnspython (>=1.16.0,<2.0)", "idna", "selectors2", "backports.socketpair", "psutil (>=5.7.0)"]
|
||||
test = ["requests", "objgraph", "cffi (>=1.12.2)", "dnspython (>=1.16.0,<2.0)", "idna", "selectors2", "futures", "mock", "backports.socketpair", "contextvars (==2.4)", "coverage (>=5.0)", "coveralls (>=1.7.0)", "psutil (>=5.7.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "gevent-websocket"
|
||||
version = "0.10.1"
|
||||
description = "Websocket handler for the gevent pywsgi server, a Python network library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
gevent = "*"
|
||||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
version = "1.1.2"
|
||||
|
@ -162,7 +194,7 @@ python-versions = ">=3.5"
|
|||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "4.8.2"
|
||||
version = "4.8.3"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
|
@ -217,14 +249,14 @@ python-versions = ">=3.6"
|
|||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "21.2"
|
||||
version = "21.3"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2,<3"
|
||||
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
|
@ -286,11 +318,14 @@ tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"]
|
|||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "2.4.7"
|
||||
version = "3.0.6"
|
||||
description = "Python parsing module"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pysocks"
|
||||
|
@ -387,7 +422,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
|||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.0.0"
|
||||
version = "4.0.1"
|
||||
description = "Backported and Experimental Type Hints for Python 3.6+"
|
||||
category = "dev"
|
||||
optional = false
|
||||
|
@ -438,10 +473,35 @@ python-versions = ">=3.6"
|
|||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||
|
||||
[[package]]
|
||||
name = "zope.event"
|
||||
version = "4.5.0"
|
||||
description = "Very basic event publishing system"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx"]
|
||||
test = ["zope.testrunner"]
|
||||
|
||||
[[package]]
|
||||
name = "zope.interface"
|
||||
version = "5.4.0"
|
||||
description = "Interfaces for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "repoze.sphinx.autointerface"]
|
||||
test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
||||
testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.6"
|
||||
content-hash = "b6700c9652a3292f2ab3153544c46ed78c75fc9b65c15fcf4e3c243f841565dd"
|
||||
content-hash = "53661539ae01732f6ff6983cf741121e19eb9f142ed3e8bc43845af7695a2c06"
|
||||
|
||||
[metadata.files]
|
||||
atomicwrites = [
|
||||
|
@ -516,8 +576,8 @@ cffi = [
|
|||
{file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
|
||||
]
|
||||
charset-normalizer = [
|
||||
{file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"},
|
||||
{file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"},
|
||||
{file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"},
|
||||
{file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
|
||||
|
@ -532,8 +592,8 @@ dnspython = [
|
|||
{file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"},
|
||||
]
|
||||
eventlet = [
|
||||
{file = "eventlet-0.32.0-py2.py3-none-any.whl", hash = "sha256:a3a67b02f336e97a1894b277bc33b695831525758781eb024f4da00e75ce5e25"},
|
||||
{file = "eventlet-0.32.0.tar.gz", hash = "sha256:2f0bb8ed0dc0ab21d683975d5d8ab3c054d588ce61def9faf7a465ee363e839b"},
|
||||
{file = "eventlet-0.33.0-py2.py3-none-any.whl", hash = "sha256:d10a8fcc9e33381905d9873303fde96ebe3541c03fb795055d2c7347dce0639c"},
|
||||
{file = "eventlet-0.33.0.tar.gz", hash = "sha256:80144f489c1bb273a51b6f96ff9785a382d2866b9bab1f5bd748385019f4141f"},
|
||||
]
|
||||
flask = [
|
||||
{file = "Flask-1.1.4-py2.py3-none-any.whl", hash = "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22"},
|
||||
|
@ -543,6 +603,45 @@ flask-socketio = [
|
|||
{file = "Flask-SocketIO-5.0.1.tar.gz", hash = "sha256:5c4319f5214ada20807857dc8fdf3dc7d2afe8d6dd38f5c516c72e2be47d2227"},
|
||||
{file = "Flask_SocketIO-5.0.1-py2.py3-none-any.whl", hash = "sha256:5d9a4438bafd806c5a3b832e74b69758781a8ee26fb6c9b1dbdda9b4fced432e"},
|
||||
]
|
||||
gevent = [
|
||||
{file = "gevent-21.12.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:2afa3f3ad528155433f6ac8bd64fa5cc303855b97004416ec719a6b1ca179481"},
|
||||
{file = "gevent-21.12.0-cp27-cp27m-win32.whl", hash = "sha256:177f93a3a90f46a5009e0841fef561601e5c637ba4332ab8572edd96af650101"},
|
||||
{file = "gevent-21.12.0-cp27-cp27m-win_amd64.whl", hash = "sha256:a5ad4ed8afa0a71e1927623589f06a9b5e8b5e77810be3125cb4d93050d3fd1f"},
|
||||
{file = "gevent-21.12.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:eae3c46f9484eaacd67ffcdf4eaf6ca830f587edd543613b0f5c4eb3c11d052d"},
|
||||
{file = "gevent-21.12.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1899b921219fc8959ff9afb94dae36be82e0769ed13d330a393594d478a0b3a"},
|
||||
{file = "gevent-21.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c21cb5c9f4e14d75b3fe0b143ec875d7dbd1495fad6d49704b00e57e781ee0f"},
|
||||
{file = "gevent-21.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:542ae891e2aa217d2cf6d8446538fcd2f3263a40eec123b970b899bac391c47a"},
|
||||
{file = "gevent-21.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:0082d8a5d23c35812ce0e716a91ede597f6dd2c5ff508a02a998f73598c59397"},
|
||||
{file = "gevent-21.12.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da8d2d51a49b2a5beb02ad619ca9ddbef806ef4870ba04e5ac7b8b41a5b61db3"},
|
||||
{file = "gevent-21.12.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfff82f05f14b7f5d9ed53ccb7a609ae8604df522bb05c971bca78ec9d8b2b9"},
|
||||
{file = "gevent-21.12.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7909780f0cf18a1fc32aafd8c8e130cdd93c6e285b11263f7f2d1a0f3678bc50"},
|
||||
{file = "gevent-21.12.0-cp36-cp36m-win32.whl", hash = "sha256:bb5cb8db753469c7a9a0b8a972d2660fe851aa06eee699a1ca42988afb0aaa02"},
|
||||
{file = "gevent-21.12.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c43f081cbca41d27fd8fef9c6a32cf83cb979345b20abc07bf68df165cdadb24"},
|
||||
{file = "gevent-21.12.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:74fc1ef16b86616cfddcc74f7292642b0f72dde4dd95aebf4c45bb236744be54"},
|
||||
{file = "gevent-21.12.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cc2fef0f98ee180704cf95ec84f2bc2d86c6c3711bb6b6740d74e0afe708b62c"},
|
||||
{file = "gevent-21.12.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08b4c17064e28f4eb85604486abc89f442c7407d2aed249cf54544ce5c9baee6"},
|
||||
{file = "gevent-21.12.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:973749bacb7bc4f4181a8fb2a7e0e2ff44038de56d08e856dd54a5ac1d7331b4"},
|
||||
{file = "gevent-21.12.0-cp37-cp37m-win32.whl", hash = "sha256:6a02a88723ed3f0fd92cbf1df3c4cd2fbd87d82b0a4bac3e36a8875923115214"},
|
||||
{file = "gevent-21.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f289fae643a3f1c3b909d6b033e6921b05234a4907e9c9c8c3f1fe403e6ac452"},
|
||||
{file = "gevent-21.12.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:3baeeccc4791ba3f8db27179dff11855a8f9210ddd754f6c9b48e0d2561c2aea"},
|
||||
{file = "gevent-21.12.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05c5e8a50cd6868dd36536c92fb4468d18090e801bd63611593c0717bab63692"},
|
||||
{file = "gevent-21.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d86438ede1cbe0fde6ef4cc3f72bf2f1ecc9630d8b633ff344a3aeeca272cdd"},
|
||||
{file = "gevent-21.12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:01928770972181ad8866ee37ea3504f1824587b188fcab782ef1619ce7538766"},
|
||||
{file = "gevent-21.12.0-cp38-cp38-win32.whl", hash = "sha256:3c012c73e6c61f13c75e3a4869dbe6a2ffa025f103421a6de9c85e627e7477b1"},
|
||||
{file = "gevent-21.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:b7709c64afa8bb3000c28bb91ec42c79594a7cb0f322e20427d57f9762366a5b"},
|
||||
{file = "gevent-21.12.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:ec21f9eaaa6a7b1e62da786132d6788675b314f25f98d9541f1bf00584ed4749"},
|
||||
{file = "gevent-21.12.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:22ce1f38fdfe2149ffe8ec2131ca45281791c1e464db34b3b4321ae9d8d2efbb"},
|
||||
{file = "gevent-21.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ccffcf708094564e442ac6fde46f0ae9e40015cb69d995f4b39cc29a7643881"},
|
||||
{file = "gevent-21.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24d3550fbaeef5fddd794819c2853bca45a86c3d64a056a2c268d981518220d1"},
|
||||
{file = "gevent-21.12.0-cp39-cp39-win32.whl", hash = "sha256:2bcec9f80196c751fdcf389ca9f7141e7b0db960d8465ed79be5e685bfcad682"},
|
||||
{file = "gevent-21.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:3dad62f55fad839d498c801e139481348991cee6e1c7706041b5fe096cb6a279"},
|
||||
{file = "gevent-21.12.0-pp27-pypy_73-win_amd64.whl", hash = "sha256:9f9652d1e4062d4b5b5a0a49ff679fa890430b5f76969d35dccb2df114c55e0f"},
|
||||
{file = "gevent-21.12.0.tar.gz", hash = "sha256:f48b64578c367b91fa793bf8eaaaf4995cb93c8bc45860e473bf868070ad094e"},
|
||||
]
|
||||
gevent-websocket = [
|
||||
{file = "gevent-websocket-0.10.1.tar.gz", hash = "sha256:7eaef32968290c9121f7c35b973e2cc302ffb076d018c9068d2f5ca8b2d85fb0"},
|
||||
{file = "gevent_websocket-0.10.1-py3-none-any.whl", hash = "sha256:17b67d91282f8f4c973eba0551183fc84f56f1c90c8f6b6b30256f31f66f5242"},
|
||||
]
|
||||
greenlet = [
|
||||
{file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"},
|
||||
{file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"},
|
||||
|
@ -555,6 +654,7 @@ greenlet = [
|
|||
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"},
|
||||
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"},
|
||||
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"},
|
||||
{file = "greenlet-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965"},
|
||||
{file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"},
|
||||
{file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"},
|
||||
{file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"},
|
||||
|
@ -567,6 +667,7 @@ greenlet = [
|
|||
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"},
|
||||
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"},
|
||||
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"},
|
||||
{file = "greenlet-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f"},
|
||||
{file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"},
|
||||
{file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"},
|
||||
{file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"},
|
||||
|
@ -575,6 +676,7 @@ greenlet = [
|
|||
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"},
|
||||
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"},
|
||||
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"},
|
||||
{file = "greenlet-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe"},
|
||||
{file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"},
|
||||
{file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"},
|
||||
{file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"},
|
||||
|
@ -583,6 +685,7 @@ greenlet = [
|
|||
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"},
|
||||
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"},
|
||||
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"},
|
||||
{file = "greenlet-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2"},
|
||||
{file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"},
|
||||
{file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"},
|
||||
{file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"},
|
||||
|
@ -591,6 +694,7 @@ greenlet = [
|
|||
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"},
|
||||
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"},
|
||||
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"},
|
||||
{file = "greenlet-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3"},
|
||||
{file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"},
|
||||
{file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"},
|
||||
{file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"},
|
||||
|
@ -600,8 +704,8 @@ idna = [
|
|||
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-4.8.2-py3-none-any.whl", hash = "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100"},
|
||||
{file = "importlib_metadata-4.8.2.tar.gz", hash = "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb"},
|
||||
{file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"},
|
||||
{file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"},
|
||||
]
|
||||
iniconfig = [
|
||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||
|
@ -621,6 +725,9 @@ markupsafe = [
|
|||
{file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"},
|
||||
{file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"},
|
||||
{file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"},
|
||||
{file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"},
|
||||
{file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"},
|
||||
{file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"},
|
||||
{file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"},
|
||||
{file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
|
||||
|
@ -632,6 +739,9 @@ markupsafe = [
|
|||
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
|
||||
{file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
|
||||
|
@ -643,6 +753,9 @@ markupsafe = [
|
|||
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
|
||||
{file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"},
|
||||
|
@ -655,6 +768,9 @@ markupsafe = [
|
|||
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
|
||||
{file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
|
||||
|
@ -667,13 +783,16 @@ markupsafe = [
|
|||
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
|
||||
{file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
|
||||
{file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-21.2-py3-none-any.whl", hash = "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0"},
|
||||
{file = "packaging-21.2.tar.gz", hash = "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966"},
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
]
|
||||
pluggy = [
|
||||
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||
|
@ -738,8 +857,8 @@ pynacl = [
|
|||
{file = "PyNaCl-1.4.0.tar.gz", hash = "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
||||
{file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
|
||||
{file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
|
||||
]
|
||||
pysocks = [
|
||||
{file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"},
|
||||
|
@ -771,7 +890,8 @@ toml = [
|
|||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-4.0.0-py3-none-any.whl", hash = "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9"},
|
||||
{file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
|
||||
{file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
|
||||
]
|
||||
unidecode = [
|
||||
{file = "Unidecode-1.3.2-py3-none-any.whl", hash = "sha256:215fe33c9d1c889fa823ccb66df91b02524eb8cc8c9c80f9c5b8129754d27829"},
|
||||
|
@ -789,3 +909,60 @@ zipp = [
|
|||
{file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
|
||||
{file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
|
||||
]
|
||||
"zope.event" = [
|
||||
{file = "zope.event-4.5.0-py2.py3-none-any.whl", hash = "sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42"},
|
||||
{file = "zope.event-4.5.0.tar.gz", hash = "sha256:5e76517f5b9b119acf37ca8819781db6c16ea433f7e2062c4afc2b6fbedb1330"},
|
||||
]
|
||||
"zope.interface" = [
|
||||
{file = "zope.interface-5.4.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7df1e1c05304f26faa49fa752a8c690126cf98b40b91d54e6e9cc3b7d6ffe8b7"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c98384b254b37ce50eddd55db8d381a5c53b4c10ee66e1e7fe749824f894021"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:08f9636e99a9d5410181ba0729e0408d3d8748026ea938f3b970a0249daa8192"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0ea1d73b7c9dcbc5080bb8aaffb776f1c68e807767069b9ccdd06f27a161914a"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:273f158fabc5ea33cbc936da0ab3d4ba80ede5351babc4f577d768e057651531"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27m-win32.whl", hash = "sha256:a1e6e96217a0f72e2b8629e271e1b280c6fa3fe6e59fa8f6701bec14e3354325"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:877473e675fdcc113c138813a5dd440da0769a2d81f4d86614e5d62b69497155"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b0297b1e05fd128d26cc2460c810d42e205d16d76799526dfa8c8ccd50e74959"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:af310ec8335016b5e52cae60cda4a4f2a60a788cbb949a4fbea13d441aa5a09e"},
|
||||
{file = "zope.interface-5.4.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9a9845c4c6bb56e508651f005c4aeb0404e518c6f000d5a1123ab077ab769f5c"},
|
||||
{file = "zope.interface-5.4.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0b465ae0962d49c68aa9733ba92a001b2a0933c317780435f00be7ecb959c702"},
|
||||
{file = "zope.interface-5.4.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f"},
|
||||
{file = "zope.interface-5.4.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:469e2407e0fe9880ac690a3666f03eb4c3c444411a5a5fddfdabc5d184a79f05"},
|
||||
{file = "zope.interface-5.4.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:52de7fc6c21b419078008f697fd4103dbc763288b1406b4562554bd47514c004"},
|
||||
{file = "zope.interface-5.4.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:3dd4952748521205697bc2802e4afac5ed4b02909bb799ba1fe239f77fd4e117"},
|
||||
{file = "zope.interface-5.4.0-cp35-cp35m-win32.whl", hash = "sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8"},
|
||||
{file = "zope.interface-5.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:3748fac0d0f6a304e674955ab1365d515993b3a0a865e16a11ec9d86fb307f63"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:d0c1bc2fa9a7285719e5678584f6b92572a5b639d0e471bb8d4b650a1a910920"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2876246527c91e101184f63ccd1d716ec9c46519cc5f3d5375a3351c46467c46"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:334701327f37c47fa628fc8b8d28c7d7730ce7daaf4bda1efb741679c2b087fc"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5bb3489b4558e49ad2c5118137cfeaf59434f9737fa9c5deefc72d22c23822e2"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-win32.whl", hash = "sha256:1c0e316c9add0db48a5b703833881351444398b04111188069a26a61cfb4df78"},
|
||||
{file = "zope.interface-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:7d97a4306898b05404a0dcdc32d9709b7d8832c0c542b861d9a826301719794e"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:867a5ad16892bf20e6c4ea2aab1971f45645ff3102ad29bd84c86027fa99997b"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:194d0bcb1374ac3e1e023961610dc8f2c78a0f5f634d0c737691e215569e640d"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8270252effc60b9642b423189a2fe90eb6b59e87cbee54549db3f5562ff8d1b8"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:15e7d1f7a6ee16572e21e3576d2012b2778cbacf75eb4b7400be37455f5ca8bf"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:8892f89999ffd992208754851e5a052f6b5db70a1e3f7d54b17c5211e37a98c7"},
|
||||
{file = "zope.interface-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2e5a26f16503be6c826abca904e45f1a44ff275fdb7e9d1b75c10671c26f8b94"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4de4bc9b6d35c5af65b454d3e9bc98c50eb3960d5a3762c9438df57427134b8e"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-win32.whl", hash = "sha256:a9506a7e80bcf6eacfff7f804c0ad5350c8c95b9010e4356a4b36f5322f09abb"},
|
||||
{file = "zope.interface-5.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0cee5187b60ed26d56eb2960136288ce91bcf61e2a9405660d271d1f122a69a4"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:a8156e6a7f5e2a0ff0c5b21d6bcb45145efece1909efcbbbf48c56f8da68221d"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:205e40ccde0f37496904572035deea747390a8b7dc65146d30b96e2dd1359a83"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3f24df7124c323fceb53ff6168da70dbfbae1442b4f3da439cd441681f54fe25"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:5208ebd5152e040640518a77827bdfcc73773a15a33d6644015b763b9c9febc1"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:17776ecd3a1fdd2b2cd5373e5ef8b307162f581c693575ec62e7c5399d80794c"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-win32.whl", hash = "sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e"},
|
||||
{file = "zope.interface-5.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:0cba8477e300d64a11a9789ed40ee8932b59f9ee05f85276dbb4b59acee5dd09"},
|
||||
{file = "zope.interface-5.4.0.tar.gz", hash = "sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e"},
|
||||
]
|
||||
|
|
|
@ -30,6 +30,7 @@ setuptools = "*"
|
|||
pynacl = "^1.4.0"
|
||||
colorama = "*"
|
||||
cepa = "1.8.3"
|
||||
gevent-websocket = "^0.10.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "*"
|
||||
|
|
|
@ -37,7 +37,7 @@ def temp_dir():
|
|||
"""Creates a persistent temporary directory for the CLI tests to use"""
|
||||
global test_temp_dir
|
||||
if not test_temp_dir:
|
||||
test_temp_dir = tempfile.mkdtemp()
|
||||
test_temp_dir = tempfile.TemporaryDirectory()
|
||||
return test_temp_dir
|
||||
|
||||
|
||||
|
@ -47,10 +47,9 @@ def temp_dir_1024(temp_dir):
|
|||
particular size (1024 bytes).
|
||||
"""
|
||||
|
||||
new_temp_dir = tempfile.mkdtemp(dir=temp_dir)
|
||||
tmp_file, tmp_file_path = tempfile.mkstemp(dir=new_temp_dir)
|
||||
with open(tmp_file, "wb") as f:
|
||||
f.write(b"*" * 1024)
|
||||
new_temp_dir = tempfile.TemporaryDirectory(dir=temp_dir.name)
|
||||
tmp_file = tempfile.NamedTemporaryFile(dir=new_temp_dir.name)
|
||||
tmp_file.write(b"*" * 1024)
|
||||
return new_temp_dir
|
||||
|
||||
|
||||
|
@ -61,9 +60,8 @@ def temp_dir_1024_delete(temp_dir):
|
|||
the file inside) will be deleted after fixture usage.
|
||||
"""
|
||||
|
||||
with tempfile.TemporaryDirectory(dir=temp_dir) as new_temp_dir:
|
||||
tmp_file, tmp_file_path = tempfile.mkstemp(dir=new_temp_dir)
|
||||
with open(tmp_file, "wb") as f:
|
||||
with tempfile.TemporaryDirectory(dir=temp_dir.name) as new_temp_dir:
|
||||
with open(os.path.join(new_temp_dir, "file"), "wb") as f:
|
||||
f.write(b"*" * 1024)
|
||||
yield new_temp_dir
|
||||
|
||||
|
@ -72,9 +70,10 @@ def temp_dir_1024_delete(temp_dir):
|
|||
def temp_file_1024(temp_dir):
|
||||
"""Create a temporary file of a particular size (1024 bytes)."""
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False, dir=temp_dir) as tmp_file:
|
||||
tmp_file.write(b"*" * 1024)
|
||||
return tmp_file.name
|
||||
filename = os.path.join(temp_dir.name, "file")
|
||||
with open(filename, "wb") as f:
|
||||
f.write(b"*" * 1024)
|
||||
return filename
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -84,11 +83,11 @@ def temp_file_1024_delete(temp_dir):
|
|||
The temporary file will be deleted after fixture usage.
|
||||
"""
|
||||
|
||||
with tempfile.NamedTemporaryFile(dir=temp_dir, delete=False) as tmp_file:
|
||||
with tempfile.NamedTemporaryFile(dir=temp_dir.name, delete=False) as tmp_file:
|
||||
tmp_file.write(b"*" * 1024)
|
||||
tmp_file.flush()
|
||||
tmp_file.close()
|
||||
yield tmp_file.name
|
||||
yield tmp_file
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
|
|
|
@ -34,6 +34,7 @@ class TestSettings:
|
|||
"bridges_builtin_pt": "obfs4",
|
||||
"bridges_moat": "",
|
||||
"bridges_custom": "",
|
||||
"bridges_builtin": {},
|
||||
"persistent_tabs": [],
|
||||
"theme": 0,
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ class TestSettings:
|
|||
"socks_port": 9999,
|
||||
"use_stealth": True,
|
||||
}
|
||||
tmp_file, tmp_file_path = tempfile.mkstemp(dir=temp_dir)
|
||||
tmp_file, tmp_file_path = tempfile.mkstemp(dir=temp_dir.name)
|
||||
with open(tmp_file, "w") as f:
|
||||
json.dump(custom_settings, f)
|
||||
settings_obj.filename = tmp_file_path
|
||||
|
@ -69,7 +70,7 @@ class TestSettings:
|
|||
|
||||
def test_save(self, monkeypatch, temp_dir, settings_obj):
|
||||
settings_filename = "default_settings.json"
|
||||
new_temp_dir = tempfile.mkdtemp(dir=temp_dir)
|
||||
new_temp_dir = tempfile.mkdtemp(dir=temp_dir.name)
|
||||
settings_path = os.path.join(new_temp_dir, settings_filename)
|
||||
settings_obj.filename = settings_path
|
||||
settings_obj.save()
|
||||
|
|
|
@ -50,7 +50,8 @@ def web_obj(temp_dir, common_obj, mode, num_files=0):
|
|||
web = Web(common_obj, False, mode_settings, mode)
|
||||
web.running = True
|
||||
|
||||
web.cleanup_filenames == []
|
||||
web.cleanup_tempfiles == []
|
||||
web.cleanup_tempdirs == []
|
||||
web.app.testing = True
|
||||
|
||||
# Share mode
|
||||
|
@ -58,7 +59,9 @@ def web_obj(temp_dir, common_obj, mode, num_files=0):
|
|||
# Add files
|
||||
files = []
|
||||
for _ in range(num_files):
|
||||
with tempfile.NamedTemporaryFile(delete=False, dir=temp_dir) as tmp_file:
|
||||
with tempfile.NamedTemporaryFile(
|
||||
delete=False, dir=temp_dir.name
|
||||
) as tmp_file:
|
||||
tmp_file.write(b"*" * 1024)
|
||||
files.append(tmp_file.name)
|
||||
web.share_mode.set_file_info(files)
|
||||
|
@ -131,7 +134,9 @@ class TestWeb:
|
|||
|
||||
with web.app.test_client() as c:
|
||||
# Load / with valid auth
|
||||
res = c.get("/",)
|
||||
res = c.get(
|
||||
"/",
|
||||
)
|
||||
res.get_data()
|
||||
assert res.status_code == 200
|
||||
|
||||
|
@ -169,7 +174,7 @@ class TestWeb:
|
|||
def test_receive_mode_message_no_files(self, temp_dir, common_obj):
|
||||
web = web_obj(temp_dir, common_obj, "receive")
|
||||
|
||||
data_dir = os.path.join(temp_dir, "OnionShare")
|
||||
data_dir = os.path.join(temp_dir.name, "OnionShare")
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
web.settings.set("receive", "data_dir", data_dir)
|
||||
|
@ -200,7 +205,7 @@ class TestWeb:
|
|||
def test_receive_mode_message_and_files(self, temp_dir, common_obj):
|
||||
web = web_obj(temp_dir, common_obj, "receive")
|
||||
|
||||
data_dir = os.path.join(temp_dir, "OnionShare")
|
||||
data_dir = os.path.join(temp_dir.name, "OnionShare")
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
web.settings.set("receive", "data_dir", data_dir)
|
||||
|
@ -235,7 +240,7 @@ class TestWeb:
|
|||
def test_receive_mode_files_no_message(self, temp_dir, common_obj):
|
||||
web = web_obj(temp_dir, common_obj, "receive")
|
||||
|
||||
data_dir = os.path.join(temp_dir, "OnionShare")
|
||||
data_dir = os.path.join(temp_dir.name, "OnionShare")
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
web.settings.set("receive", "data_dir", data_dir)
|
||||
|
@ -267,7 +272,7 @@ class TestWeb:
|
|||
def test_receive_mode_no_message_no_files(self, temp_dir, common_obj):
|
||||
web = web_obj(temp_dir, common_obj, "receive")
|
||||
|
||||
data_dir = os.path.join(temp_dir, "OnionShare")
|
||||
data_dir = os.path.join(temp_dir.name, "OnionShare")
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
web.settings.set("receive", "data_dir", data_dir)
|
||||
|
@ -300,15 +305,21 @@ class TestWeb:
|
|||
res.get_data()
|
||||
assert res.status_code == 200
|
||||
|
||||
def test_cleanup(self, common_obj, temp_dir_1024, temp_file_1024):
|
||||
def test_cleanup(self, common_obj, temp_dir_1024):
|
||||
web = web_obj(temp_dir_1024, common_obj, "share", 3)
|
||||
|
||||
web.cleanup_filenames = [temp_dir_1024, temp_file_1024]
|
||||
temp_file = tempfile.NamedTemporaryFile()
|
||||
temp_dir = tempfile.TemporaryDirectory()
|
||||
|
||||
web.cleanup_tempfiles = [temp_file]
|
||||
web.cleanup_tempdirs = [temp_dir]
|
||||
web.cleanup()
|
||||
|
||||
assert os.path.exists(temp_file_1024) is False
|
||||
assert os.path.exists(temp_dir_1024) is False
|
||||
assert web.cleanup_filenames == []
|
||||
assert os.path.exists(temp_file.name) is False
|
||||
assert os.path.exists(temp_dir.name) is False
|
||||
|
||||
assert web.cleanup_tempfiles == []
|
||||
assert web.cleanup_tempdirs == []
|
||||
|
||||
|
||||
class TestZipWriterDefault:
|
||||
|
@ -339,8 +350,10 @@ class TestZipWriterDefault:
|
|||
assert default_zw.processed_size_callback(None) is None
|
||||
|
||||
def test_add_file(self, default_zw, temp_file_1024_delete):
|
||||
default_zw.add_file(temp_file_1024_delete)
|
||||
zipfile_info = default_zw.z.getinfo(os.path.basename(temp_file_1024_delete))
|
||||
default_zw.add_file(temp_file_1024_delete.name)
|
||||
zipfile_info = default_zw.z.getinfo(
|
||||
os.path.basename(temp_file_1024_delete.name)
|
||||
)
|
||||
|
||||
assert zipfile_info.compress_type == zipfile.ZIP_DEFLATED
|
||||
assert zipfile_info.file_size == 1024
|
||||
|
@ -568,7 +581,6 @@ class TestRangeRequests:
|
|||
resp = client.get(url, headers=headers)
|
||||
assert resp.status_code == 206
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "linux", reason="requires Linux")
|
||||
@check_unsupported("curl", ["--version"])
|
||||
def test_curl(self, temp_dir, tmpdir, common_obj):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue