Merge branch 'develop' of github.com:onionshare/onionshare into ros-fixes
@ -9,7 +9,7 @@ workflows:
|
||||
jobs:
|
||||
test-cli:
|
||||
docker:
|
||||
- image: circleci/python:3.8-buster
|
||||
- image: circleci/python:3.9-bullseye
|
||||
|
||||
working_directory: ~/repo
|
||||
|
||||
@ -37,7 +37,7 @@ jobs:
|
||||
|
||||
test-gui:
|
||||
docker:
|
||||
- image: circleci/python:3.8-buster
|
||||
- image: circleci/python:3.9-bullseye
|
||||
|
||||
working_directory: ~/repo
|
||||
|
||||
@ -50,16 +50,11 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y tor obfs4proxy gcc python3-dev python3-pyside2.qtcore python3-pyside2.qtwidgets python3-pyside2.qtgui
|
||||
sudo apt-get install -y xvfb x11-utils libxkbcommon-x11-0 libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev libxcb-render-util0 libxcb-icccm4 libxcb-keysyms1 libxcb-image0
|
||||
cd ~/repo/cli
|
||||
poetry install
|
||||
poetry build
|
||||
cp dist/onionshare_cli-*.whl ~/repo/desktop
|
||||
cd ~/repo/desktop
|
||||
pip install briefcase pytest pytest-briefcase pytest-faulthandler pytest-qt pytest-xvfb
|
||||
pip install $(python -c 'import toml; print(" ".join(toml.loads(open("pyproject.toml").read())["tool"]["briefcase"]["app"]["onionshare"]["requires"]))')
|
||||
poetry install
|
||||
|
||||
- run:
|
||||
name: Run tests
|
||||
command: |
|
||||
cd ~/repo/desktop
|
||||
./tests/run.sh
|
||||
xvfb-run poetry run ./tests/run.sh
|
||||
|
8
.gitignore
vendored
@ -59,10 +59,4 @@ venv
|
||||
# other
|
||||
.vscode
|
||||
onionshare.dist-info
|
||||
desktop/src/onionshare/resources/tor
|
||||
desktop/*.whl
|
||||
desktop/linux
|
||||
desktop/windows
|
||||
desktop/macOS
|
||||
# gets added automatically when building for Windows or macOS
|
||||
desktop/include
|
||||
desktop/onionshare/resources/tor
|
||||
|
@ -110,7 +110,7 @@
|
||||
## 1.3
|
||||
|
||||
* Major UI redesign, introducing many UX improvements
|
||||
* Client-side web interfact redesigned
|
||||
* Client-side web interface redesigned
|
||||
* New feature: Support for meek_lite pluggable transports (Amazon and Azure) - not yet ready for Windows or macOS, sorry
|
||||
* New feature: Support for custom obfs4 and meek_lite bridges (again, meek_lite not available on Windows/macOS yet)
|
||||
* New feature: Ability to cancel share before it starts
|
||||
|
8
LICENSE
@ -6,7 +6,7 @@ Copyright (C) 2014-2021 Micah Lee, et al. <micah@micahflee.com>
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@ -650,7 +650,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@ -669,11 +669,11 @@ might be different; for a GUI interface, you would use an "about box".
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
67
RELEASE.md
@ -9,9 +9,9 @@ Before making a release, you must update the version in these places:
|
||||
- [ ] `cli/pyproject.toml`
|
||||
- [ ] `cli/setup.py`
|
||||
- [ ] `cli/onionshare_cli/resources/version.txt`
|
||||
- [ ] `desktop/pyproject.toml` (under `version` and **don't forget** the `./onionshare_cli-$VERSION-py3-none-any.whl` dependency)
|
||||
- [ ] `desktop/src/setup.py`
|
||||
- [ ] `desktop/src/org.onionshare.OnionShare.appdata.xml`
|
||||
- [ ] `desktop/pyproject.toml`
|
||||
- [ ] `desktop/setup.py`
|
||||
- [ ] `desktop/org.onionshare.OnionShare.appdata.xml`
|
||||
- [ ] `docs/source/conf.py` (`version` at the top, and the `versions` list too)
|
||||
- [ ] `snap/snapcraft.yaml`
|
||||
|
||||
@ -19,6 +19,7 @@ If you update `flask-socketio`, ensure that you also update the [socket.io.min.j
|
||||
|
||||
Use tor binaries from the latest Tor Browser:
|
||||
|
||||
- [ ] `desktop/scripts/get-tor-linux.py`
|
||||
- [ ] `desktop/scripts/get-tor-osx.py`
|
||||
- [ ] `desktop/scripts/get-tor-windows.py`
|
||||
|
||||
@ -42,7 +43,7 @@ Finalize localization:
|
||||
|
||||
You also must edit these files:
|
||||
|
||||
- [ ] `desktop/src/org.onionshare.OnionShare.appdata.xml` should have the correct release date, and links to correct screenshots
|
||||
- [ ] `desktop/org.onionshare.OnionShare.appdata.xml` should have the correct release date, and links to correct screenshots
|
||||
- [ ] `CHANGELOG.md` should be updated to include a list of all major changes since the last release
|
||||
|
||||
Make sure snapcraft packaging works. In `snap/snapcraft.yaml`:
|
||||
@ -97,73 +98,45 @@ snapcraft login
|
||||
snapcraft upload --release=stable onionshare_$VERSION_amd64.snap
|
||||
```
|
||||
|
||||
## Linux AppImage release
|
||||
|
||||
_Note: AppImage packages are currently broken due to [this briefcase bug](https://github.com/beeware/briefcase/issues/504). Until it's fixed, OnionShare for Linux will only be available in Flatpak and Snapcraft._
|
||||
|
||||
Set up the development environment described in `README.md`.
|
||||
|
||||
Make sure your virtual environment is active:
|
||||
|
||||
```sh
|
||||
. venv/bin/activate
|
||||
```
|
||||
|
||||
Run the AppImage build script:
|
||||
|
||||
```sh
|
||||
./package/linux/build-appimage.py
|
||||
```
|
||||
|
||||
## Windows
|
||||
|
||||
Set up the development environment described in `README.md`. And install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) and add `C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86` to your path.
|
||||
Set up the development environment described in desktop `README.md`.
|
||||
|
||||
Make sure your virtual environment is active:
|
||||
|
||||
```
|
||||
venv\Scripts\activate.bat
|
||||
```
|
||||
- To get `signtool.exe`, install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) and add `C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x86` to your path.
|
||||
- Go to https://dotnet.microsoft.com/download/dotnet-framework and download and install .NET Framework 3.5 SP1 Runtime. I downloaded `dotnetfx35.exe`.
|
||||
- Go to https://wixtoolset.org/releases/ and download and install WiX toolset. I downloaded `wix311.exe`. Add `C:\Program Files (x86)\WiX Toolset v3.11\bin` to the path.
|
||||
|
||||
Run the Windows build script:
|
||||
|
||||
```
|
||||
python package\windows\build.py
|
||||
poetry run python .\package\build-windows.py
|
||||
```
|
||||
|
||||
This will create `desktop/windows/OnionShare-$VERSION.msi`, signed.
|
||||
This will create `desktop/dist/OnionShare-$VERSION.msi`, signed.
|
||||
|
||||
## macOS
|
||||
|
||||
Set up the development environment described in `README.md`. And install `create-dmg`:
|
||||
Set up the development environment described in `README.md`.
|
||||
|
||||
Then build an executable, make it a macOS app bundle, and package it in a dmg:
|
||||
|
||||
```sh
|
||||
brew install create-dmg
|
||||
poetry run ./package/build-mac.py
|
||||
```
|
||||
|
||||
Make sure your virtual environment is active:
|
||||
|
||||
```sh
|
||||
. venv/bin/activate
|
||||
```
|
||||
|
||||
Run the macOS build script:
|
||||
|
||||
```sh
|
||||
./package/macos/build.py --with-codesign
|
||||
```
|
||||
The will create `dist/OnionShare-$VERSION.dmg`.
|
||||
|
||||
Now, notarize the release. You must have an app-specific Apple ID password saved in the login keychain called `onionshare-notarize`.
|
||||
|
||||
- Notarize it: `xcrun altool --notarize-app --primary-bundle-id "com.micahflee.onionshare" -u "micah@micahflee.com" -p "@keychain:onionshare-notarize" --file macOS/OnionShare.dmg`
|
||||
- Notarize it: `xcrun altool --notarize-app --primary-bundle-id "com.micahflee.onionshare" -u "micah@micahflee.com" -p "@keychain:onionshare-notarize" --file dist/OnionShare-$VERSION.dmg`
|
||||
- Wait for it to get approved, check status with: `xcrun altool --notarization-history 0 -u "micah@micahflee.com" -p "@keychain:onionshare-notarize"`
|
||||
- After it's approved, staple the ticket: `xcrun stapler staple macOS/OnionShare.dmg`
|
||||
- After it's approved, staple the ticket: `xcrun stapler staple dist/OnionShare-$VERSION.dmg`
|
||||
|
||||
This will create `desktop/macOS/OnionShare.dmg`, signed and notarized.
|
||||
This will create `desktop/dist/OnionShare-$VERSION.dmg`, signed and notarized.
|
||||
|
||||
## Source package
|
||||
|
||||
To make a source package, run `./build-source.sh $TAG`, where `$TAG` is the the name of the signed git tag, e.g. `v2.1`.
|
||||
To make a source package, run `./build-source.sh $TAG`, where `$TAG` is the name of the signed git tag, e.g. `v2.1`.
|
||||
|
||||
This will create `dist/onionshare-$VERSION.tar.gz`.
|
||||
|
||||
|
@ -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:
|
||||
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":
|
||||
# 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 tor_path:
|
||||
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,21 +114,8 @@ 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()
|
||||
|
||||
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
|
||||
# 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]
|
||||
@ -152,6 +129,7 @@ class Meek(object):
|
||||
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":
|
||||
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",
|
||||
)
|
||||
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")
|
||||
self.common.get_resource_path(
|
||||
"torrc_template-obfs4"
|
||||
)
|
||||
) as o:
|
||||
f.write(o.read())
|
||||
elif self.settings.get("bridges_builtin_pt") == "meek-azure":
|
||||
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 self.settings.get("bridges_builtin_pt") == "snowflake":
|
||||
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(
|
||||
|
@ -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 (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;
|
||||
|
@ -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
@ -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):
|
||||
|
@ -9,135 +9,83 @@ git clone https://github.com/onionshare/onionshare.git
|
||||
cd onionshare/desktop
|
||||
```
|
||||
|
||||
Make sure you have Python 3 installed. If you're using Windows or macOS, install version 3.9.9 [from python.org](https://www.python.org/downloads/release/python-399/). For Windows, make sure to install the 32-bit (x86) version, and to check the box to add python to the path on the first page of the installer.
|
||||
|
||||
Make sure you have [poetry installed](https://python-poetry.org/docs/#installation), and then install the dependencies:
|
||||
|
||||
```sh
|
||||
poetry install
|
||||
```
|
||||
|
||||
### Install platform-specific dependencies
|
||||
|
||||
#### Linux
|
||||
|
||||
In Ubuntu 20.04 you need the `libxcb-xinerama0` package installed.
|
||||
|
||||
Install python dependencies:
|
||||
|
||||
```sh
|
||||
pip3 install --user poetry requests
|
||||
```
|
||||
|
||||
Download Tor Browser and extract the binaries:
|
||||
|
||||
```sh
|
||||
./scripts/get-tor-linux.py
|
||||
poetry run ./scripts/get-tor-linux.py
|
||||
```
|
||||
|
||||
#### macOS
|
||||
|
||||
Download and install Python 3.8.6 from https://www.python.org/downloads/release/python-386/. I downloaded `python-3.8.6-macosx10.9.pkg`. (You may need to also run `/Applications/Python\ 3.8/Install\ Certificates.command`.)
|
||||
|
||||
Install python dependencies:
|
||||
|
||||
```sh
|
||||
pip3 install --user poetry requests
|
||||
```
|
||||
|
||||
Download Tor Browser and extract the binaries:
|
||||
|
||||
```sh
|
||||
./scripts/get-tor-osx.py
|
||||
poetry run ./scripts/get-tor-osx.py
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
These instructions include adding folders to the path in Windows. To do this, go to Start and type "advanced system settings", and open "View advanced system settings" in the Control Panel. Click Environment Variables. Under "System variables" double-click on Path. From there you can add and remove folders that are available in the PATH.
|
||||
|
||||
Download Python 3.8.6, 32-bit (x86) from https://www.python.org/downloads/release/python-386/. I downloaded `python-3.8.6.exe`. When installing it, make sure to check the "Add Python 3.8 to PATH" checkbox on the first page of the installer.
|
||||
|
||||
Download and install 7-Zip from http://www.7-zip.org/download.html. I downloaded `7z1900.exe`. Add `C:\Program Files (x86)\7-Zip` to your path.
|
||||
|
||||
Install python dependencies:
|
||||
|
||||
```
|
||||
pip install poetry requests
|
||||
```
|
||||
Download and install 7-Zip from https://7-zip.org/download.html. I downloaded `7z1900.exe`. Add `C:\Program Files (x86)\7-Zip` to your path.
|
||||
|
||||
Download Tor Browser and extract the binaries:
|
||||
|
||||
```
|
||||
python scripts\get-tor-windows.py
|
||||
```sh
|
||||
poetry run python scripts\get-tor-windows.py
|
||||
```
|
||||
|
||||
### Compile dependencies
|
||||
|
||||
Install Go. The simplest way to make sure everything works is to install Go by following [these instructions](https://golang.org/doc/install). (In Windows, make sure to install the 32-bit version of Go, such as `go1.17.3.windows-386.msi`.)
|
||||
Install Go. The simplest way to make sure everything works is to install Go by following [these instructions](https://golang.org/doc/install). (In Windows, make sure to install the 32-bit version of Go, such as `go1.17.5.windows-386.msi`.)
|
||||
|
||||
Download and compile `meek-client`:
|
||||
|
||||
```
|
||||
./scripts/build-meek-client.py
|
||||
```
|
||||
|
||||
### Prepare the virtual environment
|
||||
|
||||
OnionShare uses [Briefcase](https://briefcase.readthedocs.io/en/latest/).
|
||||
|
||||
Install Briefcase dependencies by following [these instructions](https://docs.beeware.org/en/latest/tutorial/tutorial-0.html#install-dependencies).
|
||||
|
||||
Now create and/or activate a virtual environment.
|
||||
|
||||
* Linux and macOS
|
||||
```
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
```
|
||||
* Windows
|
||||
```
|
||||
python -m venv venv
|
||||
venv\Scripts\activate.bat
|
||||
```
|
||||
|
||||
While your virtual environment is active, install briefcase from pip.
|
||||
|
||||
```
|
||||
pip install briefcase
|
||||
```
|
||||
|
||||
In order to work with the desktop app, you'll need to build a wheel of the CLI package first, and copy it into the `desktop` folder. You'll need to re-run this script each time you change the CLI code.
|
||||
|
||||
```sh
|
||||
python scripts/rebuild-cli.py
|
||||
./scripts/build-meek-client.py
|
||||
```
|
||||
|
||||
### Running OnionShare from the source code tree
|
||||
|
||||
Inside the virtual environment, run OnionShare like this to install all of the dependencies:
|
||||
To run OnionShare from the source tree:
|
||||
|
||||
```
|
||||
briefcase dev -d
|
||||
```sh
|
||||
poetry run onionshare
|
||||
poetry run onionshare --help
|
||||
poetry run onionshare -v
|
||||
poetry run onionshare -v --local-only
|
||||
```
|
||||
|
||||
Once you have the dependencies installed, you can run it using the `dev.sh` script, which lets you use command line arguments, such as to `--verbose` or `--local-only`:
|
||||
You can also run `onionshare-cli` from the source tree, and it will look for Tor binaries in `desktop/onionshare/resources/tor`.
|
||||
|
||||
```sh
|
||||
poetry run onionshare-cli --help
|
||||
```
|
||||
./scripts/dev.sh --help
|
||||
./scripts/dev.sh -v
|
||||
./scripts/dev.sh -v --local-only
|
||||
```
|
||||
|
||||
Windows uses `scripts\dev.bat` instead.
|
||||
|
||||
## Running tests
|
||||
|
||||
Install these packages inside your virtual environment:
|
||||
Run the tests:
|
||||
|
||||
```sh
|
||||
pip install pytest pytest-briefcase pytest-faulthandler pytest-qt
|
||||
```
|
||||
|
||||
Then run the tests:
|
||||
|
||||
```sh
|
||||
./tests/run.sh
|
||||
poetry run ./tests/run.sh
|
||||
```
|
||||
|
||||
If you want to run tests while hiding the GUI, you must have the `xvfb` package installed, and then:
|
||||
|
||||
```sh
|
||||
xvfb-run ./tests/run.sh
|
||||
xvfb-run poetry run ./tests/run.sh
|
||||
```
|
||||
|
@ -507,5 +507,4 @@ class GuiCommon:
|
||||
return strings._("error_stealth_not_supported")
|
||||
elif type(e) is PortNotAvailable:
|
||||
return strings._("error_port_not_available")
|
||||
|
||||
return None
|
@ -163,6 +163,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
# Start the "Connecting to Tor" dialog, which calls onion.connect()
|
||||
tor_con = TorConnectionDialog(self.common)
|
||||
tor_con.canceled.connect(self.tor_connection_canceled)
|
||||
tor_con.success.connect(self.tabs.tor_is_connected)
|
||||
tor_con.open_tor_settings.connect(self.tor_connection_open_tor_settings)
|
||||
if not self.common.gui.local_only:
|
||||
tor_con.start()
|
Before Width: | Height: | Size: 688 B After Width: | Height: | Size: 688 B |
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 305 B |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 456 B |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 182 B After Width: | Height: | Size: 182 B |
Before Width: | Height: | Size: 646 B After Width: | Height: | Size: 646 B |
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 437 B |
Before Width: | Height: | Size: 638 B After Width: | Height: | Size: 638 B |
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 412 B |
Before Width: | Height: | Size: 738 B After Width: | Height: | Size: 738 B |
Before Width: | Height: | Size: 754 B After Width: | Height: | Size: 754 B |
Before Width: | Height: | Size: 435 B After Width: | Height: | Size: 435 B |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 221 B After Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 380 B After Width: | Height: | Size: 380 B |
Before Width: | Height: | Size: 468 B After Width: | Height: | Size: 468 B |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 347 B |
Before Width: | Height: | Size: 342 B After Width: | Height: | Size: 342 B |
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 389 B After Width: | Height: | Size: 389 B |
Before Width: | Height: | Size: 473 B After Width: | Height: | Size: 473 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@ -101,9 +101,9 @@
|
||||
"gui_settings_connection_type_automatic_option": "Versuche automatische Konfiguration mittels Tor Browser",
|
||||
"gui_settings_connection_type_test_button": "Verbindung zu Tor testen",
|
||||
"gui_settings_authenticate_label": "Authentifizierungseinstellungen für Tor",
|
||||
"gui_settings_tor_bridges": "Unterstützung für Tor-Bridges",
|
||||
"gui_settings_meek_lite_expensive_warning": "Achtung: Die „meek_lite“-Bridges sind für das Tor-Projekt sehr kostspielig.<br><br> Nutze sie nur, wenn du dich nicht direkt, per obfs4-Transport oder über andere, normale Bridges zum Tor-Netzwerk verbinden kannst.",
|
||||
"gui_settings_tor_bridges_invalid": "Keine der ausgewählten Bridges funktioniert.\nÜberprüfe sie oder gib andere an.",
|
||||
"gui_settings_tor_bridges": "Mittels einer Tor-Bridge verbinden?",
|
||||
"gui_settings_meek_lite_expensive_warning": "Achtung: Die „meek-azure“-Bridges sind für das Tor-Projekt sehr kostspielig.<br><br> Nutze sie nur, wenn du dich nicht direkt, per obfs4-Transport oder über andere, normale Bridges zum Tor-Netzwerk verbinden kannst.",
|
||||
"gui_settings_tor_bridges_invalid": "Keine der ausgewählten Bridges funktioniert. Überprüfe sie oder gib andere an.",
|
||||
"settings_error_unknown": "Kann nicht zum Tor-Controller verbinden, weil deine Einstellungen keinen Sinn ergeben.",
|
||||
"settings_error_automatic": "Kann nicht zum Tor-Controller verbinden. Läuft der Tor Browser (kann von https://www.torproject.org/ heruntergeladen werden) im Hintergrund?",
|
||||
"settings_error_socket_port": "Kann unter {}:{} nicht zum Tor-Controller verbinden.",
|
||||
@ -162,7 +162,7 @@
|
||||
"gui_upload_in_progress": "Upload gestartet {}",
|
||||
"gui_download_in_progress": "Download gestartet {}",
|
||||
"gui_open_folder_error_nautilus": "Kann den Ordner nicht öffnen, weil Nautilus nicht verfügbar ist. Die Datei ist hier: {}",
|
||||
"gui_settings_language_label": "Bevorzugte Sprache",
|
||||
"gui_settings_language_label": "Sprache",
|
||||
"gui_settings_language_changed_notice": "Starte OnionShare neu, damit die neue Sprache übernommen wird.",
|
||||
"help_config": "Ort deiner eigenen JSON Konfigurationsdatei (optional)",
|
||||
"timeout_upload_still_running": "Warte bis Upload vollständig ist",
|
||||
@ -316,5 +316,30 @@
|
||||
"gui_qr_label_url_title": "OnionShare-Adresse",
|
||||
"gui_copied_client_auth": "Privater Schlüssel in die Zwischenablage kopiert",
|
||||
"gui_copied_client_auth_title": "Privater Schlüssel kopiert",
|
||||
"gui_copy_client_auth": "Privaten Schlüssel kopieren"
|
||||
"gui_copy_client_auth": "Privaten Schlüssel kopieren",
|
||||
"gui_dragdrop_sandbox_flatpak": "Um die Flatpak Sandbox sicherer zu machen, wird Drag und Drop nicht unterstützt. Bitte nutze stattdessen die Buttons \"Dateien hinzufügen\" und \"Ordner hinzufügen\".",
|
||||
"gui_tor_settings_window_title": "Tor Einstellungen",
|
||||
"gui_settings_controller_extras_label": "Tor Einstellungen",
|
||||
"gui_settings_bridge_use_checkbox": "Benutze eine Brigde",
|
||||
"gui_settings_bridge_radio_builtin": "Wähle eine eingebaute Bridge",
|
||||
"gui_settings_bridge_none_radio_option": "Keine Bridge verwenden",
|
||||
"gui_settings_bridge_moat_button": "Neue Bridge verwenden",
|
||||
"gui_settings_bridge_custom_placeholder": "Schreibe im Format adresse:port (eine pro Zeile)",
|
||||
"gui_settings_moat_bridges_invalid": "Du hast noch keine Bridge von torproject.org angefragt.",
|
||||
"gui_settings_stop_active_tabs_label": "Es laufen noch Services in deinen Tabs.\nDu musst alle Services beenden, bevor du die Tor Einstellungen ändern kannst.",
|
||||
"gui_settings_version_label": "Du verwendest OnionShare {}",
|
||||
"gui_settings_help_label": "Du benötigst Hilfe? Gehe zu <a href='https://docs.onionshare.org'>docs.onionshare.org</a>",
|
||||
"mode_settings_website_custom_csp_checkbox": "Sende einen benutzerdefinierten Content Security Policy header",
|
||||
"moat_contact_label": "Kontaktiere BridgeDB...",
|
||||
"moat_captcha_label": "Löse das CAPTCHA um eine Bridge zu laden.",
|
||||
"moat_captcha_placeholder": "Gib die Zeichen auf dem Bild ein",
|
||||
"moat_captcha_submit": "Absenden",
|
||||
"moat_captcha_reload": "Neu laden",
|
||||
"moat_bridgedb_error": "Fehler beim kontaktieren der BridgeDB.",
|
||||
"moat_captcha_error": "Die Lösung ist nicht korrekt. Bitte nochmal versuchen.",
|
||||
"mode_tor_not_connected_label": "OnionShare ist nicht mit dem Tor Netzwerk verbunden",
|
||||
"gui_settings_bridge_moat_radio_option": "Verwende eine Bridge von torproject.org",
|
||||
"moat_solution_empty_error": "Du musst die Zeichen auf dem Bild eingeben",
|
||||
"gui_settings_bridge_custom_radio_option": "Stelle eine Bridge aus einer dir bekannten vertraulichen Quelle bereit",
|
||||
"gui_settings_tor_bridges_label": "Brigdes helfen dir das Tor Netzwerk an Orten zu verwenden, wo es blockiert wird. Je nachdem wo du bist, funktioniert eine Bridge besser als eine andere."
|
||||
}
|
@ -90,16 +90,16 @@
|
||||
"gui_settings_authenticate_no_auth_option": "Χωρίς επαλήθευση ή επαλήθευση με cookie",
|
||||
"gui_settings_authenticate_password_option": "Κωδικός",
|
||||
"gui_settings_password_label": "Κωδικός",
|
||||
"gui_settings_tor_bridges": "Υποστήριξη γεφυρών Tor",
|
||||
"gui_settings_tor_bridges": "Σύνδεση με χρήση γέφυρας Tor;",
|
||||
"gui_settings_tor_bridges_no_bridges_radio_option": "Να μη χρησιμοποιηθούν γέφυρες",
|
||||
"gui_settings_tor_bridges_obfs4_radio_option": "Να χρησιμοποιηθούν τα ενσωματωμένα obfs4 pluggable transports",
|
||||
"gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy": "Να χρησιμοποιηθούν τα ενσωματωμένα obfs4 pluggable transports (απαιτείται το πρόγραμμα obfs4proxy)",
|
||||
"gui_settings_tor_bridges_meek_lite_azure_radio_option": "Να χρησιμοποιηθουν τα ενσωματωμένα meek_lite (Azure) pluggable transports",
|
||||
"gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy": "Να χρησιμοποιηθούν τα ενσωματωμένα meek_lite (Azure) pluggable transports (απαιτείται το πρόγραμμα obfs4proxy)",
|
||||
"gui_settings_meek_lite_expensive_warning": "Προσοχή: Τα meek_lite bridges επιβαρύνουν πολύ το Tor Project στη λειτουργία. <br><br> Χρησιμοποιήστε τα μόνο αν δεν μπορείτε να συνδεθείτε κατ' ευθείαν στο Tor μέσω obfs4 transports ή άλλων κανονικών bridges.",
|
||||
"gui_settings_meek_lite_expensive_warning": "Προσοχή: Οι γέφυρες meek_azure επιβαρύνουν τη λειτουργία του Tor Project. <br><br> Χρησιμοποιήστε τες μόνο αν δεν μπορείτε να συνδεθείτε κατ' ευθείαν στο Tor μέσω obfs4 transports ή άλλων κανονικών γεφυρών.",
|
||||
"gui_settings_tor_bridges_custom_radio_option": "Χρήση παραμετροποιημένων γεφυρών",
|
||||
"gui_settings_tor_bridges_custom_label": "Αποκτήστε γέφυρες στο <a href=\"https://bridges.torproject.org/options?lang=el\"> https://bridges.torproject.org</a>",
|
||||
"gui_settings_tor_bridges_invalid": "Δεν λειτούργησε κάποιο από τα bridges που προσθέσατε.\nΞαναελέγξτε τα ή προσθέστε άλλα.",
|
||||
"gui_settings_tor_bridges_invalid": "Καμία γέφυρα που προσθέσατε δεν λειτουργεί. Ελέγξτε ξανά ή προσθέστε άλλες.",
|
||||
"gui_settings_button_save": "Αποθήκευση",
|
||||
"gui_settings_button_cancel": "Άκυρο",
|
||||
"gui_settings_button_help": "Βοήθεια",
|
||||
@ -134,8 +134,8 @@
|
||||
"gui_server_autostop_timer_expired": "Το χρονόμετρο αυτόματης διακοπής έχει ήδη τελειώσει. Παρακαλώ ρυθμίστε το για να ξεκινήσετε το διαμοιρασμό.",
|
||||
"share_via_onionshare": "Μοιραστείτε μέσω OnionShare",
|
||||
"gui_save_private_key_checkbox": "Χρήση μόνιμης διεύθυνσης",
|
||||
"gui_share_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare μπορεί να <b>κατεβάσει</b> τα αρχεία σας χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_receive_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare, μπορεί να <b>ανεβάσει</b> αρχεία στον υπολογιστή σας χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_share_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare και το ιδιωτικό κλειδί μπορεί να <b>κατεβάσει</b> τα αρχεία σας χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_receive_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare και το ιδιωτικό κλειδί μπορεί να <b>ανεβάσει</b> αρχεία στον υπολογιστή σας χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_url_label_persistent": "Αυτή η σελίδα διαμοιρασμού δεν θα πάψει να λειτουργεί αυτόματα.<br><br>Όσοι μοιράζονται αρχεία μαζί σας θα μπορέσουν να ξαναχρησιμοποιήσουν αυτή τη διεύθυνση αργότερα. (Για να χρησιμοποιήσετε διευθύνσεις μιας χρήσης, απενεργοποιήστε τη λειτουργία \"Χρήση μόνιμης διεύθυνσης\" στις Ρυθμίσεις.)",
|
||||
"gui_url_label_stay_open": "Αυτή η σελίδα διαμοιρασμού δεν θα πάψει να λειτουργεί αυτόματα.",
|
||||
"gui_url_label_onetime": "Αυτός ο διαμοιρασμός θα σταματήσει μετά την πρώτη λήψη.",
|
||||
@ -178,7 +178,7 @@
|
||||
"gui_upload_finished": "",
|
||||
"gui_download_in_progress": "",
|
||||
"gui_open_folder_error_nautilus": "Δεν μπορεί να ανοιχτεί ο φάκελος γιατί το nautilus δεν είναι διαθέσιμο. Το αρχείο είναι εδω: {}",
|
||||
"gui_settings_language_label": "Προτιμώμενη γλώσσα",
|
||||
"gui_settings_language_label": "Γλώσσα",
|
||||
"gui_settings_language_changed_notice": "Επανεκκινήστε το OnionShare για να εφαρμοστεί η αλλαγή γλώσσας.",
|
||||
"timeout_upload_still_running": "Αναμονή ολοκλήρωσης του ανεβάσματος",
|
||||
"gui_add_files": "Προσθήκη αρχείων",
|
||||
@ -225,7 +225,7 @@
|
||||
"hours_first_letter": "ώ",
|
||||
"minutes_first_letter": "λ",
|
||||
"seconds_first_letter": "δ",
|
||||
"gui_website_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare μπορεί <b>να επισκεφτεί</b> την ιστοσελίδα χρησιμοποιώντας τον <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_website_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare και το ιδιωτικό κλειδί μπορεί <b>να επισκεφτεί</b> την ιστοσελίδα σας χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_mode_website_button": "Δημοσίευση ιστοσελίδας",
|
||||
"gui_website_mode_no_files": "Δεν έχει γίνει διαμοιρασμός ιστοσελίδας ακόμα",
|
||||
"incorrect_password": "Λάθος κωδικός",
|
||||
@ -237,14 +237,14 @@
|
||||
"gui_receive_flatpak_data_dir": "Επειδή έχετε εγκαταστήσει το OnionShare μέσω Flatpak, θα πρέπει να αποθηκεύσετε τα αρχεία μέσα σε έναν φάκελο στο ~/OnionShare.",
|
||||
"gui_chat_stop_server": "Τερματισμός διακομιστή συνομιλίας",
|
||||
"gui_chat_start_server": "Έναρξη διακομιστή συνομιλίας",
|
||||
"mode_settings_website_disable_csp_checkbox": "Μην στέλνετε κεφαλίδα με περιεχόμενο από την πολιτικής ασφάλειας σας (επιτρέπει στην ιστοσελίδα σας να χρησιμοποιεί πόρους τρίτων)",
|
||||
"mode_settings_website_disable_csp_checkbox": "Μην στέλνετε την προεπιλεγμένη κεφαλίδα Πολιτικής Ασφάλειας Περιεχομένου (επιτρέπει στην ιστοσελίδα σας να χρησιμοποιεί πόρους τρίτων)",
|
||||
"mode_settings_receive_data_dir_browse_button": "Επιλογή",
|
||||
"mode_settings_receive_data_dir_label": "Αποθήκευση αρχείων σε",
|
||||
"mode_settings_share_autostop_sharing_checkbox": "Τερματισμός κοινής χρήσης με την ολοκλήρωση αρχείων (αποεπιλέξτε για λήψη μεμονωμένων αρχείων)",
|
||||
"mode_settings_legacy_checkbox": "Χρήση παλαιάς διεύθυνσης (δεν προτείνεται η χρήση υπηρεσία v2 onion)",
|
||||
"mode_settings_autostop_timer_checkbox": "Προγραμματισμένος τερματισμός",
|
||||
"mode_settings_autostart_timer_checkbox": "Προγραμματισμένη εκκίνηση",
|
||||
"mode_settings_public_checkbox": "Χωρίς χρήση κωδικού πρόσβασης",
|
||||
"mode_settings_public_checkbox": "Δημόσια υπηρεσία OnionShare (απενεργοποιεί το ιδιωτικό κλειδί)",
|
||||
"mode_settings_persistent_checkbox": "Αποθήκευση της καρτέλας και αυτόματο άνοιγμά της με την έναρξη του OnionShare",
|
||||
"mode_settings_advanced_toggle_hide": "Απόκρυψη προχωρημένων ρυθμίσεων",
|
||||
"mode_settings_advanced_toggle_show": "Εμφάνιση προχωρημένων ρυθμίσεων",
|
||||
@ -279,7 +279,7 @@
|
||||
"error_port_not_available": "Η θύρα OnionShare δεν είναι διαθέσιμη",
|
||||
"gui_rendezvous_cleanup_quit_early": "Πρόωρη έξοδος",
|
||||
"gui_rendezvous_cleanup": "Αναμονή για τερματισμό των κυκλωμάτων του Tor για να βεβαιωθείτε ότι τα αρχεία σας έχουν μεταφερθεί με επιτυχία.\n\nΑυτό μπορεί να διαρκέσει λίγα λεπτά.",
|
||||
"gui_chat_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση του OnionShare μπορεί <b>να συμμετέχει στο δωμάτιο συνομιλίας</b> με χρήση του <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_chat_url_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare και το ιδιωτικό κλειδί μπορεί να <b>συμμετέχει στο δωμάτιο συνομιλίας</b> χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_color_mode_changed_notice": "Επανεκκινήστε το OnionShare για εφαρμοστεί το νέο χρώμα.",
|
||||
"history_receive_read_message_button": "Ανάγνωση μηνύματος",
|
||||
"mode_settings_receive_webhook_url_checkbox": "Χρήση ειδοποίησης webhook",
|
||||
@ -289,5 +289,50 @@
|
||||
"gui_status_indicator_chat_started": "Σε συνομιλία",
|
||||
"gui_status_indicator_chat_scheduled": "Δρομολόγηση…",
|
||||
"gui_status_indicator_chat_working": "Εκκίνηση…",
|
||||
"gui_status_indicator_chat_stopped": "Έτοιμο για συνομιλία"
|
||||
"gui_status_indicator_chat_stopped": "Έτοιμο για συνομιλία",
|
||||
"gui_copied_client_auth_title": "Το ιδιωτικό κλειδί αντιγράφηκε",
|
||||
"gui_qr_label_url_title": "Διεύθυνση OnionShare",
|
||||
"gui_reveal": "Εμφάνιση",
|
||||
"gui_hide": "Απόκρυψη",
|
||||
"gui_share_url_public_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare μπορεί να <b>κατεβάσει</b> τα αρχεία σας χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_website_url_public_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare μπορεί <b>να επισκεφθεί</b> την ιστοσελίδα σας χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_chat_url_public_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare μπορεί να <b>συμμετέχει στο δωμάτιο συνομιλίας</b> χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_url_instructions_public_mode": "Στείλτε την παρακάτω διεύθυνση OnionShare:",
|
||||
"gui_settings_theme_label": "Θέμα",
|
||||
"gui_copy_client_auth": "Αντιγραφή ιδιωτικού κλειδιού",
|
||||
"gui_copied_client_auth": "Το ιδιωτικό κλειδί αντιγράφηκε στο πρόχειρο",
|
||||
"gui_qr_label_auth_string_title": "Ιδιωτικό κλειδί",
|
||||
"gui_please_wait_no_button": "Εκκίνηση…",
|
||||
"gui_server_doesnt_support_stealth": "Αυτή η έκδοση Tor, δεν υποστηρίζει το stealth (πιστοποίηση πελάτη). Παρακαλούμε δοκιμάστε με μια νεότερη έκδοση του Tor ή χρησιμοποιήστε τη λειτουργία 'δημόσιο' αν δεν χρειάζεται να είναι ιδιωτική.",
|
||||
"gui_receive_url_public_description": "<b>Οποιοσδήποτε</b> με αυτή τη διεύθυνση OnionShare μπορεί να <b>ανεβάσει</b> αρχεία στον υπολογιστή σας, χρησιμοποιώντας το <b>Tor Browser</b>: <img src='{}' />",
|
||||
"gui_settings_theme_auto": "Αυτόματο",
|
||||
"gui_settings_theme_dark": "Σκοτεινό",
|
||||
"gui_url_instructions": "Αρχικά, στείλτε την παρακάτω διεύθυνση OnionShare:",
|
||||
"gui_settings_theme_light": "Φωτεινό",
|
||||
"gui_client_auth_instructions": "Στη συνέχεια, στείλτε το ιδιωτικό κλειδί για πρόσβαση στην υπηρεσία OnionShare:",
|
||||
"gui_dragdrop_sandbox_flatpak": "Για να γίνει πιο ασφαλές το sandbox του Flatpak, δεν υποστηρίζεται η μεταφορά και απόθεση. Χρησιμοποιήστε τα κουμπιά Προσθήκη αρχείων και Προσθήκη φακέλου για να αναζητήσετε αρχεία.",
|
||||
"moat_captcha_label": "Λύστε το CAPTCHA για να αιτηθείτε μια γέφυρα.",
|
||||
"gui_settings_tor_bridges_label": "Οι γέφυρες σας βοηθούν να αποκτήσετε πρόσβαση στο δίκτυο Tor σε τοποθεσίες όπου είναι αποκλεισμένο. Ανάλογα με το πού βρίσκεστε, μια γέφυρα μπορεί να λειτουργεί καλύτερα από μια άλλη.",
|
||||
"moat_captcha_submit": "Υποβολή",
|
||||
"moat_solution_empty_error": "Πρέπει να εισαγάγετε τους χαρακτήρες από την εικόνα",
|
||||
"moat_contact_label": "Επικοινωνία με BridgeDB...",
|
||||
"gui_tor_settings_window_title": "Ρυθμίσεις Tor",
|
||||
"gui_settings_controller_extras_label": "Ρυθμίσεις Tor",
|
||||
"gui_settings_bridge_use_checkbox": "Χρήση γέφυρας",
|
||||
"gui_settings_bridge_radio_builtin": "Επιλέξτε μια ενσωματωμένη γέφυρα",
|
||||
"gui_settings_bridge_none_radio_option": "Χωρίς χρήση γέφυρας",
|
||||
"gui_settings_bridge_moat_radio_option": "Αιτηθείτε μια γέφυρα από torproject.org",
|
||||
"gui_settings_bridge_moat_button": "Αίτημα για νέα γέφυρα",
|
||||
"gui_settings_bridge_custom_radio_option": "Προτείνετε μια γέφυρα για την οποία ενημερωθήκατε από αξιόπιστη πηγή",
|
||||
"gui_settings_bridge_custom_placeholder": "πληκτρολογήστε διεύθυνση: πόρτα (μια ανά γραμμή)",
|
||||
"gui_settings_moat_bridges_invalid": "Δεν έχετε αιτηθεί ακόμα γέφυρα από το torproject.org.",
|
||||
"gui_settings_stop_active_tabs_label": "Υπάρχουν υπηρεσίες που εκτελούνται σε ορισμένες από τις καρτέλες σας.\nΠρέπει να σταματήσετε όλες τις υπηρεσίες για να αλλάξετε τις ρυθμίσεις του Tor.",
|
||||
"gui_settings_version_label": "Χρησιμοποιείτε το OnionShare {}",
|
||||
"gui_settings_help_label": "Χρειάζεστε βοήθεια; Δείτε το <a href='https://docs.onionshare.org'>docs.onionshare.org</a>",
|
||||
"mode_settings_website_custom_csp_checkbox": "Αποστολή προσαρμοσμένης κεφαλίδας Πολιτικής Ασφαλείας Περιεχομένου",
|
||||
"moat_captcha_placeholder": "Εισαγάγετε τους χαρακτήρες από την εικόνα",
|
||||
"moat_captcha_reload": "Επαναφόρτωση",
|
||||
"moat_bridgedb_error": "Σφάλμα επικοινωνίας με BridgeDB.",
|
||||
"moat_captcha_error": "Η λύση δεν είναι σωστή. Παρακαλούμε δοκιμάστε ξανά.",
|
||||
"mode_tor_not_connected_label": "Το OnionShare δεν είναι συνδεδεμένο με το δίκτυο Tor"
|
||||
}
|
@ -41,8 +41,8 @@
|
||||
"gui_settings_connection_type_bundled_option": "Usa la versión de Tor incorporada en OnionShare",
|
||||
"gui_settings_connection_type_automatic_option": "Intentar la configuración automática con el Navegador Tor",
|
||||
"gui_settings_connection_type_test_button": "Probar la conexión a Tor",
|
||||
"gui_settings_tor_bridges": "Soporte para puentes Tor",
|
||||
"gui_settings_tor_bridges_invalid": "No funciona ninguno de los puentes agregados.\nVuelve a comprobarlos o añade otros.",
|
||||
"gui_settings_tor_bridges": "¿Conectar usando un puente Tor?",
|
||||
"gui_settings_tor_bridges_invalid": "No funciona ninguno de los puentes que agregaste. Vuelve a comprobarlos o añade otros.",
|
||||
"settings_saved": "Ajustes guardados en {}",
|
||||
"give_this_url_receive": "Dele esta dirección al remitente:",
|
||||
"give_this_url_receive_stealth": "Entrega esta dirección y HidServAuth al remitente:",
|
||||
@ -143,7 +143,7 @@
|
||||
"gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy": "Usar transportes conectables obfs4 incorporados (requiere obfs4proxy)",
|
||||
"gui_settings_tor_bridges_meek_lite_azure_radio_option": "Usar transportes conectables incorporados meek_lite (Azure)",
|
||||
"gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy": "Usar transportes conectables meek_lite (Azure) incorporados (requiere obfs4proxy)",
|
||||
"gui_settings_meek_lite_expensive_warning": "Advertencia: Los puentes meek_lite son muy costosos de correr para el Proyecto Tor.<br><br>Utilízalos solo si no puedes conectarte a Tor directamente, a través de transportes obfs4 u otros puentes normales.",
|
||||
"gui_settings_meek_lite_expensive_warning": "Advertencia: Los puentes meek-azure son muy costosos de mantener para el Proyecto Tor.<br><br>Utilízalos solo si no puedes conectarte a Tor directamente, a través de transportes obfs4 u otros puentes normales.",
|
||||
"gui_settings_tor_bridges_custom_radio_option": "Usar puentes personalizados",
|
||||
"gui_settings_tor_bridges_custom_label": "Puedes obtener puentes en <a href=\"https://bridges.torproject.org/options\">https://bridges.torproject.org</a>",
|
||||
"gui_settings_button_save": "Guardar",
|
||||
@ -177,7 +177,7 @@
|
||||
"gui_upload_finished": "Subido {}",
|
||||
"gui_download_in_progress": "Descarga iniciada {}",
|
||||
"gui_open_folder_error_nautilus": "No se puede abrir la carpeta porque nautilus no está disponible. El archivo está aquí: {}",
|
||||
"gui_settings_language_label": "Idioma preferido",
|
||||
"gui_settings_language_label": "Idioma",
|
||||
"gui_settings_language_changed_notice": "Reinicia OnionShare para que se aplique el idioma nuevo.",
|
||||
"gui_upload_finished_range": "Cargado {} a {}",
|
||||
"timeout_upload_still_running": "Esperando a que se complete la subida",
|
||||
@ -265,7 +265,7 @@
|
||||
"gui_new_tab_tooltip": "Abrir una pestaña nueva",
|
||||
"gui_new_tab": "Nueva pestaña",
|
||||
"gui_new_tab_share_description": "Elige los archivos de tu ordenador para enviarlos a otra persona. La persona o personas a las que quieras enviar los archivos tendrán que usar el Tor Browser para descargarlos de ti.",
|
||||
"mode_settings_website_disable_csp_checkbox": "No enviar encabezado de Política de Seguridad de Contenido (permite que tu sitio web utilice recursos de terceros)",
|
||||
"mode_settings_website_disable_csp_checkbox": "No enviar encabezado predeterminado de Política de Seguridad de Contenido (permite que tu sitio web utilice recursos de terceros)",
|
||||
"mode_settings_receive_data_dir_browse_button": "Navegar",
|
||||
"mode_settings_receive_data_dir_label": "Guardar archivos en",
|
||||
"mode_settings_share_autostop_sharing_checkbox": "Dejar de compartir después de haber enviado archivos (desmarcar para permitir la descarga de archivos individuales)",
|
||||
@ -321,5 +321,30 @@
|
||||
"gui_settings_theme_dark": "Oscuro",
|
||||
"gui_settings_theme_light": "Claro",
|
||||
"gui_settings_theme_auto": "Automático",
|
||||
"gui_url_instructions_public_mode": "Envíe la siguiente dirección de OnionShare:"
|
||||
"gui_url_instructions_public_mode": "Envíe la siguiente dirección de OnionShare:",
|
||||
"gui_dragdrop_sandbox_flatpak": "Para hacer que la zona de prueba de Flatpak sea más segura, arrastrar y colocar no es soportado. En vez, usa los botones Agregar Archivos y Agregar Carpeta para navegar entre archivos.",
|
||||
"gui_tor_settings_window_title": "Configuraciones de Tor",
|
||||
"gui_settings_controller_extras_label": "Configuraciones de Tor",
|
||||
"gui_settings_tor_bridges_label": "Los puentes te ayudan a acceder a la red Tor en lugares donde Tor está bloqueado. Dependiendo de dónde estés, un puente podría funcionar mejor que otro.",
|
||||
"gui_settings_bridge_use_checkbox": "Usar un puente",
|
||||
"gui_settings_bridge_radio_builtin": "Seleccionar un puente incorporado",
|
||||
"gui_settings_bridge_none_radio_option": "No usar un puente",
|
||||
"gui_settings_bridge_moat_radio_option": "Solicita un puente desde torproject.org",
|
||||
"gui_settings_bridge_moat_button": "Solicitar un Nuevo Puente",
|
||||
"gui_settings_bridge_custom_radio_option": "Provee un puente del que te enteraste a través de una fuente confiable",
|
||||
"gui_settings_bridge_custom_placeholder": "tipea dirección:puerto (una por línea)",
|
||||
"gui_settings_moat_bridges_invalid": "Aún no has solicitado un puente desde torproject.org.",
|
||||
"gui_settings_stop_active_tabs_label": "Estos son servicios ejecutándose en algunas de tus pestañas.\nDebes detenerlos a todos para cambiar tus configuraciones de Tor.",
|
||||
"gui_settings_version_label": "Estás usando OnionShare {}",
|
||||
"gui_settings_help_label": "¿Necesitas ayuda? Mira <a href='https://docs.onionshare.org'>docs.onionshare.org</a>",
|
||||
"mode_settings_website_custom_csp_checkbox": "Enviar un encabezado personaizado de Política de Seguridad de Contenido",
|
||||
"moat_contact_label": "Contactando BridgeDB...",
|
||||
"moat_captcha_label": "Resuelve el CAPTCHA para solicitar un puente.",
|
||||
"moat_captcha_placeholder": "Ingresa los caracteres en la imagen",
|
||||
"moat_captcha_submit": "Enviar",
|
||||
"moat_captcha_reload": "Recargar",
|
||||
"moat_bridgedb_error": "Error contactando BridgeDB.",
|
||||
"moat_captcha_error": "La solución no es correcta. Por favor, inténtalo de nuevo.",
|
||||
"moat_solution_empty_error": "Debes ingresar los caracteres en la imagen",
|
||||
"mode_tor_not_connected_label": "OnionShare no está conectado a la red Tor"
|
||||
}
|