WIP: Adding vanguard...

pull/67/head
Christophe Mehay 4 years ago
parent af0cbea44f
commit 0334d7eb6b

@ -4,11 +4,13 @@ ARG tor_version
ENV HOME /var/lib/tor
ENV POETRY_VIRTUALENVS_CREATE=false
RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils libffi-dev zlib-dev && \
mkdir -p /usr/local/src/ && \
RUN apk add --no-cache git bind-tools libevent-dev openssl-dev gnupg gcc make automake ca-certificates autoconf musl-dev coreutils libffi-dev zlib-dev && \
mkdir -p /usr/local/src/ /var/lib/tor/ && \
gpg --batch --auto-key-locate nodefault,wkd --recv-keys FE43009C4607B1FB && \
git clone https://git.torproject.org/tor.git /usr/local/src/tor && \
cd /usr/local/src/tor && \
git checkout tor-$tor_version && \
git verify-tag tor-$tor_version && \
./autogen.sh && \
./configure \
--disable-asciidoc \
@ -18,7 +20,7 @@ RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-cer
cd .. && \
rm -rf tor && \
pip3 install --upgrade pip poetry && \
apk del git libevent-dev openssl-dev make automake autoconf musl-dev coreutils libffi-dev && \
apk del git libevent-dev openssl-dev gnupg make automake autoconf musl-dev coreutils libffi-dev && \
apk add --no-cache libevent openssl
RUN mkdir -p /etc/tor/
@ -39,8 +41,11 @@ RUN mkdir -p ${HOME}/.tor && \
COPY assets/entrypoint-config.yml /
COPY assets/torrc /var/local/tor/torrc.tpl
COPY assets/vanguards.conf.tpl /var/local/tor/vanguards.conf.tpl
ENV VANGUARDS_CONFIG /etc/tor/vanguards.conf
RUN apk add socat
VOLUME ["/var/lib/tor/hidden_service/"]

@ -40,3 +40,9 @@ shell-v3: build
run-v3-latest:
docker-compose -f docker-compose.v3.latest.yml up --force-recreate
run-vanguards: build
docker-compose -f docker-compose.vanguards.yml up --force-recreate
run-vanguards-network: build
docker-compose -f docker-compose.vanguards-network.yml up --force-recreate

@ -181,6 +181,37 @@ If you need to use the legacy version, please checkout the `legacy` branch or pu
This containner uses [`pytor`](https://github.com/cmehay/pytor) to mannages tor cryptography, generate keys and compute onion urls.
## Control port
Use these environment variables to enable control port
* `TOR_CONTROL_PORT`: enable and set control port binding (`ip`, `ip:port` or `unix:/path/to/socket.sock`) (default port is 9051)
* `TOR_CONTROL_PASSWORD`: set control port password (in clear, not hashed)
* `TOR_DATA_DIRECTORY`: set data directory (default `/run/tor/data`)
## Vanguards
For critical hidden services, it's possible to increase security with [`Vanguards`](https://github.com/mikeperry-tor/vanguards) tool.
#### Settings
It's not possible yet to custom all the settings using environment variable, but it's possible to mount configuration file to `/etc/tor/vanguards.conf` to custom `vanguards` settings.
### Run in the same container
Check out [`docker-compose.vanguards.yml`](docker-compose.vanguads.yml) for example.
Add environment variable `TOR_ENABLE_VANGUARDS` to `true` to start `vanguards` daemon beside `tor` process. `Vanguards` logs will be displayed to stdout using `pyentrypoint` logging, if you need raw output, set `ENTRYPOINT_RAW` to `true` in environment.
In this mode, if `vanguards` exits, sigint is sent to `tor` process to terminate it. If you want to disable this behavior, set `VANGUARD_KILL_TOR_ON_EXIT` to `false` in environment.
### Run in separate containers
Check out[`docker-compose.vanguards-network.yml`](docker-compose.vanguards-network.yml) for an example of increased security setup using docker networks.
#### settings
Use the same environment variable as `tor` to configure `vangards` (see upper).
* `TOR_CONTROL_PORT`
* `TOR_CONTROL_PASSWORD`
# Legacy deprecated doc

@ -1,4 +1,6 @@
command: tor
commands:
- tor
- vanguards
user: tor
group: tor
@ -9,14 +11,29 @@ secret_env:
- '*_SERVICE_NAME'
- '*_TOR_SERVICE_*'
- 'TOR_SOCKS_PORT'
- TOR_CONTROL_PASSWORD
config_files:
- vanguards:
- /var/local/tor/vanguards.conf.tpl: /etc/tor/vanguards.conf
pre_conf_commands:
- onions --setup-hosts
- tor:
- onions --setup-hosts
post_conf_commands:
- chmod -R 700 $HOME
- chown -R tor:tor $HOME
- tor:
- mkdir -p /run/tor
- chmod -R 700 $HOME /run/tor
- chown -R tor:tor $HOME /run/tor
post_run_commands:
- tor:
- onions --run-vanguards
set_environment:
- vanguards:
- TOR_CONTROL_PORT: onions --resolve-control-port
reload:
files:
- /etc/tor/torrc

@ -1,30 +1,50 @@
{% for service_group in services %}
{% for service_group in onion.services %}
HiddenServiceDir {{service_group.hidden_service_dir}}
{% if service_group.version == 3 %}
{% if service_group.version == 3 %}
HiddenServiceVersion 3
{% endif %}
{% for service in service_group.services %}
{% for port in service.ports %}
{% if port.is_socket %}
{% endif %}
{% for service in service_group.services %}
{% for port in service.ports %}
{% if port.is_socket %}
HiddenServicePort {{port.port_from}} {{port.dest}}
{% endif %}
{% if not port.is_socket %}
{% endif %}
{% if not port.is_socket %}
HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% if 'RELAY' in env %}
ORPort 9001
{% endif %}
DataDirectory {{ onion.data_directory }}
{% if 'TOR_SOCKS_PORT' in env %}
SocksPort {{env['TOR_SOCKS_PORT']}}
{% else %}
SocksPort 0
{% endif %}
{% if envtobool('TOR_EXIT_RELAY', False) %}
ExitRelay 1
{% else %}
ExitRelay 0
{% endif %}
{% if onion.enable_control_port %}
{% if onion.control_socket %}
ControlPort unix:{{onion.control_socket}}
{% endif %}
{% if not onion.control_socket %}
{% if onion.control_ip_binding.version() == 4 %}
ControlPort {{onion.control_ip_binding}}:{{ onion.control_port }}
{% endif %}
{% if onion.control_ip_binding.version() == 6 %}
ControlPort [{{onion.control_ip_binding}}]:{{ onion.control_port }}
{% endif %}
{% endif %}
{% if onion.control_hashed_password %}
HashedControlPassword {{ onion.control_hashed_password }}
{% endif %}
{% endif %}
{% if 'TOR_EXTRA_OPTIONS' in env %}
{{env['TOR_EXTRA_OPTIONS']}}
{% endif %}

@ -0,0 +1,137 @@
## Example vanguards configuration file
#
# The values in this file are the defaults. You do not need to specify
# options in your config file unless you wish to change the defaults.
## Global options
[Global]
{% if env.get('TOR_CONTROL_PORT', '').startswith('unix:') %}
{% set _, unix_path = env['TOR_CONTROL_PORT'].split(':', 1) %}
{% elif ':' in env.get('TOR_CONTROL_PORT', '') %}
{% set host, port = env['TOR_CONTROL_PORT'].split(':', 1) %}
{% else %}
{% set host = env.get('TOR_CONTROL_PORT') %}
{% endif %}
# IP address that the Tor control port is listening on:
control_ip = {{ host or '' }}
# TCP port the control port is listening on:
control_port = {{ port or 9051 }}
# If set, use this filesystem control socket instead of IP+Port:
control_socket = {{ unix_path or '' }}
# If set, use this as the control port password:
control_pass = {{ env.get('TOR_CONTROL_PASSWORD', '') }}
# Enable/disable active vanguard update of layer2 and layer3 guards
enable_vanguards = True
# Enable/disable the bandwidth side channel detection checks:
enable_bandguards = True
# Enable/disable circuit build timeout analysis (informational only):
enable_cbtverify = True
# Enable/disable checks on Rendezvous Point overuse attacks:
enable_rendguard = True
# Close circuits upon suspected attack conditions:
close_circuits = True
# If True, we write (or update/rotate) layer2 and layer3 vanguards in torrc,
# then exit. This option disables the bandguards and rendguard defenses.
one_shot_vanguards = False
# The current loglevel:
loglevel = NOTICE
# If specified, log to this file instead of stdout:
logfile =
# Name of state file (with absolute path, or relative to current directory):
state_file = {{ env.get('VANGUARDS_STATE_FILE', '/run/tor/data/vanguards.state') }}
## Vanguards: layer1, layer2, and layer3 rotation params.
[Vanguards]
# How long to keep our layer1 guard (0 means use Tor default):
layer1_lifetime_days = 0
# The maximum amount of time to keep a layer2 guard:
max_layer2_lifetime_hours = 1080
# The maximum amount of time to keep a layer3 guard:
max_layer3_lifetime_hours = 48
# The minimum amount of time to keep a layer2 guard:
min_layer2_lifetime_hours = 24
# The minimum amount of time to keep a layer3 guard:
min_layer3_lifetime_hours = 1
# The number of layer1 guards:
num_layer1_guards = 2
# The number of layer2 guards:
num_layer2_guards = 3
# The number of layer3 guards:
num_layer3_guards = 8
## Bandguards: Mechanisms to detect + mitigate bandwidth side channel attacks.
[Bandguards]
# Maximum number of hours to allow any circuit to remain open
# (set to 0 to disable):
circ_max_age_hours = 24
# Maximum amount of kilobytes that can be present in a hidden service
# descriptor before we close the circuit (set to 0 to disable):
circ_max_hsdesc_kilobytes = 30
# Total maximum megabytes on any circuit before we close it. Note that
# while HTTP GET can resume if this limit is hit, HTTP POST will not.
# This means that applications that require large data submission (eg
# SecureDrop or onionshare) should set this much higher
# (or set to 0 to disable):
circ_max_megabytes = 0
# Warn if we can't build or use circuits for this many seconds.
circ_max_disconnected_secs = 30
# Warn if we are disconnected from the Tor network for this many seconds.
conn_max_disconnected_secs = 15
## Rendguard: Monitors service-side Rendezvous Points to detect misuse/attack
[Rendguard]
# No relay should show up as a Rendezvous Point more often than this ratio
# multiplied by its bandwidth weight:
rend_use_max_use_to_bw_ratio = 5.0
# What is percent of the network weight is not in the consensus right now?
# Put another way, the max number of rend requests from relays not in the
# consensus is rend_use_max_use_to_bw_ratio times this churn rate.
rend_use_max_consensus_weight_churn = 1.0
# Close circuits where the Rendezvous Point appears too often. Note that an
# adversary can deliberately cause RP overuse in order to impact availability.
# If this is a concern, either set this to false, or raise the ratio
# parameter above.
rend_use_close_circuits_on_overuse = True
# Total number of circuits we need before we begin enforcing rendezvous point
# ratio limits:
rend_use_global_start_count = 1000
# Number of times a relay must be seen as a Rendezvous Point before applying
# ratio limits:
rend_use_relay_start_count = 100
# Divide all relay counts by two once the total circuit count hits this many:
rend_use_scale_at_count = 20000

@ -0,0 +1,99 @@
# Run secure vanguards using network
version: "3.1"
services:
# Tor container
tor:
image: goldy/tor-hidden-service:$CUR_TAG
environment:
# Enable control port with ip binding (see networks configuration bellow)
# Using network interface instead of 0.0.0.0 help to protect control port from hidden services.
TOR_CONTROL_PORT: 127.16.111.10
# Set controle port password (optionnal)
TOR_CONTROL_PASSWORD: something_secret
HELLO_TOR_SERVICE_HOSTS: '80:hello:80'
HELLO_TOR_SERVICE_VERSION: '3'
# Keep keys in volumes
volumes:
# Keep keys in volumes
- tor-keys:/var/lib/tor/hidden_service/
- tor-data:/run/tor/data
# Set secret for key, use the same name as the service
secrets:
- source: hello
target: hello
mode: 0400
networks:
hidden_services:
ipv4_address: 172.16.222.10
tor_control:
# Set an ip address for tor_control network to bind for the good network
ipv4_address: 172.16.111.10
# Vanguards container
vanguards:
depends_on:
- tor
# Use the same image
image: goldy/tor-hidden-service:$CUR_TAG
# Run vanguards
command: vanguards
environment:
# Set tor hostname (or ip:port or unix:/path/to/socket.sock)
TOR_CONTROL_PORT: tor
# set password if needed
TOR_CONTROL_PASSWORD: something_secret
# Vanguards is assigned to tor_control network
networks:
- tor_control
# Sharing tor-data volume with tor container
volumes:
- tor-data:/run/tor/data
# Hidden service container
hello:
image: tutum/hello-world
hostname: hello
depends_on:
- tor
# this hidden service is assigned to hidden_services network
networks:
- hidden_services
volumes:
tor-keys:
driver: local
tor-data:
driver: local
secrets:
hello:
file: ./private_key_bar_v3
networks:
# This network is used for hidden services
hidden_services:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.222.0/24
# This network is used for vagrands to get access to tor
tor_control:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.111.0/24

@ -0,0 +1,36 @@
# Secure vangard in the same container
version: "3.1"
services:
tor:
image: goldy/tor-hidden-service:$CUR_TAG
environment:
TOR_ENABLE_VANGUARDS: 'true'
HELLO_TOR_SERVICE_HOSTS: '80:hello:80'
HELLO_TOR_SERVICE_VERSION: '3'
# Keep keys in volumes
volumes:
- tor-keys:/var/lib/tor/hidden_service/
# Set secret for key, use the same name as the service
secrets:
- source: hello
target: hello
mode: 0400
hello:
image: tutum/hello-world
hostname: hello
depends_on:
- tor
volumes:
tor-keys:
driver: local
secrets:
hello:
file: ./private_key_bar_v3

@ -2,14 +2,18 @@
import argparse
import logging
import os
import socket
import subprocess
import sys
from base64 import b64decode
from json import dumps
from re import match
from IPy import IP
from jinja2 import Environment
from jinja2 import FileSystemLoader
from pyentrypoint import DockerLinks
from pyentrypoint.config import envtobool
from .Service import Service
from .Service import ServicesGroup
@ -18,8 +22,17 @@ from .Service import ServicesGroup
class Setup(object):
hidden_service_dir = "/var/lib/tor/hidden_service/"
data_directory = "/run/tor/data"
torrc = '/etc/tor/torrc'
torrc_template = '/var/local/tor/torrc.tpl'
enable_control_port = False
control_port = 9051
control_ip_binding = IP('0.0.0.0')
control_hashed_password = None
control_socket = 'unix:/run/tor/tor_control.sock'
enable_vanguards = False
vanguards_template = '/var/local/tor/vanguards.conf.tpl'
vanguards_conf = '/etc/tor/vanguards.conf'
def _add_host(self, host):
if host not in self.setup:
@ -42,6 +55,58 @@ class Setup(object):
if port not in self.setup[host]['ports'][host]:
self.setup[host]['ports'][host].append(port)
def _hash_control_port_password(self, password):
self.control_hashed_password = subprocess.check_output([
'tor', '--quiet', '--hash-password', password
]).decode()
def _parse_control_port_variable(self, check_ip=True):
control_port = os.environ['TOR_CONTROL_PORT']
try:
if control_port.startswith('unix:'):
_, self.control_socket = control_port.split(':')
return
self.control_socket = None
if ':' in control_port:
host, port = control_port.split(':')
self.control_ip_binding = IP(host) if check_ip else host
self.control_port = int(port)
return
self.control_ip_binding = (
IP(control_port) if check_ip else control_port
)
except BaseException as e:
logging.error('TOR_CONTROL_PORT environment variable error')
logging.exception(e)
def _setup_control_port(self):
if 'TOR_CONTROL_PORT' not in os.environ:
return
self.enable_control_port = True
self._parse_control_port_variable()
if os.environ.get('TOR_CONTROL_PASSWORD'):
self._hash_control_port_password(os.environ[
'TOR_CONTROL_PASSWORD'
])
if envtobool('TOR_DATA_DIRECTORY', False):
self.data_directory = os.environ['TOR_DATA_DIRECTORY']
def _setup_vanguards(self):
if not envtobool('TOR_ENABLE_VANGUARDS', False):
return
self.enable_control_port = True
self.enable_vanguards = True
os.environ['TOR_CONTROL_PORT'] = self.control_socket
self.kill_tor_on_vanguard_exit = envtobool(
'VANGUARD_KILL_TOR_ON_EXIT',
True
)
self.vanguards_state_file = os.path.join(
self.data_directory,
'vanguards.state'
)
def _get_key(self, host, key):
self._add_host(host)
assert len(key) > 800
@ -213,6 +278,8 @@ class Setup(object):
def apply_conf(self):
self._write_keys()
self._write_torrc()
if self.enable_vanguards:
self._write_vanguards_conf()
def _write_keys(self):
for service in self.services:
@ -222,17 +289,65 @@ class Setup(object):
env = Environment(loader=FileSystemLoader('/'))
temp = env.get_template(self.torrc_template)
with open(self.torrc, mode='w') as f:
f.write(temp.render(services=self.services,
f.write(temp.render(onion=self,
env=os.environ,
envtobool=envtobool,
type=type,
int=int))
def _write_vanguards_conf(self):
env = Environment(loader=FileSystemLoader('/'))
temp = env.get_template(self.vanguards_template)
with open(self.vanguards_conf, mode='w') as f:
f.write(temp.render(env=os.environ,
envtobool=envtobool))
def run_vanguards(self):
self._setup_vanguards()
if not self.enable_vanguards:
return
logging.info('Vanguard enabled, starting...')
if not self.kill_tor_on_vanguard_exit:
os.execvp('vanguards', ['vanguards'])
try:
subprocess.check_call('vanguards')
except subprocess.CalledProcessError as e:
logging.error(str(e))
finally:
logging.error('Vanguards has exited, killing tor...')
os.kill(1, 2)
def resolve_control_hostname(self):
try:
addr = socket.getaddrinfo(self.control_ip_binding,
None,
socket.AF_INET,
socket.SOCK_STREAM,
socket.IPPROTO_TCP)
except socket.gaierror:
raise
return IP(addr[0][4][0])
def resolve_control_port(self):
if 'TOR_CONTROL_PORT' not in os.environ:
return
self._parse_control_port_variable(check_ip=False)
if self.control_socket:
print(os.environ['TOR_CONTROL_PORT'])
try:
ip = IP(self.control_ip_binding)
except ValueError:
ip = self.resolve_control_hostname()
print(f"{ip}:{self.control_port}")
def setup_hosts(self):
self.setup = {}
self._get_setup_from_env()
self._get_setup_from_links()
self._load_keys_in_services()
self.check_services()
self._setup_vanguards()
self._setup_control_port()
self.apply_conf()
def check_services(self):
@ -272,6 +387,8 @@ class Onions(Setup):
self.services = []
if 'HIDDEN_SERVICE_DIR' in os.environ:
self.hidden_service_dir = os.environ['HIDDEN_SERVICE_DIR']
if os.environ.get('TOR_DATA_DIRECTORY'):
self.data_directory = os.environ['TOR_DATA_DIRECTORY']
def torrc_parser(self):
@ -357,6 +474,13 @@ def main():
parser.add_argument('--setup-hosts', dest='setup', action='store_true',
help='Setup hosts')
parser.add_argument('--run-vanguards', dest='vanguards',
action='store_true',
help='Run Vanguards in tor container')
parser.add_argument('--resolve-control-port', dest='resolve_control_port',
action='store_true',
help='Resolve ip from host if needed')
args = parser.parse_args()
logging.getLogger().setLevel(logging.WARNING)
try:
@ -365,6 +489,12 @@ def main():
onions.setup_hosts()
else:
onions.torrc_parser()
if args.vanguards:
onions.run_vanguards()
return
if args.resolve_control_port:
onions.resolve_control_port()
return
except BaseException as e:
logging.exception(e)
error_msg = str(e)

@ -54,7 +54,7 @@ class ServicesGroup(object):
version = int(version)
if version not in self.onion_map:
raise Exception(
'Url version {version} is not supported'.format(version)
f'Url version {version} is not supported'
)
self.version = version
self._onion = self.onion_map[version]()

222
poetry.lock generated

@ -4,7 +4,7 @@ description = "A small Python module for determining appropriate platform-specif
name = "appdirs"
optional = false
python-versions = "*"
version = "1.4.3"
version = "1.4.4"
[[package]]
category = "dev"
@ -52,10 +52,11 @@ description = "A tool that automatically formats Python code to conform to the P
name = "autopep8"
optional = false
python-versions = "*"
version = "1.5.2"
version = "1.5.3"
[package.dependencies]
pycodestyle = ">=2.5.0"
pycodestyle = ">=2.6.0"
toml = "*"
[[package]]
category = "dev"
@ -165,7 +166,7 @@ description = "File identification library for Python"
name = "identify"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "1.4.15"
version = "1.4.19"
[package.extras]
license = ["editdistance"]
@ -176,14 +177,30 @@ description = "Read metadata from Python packages"
name = "importlib-metadata"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
version = "1.6.0"
version = "1.6.1"
[package.dependencies]
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "rst.linker"]
testing = ["packaging", "importlib-resources"]
testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
[[package]]
category = "main"
description = "IPv4/IPv6 manipulation library"
name = "ipaddress"
optional = false
python-versions = "*"
version = "1.0.23"
[[package]]
category = "main"
description = "Class and tools for handling of IPv4 and IPv6 addresses and networks"
name = "ipy"
optional = false
python-versions = "*"
version = "1.00"
[[package]]
category = "dev"
@ -258,7 +275,7 @@ description = "More routines for operating on iterables, beyond itertools"
name = "more-itertools"
optional = false
python-versions = ">=3.5"
version = "8.2.0"
version = "8.3.0"
[[package]]
category = "dev"
@ -266,7 +283,7 @@ description = "Node.js virtual environment builder"
name = "nodeenv"
optional = false
python-versions = "*"
version = "1.3.5"
version = "1.4.0"
[[package]]
category = "dev"
@ -274,7 +291,7 @@ description = "Core utilities for Python packages"
name = "packaging"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "20.3"
version = "20.4"
[package.dependencies]
pyparsing = ">=2.0.2"
@ -329,7 +346,7 @@ description = "A framework for managing and maintaining multi-language pre-commi
name = "pre-commit"
optional = false
python-versions = ">=3.6.1"
version = "2.3.0"
version = "2.4.0"
[package.dependencies]
cfgv = ">=2.0.0"
@ -337,7 +354,7 @@ identify = ">=1.0.0"
nodeenv = ">=0.11.1"
pyyaml = ">=5.1"
toml = "*"
virtualenv = ">=15.2"
virtualenv = ">=20.0.8"
[package.dependencies.importlib-metadata]
python = "<3.8"
@ -385,7 +402,7 @@ description = "Python style guide checker"
name = "pycodestyle"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.5.0"
version = "2.6.0"
[[package]]
category = "dev"
@ -408,15 +425,15 @@ category = "main"
description = "pyentrypoint manages entrypoints in Docker containers."
name = "pyentrypoint"
optional = false
python-versions = "*"
version = "0.5.2"
python-versions = ">=3.6.1,<4.0.0"
version = "0.7.3"
[package.dependencies]
Jinja2 = ">=2.8"
PyYAML = ">=3.11"
colorlog = ">=2.6.1"
six = ">=1.10.0"
watchdog = ">=0.8.3"
colorlog = ">=4.1,<5.0"
jinja2 = ">=2.11,<3.0"
pyyaml = ">=5.3,<6.0"
six = ">=1.14,<2.0"
watchdog = ">=0.10,<0.11"
[[package]]
category = "dev"
@ -463,7 +480,7 @@ description = "pytest: simple powerful testing with Python"
name = "pytest"
optional = false
python-versions = ">=3.5"
version = "5.4.2"
version = "5.4.3"
[package.dependencies]
atomicwrites = ">=1.0"
@ -508,7 +525,7 @@ description = "Alternative regular expression module, to replace re."
name = "regex"
optional = false
python-versions = "*"
version = "2020.5.7"
version = "2020.6.7"
[[package]]
category = "main"
@ -516,7 +533,15 @@ description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.14.0"
version = "1.15.0"
[[package]]
category = "main"
description = "Stem is a Python controller library that allows applications to interact with Tor (https://www.torproject.org/)."
name = "stem"
optional = false
python-versions = "*"
version = "1.8.0"
[[package]]
category = "dev"
@ -524,7 +549,7 @@ description = "Python Library for Tom's Obvious, Minimal Language"
name = "toml"
optional = false
python-versions = "*"
version = "0.10.0"
version = "0.10.1"
[[package]]
category = "dev"
@ -532,15 +557,15 @@ description = "tox is a generic virtualenv management and test command line tool
name = "tox"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
version = "3.15.0"
version = "3.15.2"
[package.dependencies]
colorama = ">=0.4.1"
filelock = ">=3.0.0,<4"
filelock = ">=3.0.0"
packaging = ">=14"
pluggy = ">=0.12.0,<1"
py = ">=1.4.17,<2"
six = ">=1.14.0,<2"
pluggy = ">=0.12.0"
py = ">=1.4.17"
six = ">=1.14.0"
toml = ">=0.9.4"
virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7"
@ -549,8 +574,8 @@ python = "<3.8"
version = ">=0.12,<2"
[package.extras]
docs = ["sphinx (>=2.0.0,<3)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"]
testing = ["freezegun (>=0.3.11,<1)", "pathlib2 (>=2.3.3,<3)", "pytest (>=4.0.0,<6)", "pytest-cov (>=2.5.1,<3)", "pytest-mock (>=1.10.0,<2)", "pytest-xdist (>=1.22.2,<2)", "pytest-randomly (>=1.0.0,<4)", "flaky (>=3.4.0,<4)", "psutil (>=5.6.1,<6)"]
docs = ["sphinx (>=2.0.0)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"]
testing = ["freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-xdist (>=1.22.2)", "pytest-randomly (>=1.0.0)", "flaky (>=3.4.0)", "psutil (>=5.6.1)"]
[[package]]
category = "dev"
@ -560,13 +585,26 @@ optional = false
python-versions = "*"
version = "1.4.1"
[[package]]
category = "main"
description = "Vanguards help guard you from getting vanned..."
name = "vanguards"
optional = false
python-versions = "*"
version = "0.3.1"
[package.dependencies]
ipaddress = ">=1.0.17"
setuptools = "*"
stem = ">=1.7.0"
[[package]]
category = "dev"
description = "Virtual Python Environment builder"
name = "virtualenv"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "20.0.20"
version = "20.0.21"
[package.dependencies]
appdirs = ">=1.4.3,<2"
@ -598,11 +636,11 @@ watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"]
[[package]]
category = "dev"
description = "Measures number of Terminal column cells of wide-character codes"
description = "Measures the displayed width of unicode strings in a terminal"
name = "wcwidth"
optional = false
python-versions = "*"
version = "0.1.9"
version = "0.2.3"
[[package]]
category = "dev"
@ -625,13 +663,13 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["jaraco.itertools", "func-timeout"]
[metadata]
content-hash = "6e1eec0c17109c00a24dd51d3bb7a6a47fe528bd4ef6a0da0679fd513dbf8adc"
content-hash = "097415d9c723c691882ffa440af8e248746a278f758745d2ce75ffab1bdac90d"
python-versions = ">= 3.7, < 3.8"
[metadata.files]
appdirs = [
{file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"},
{file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"},
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
]
astroid = [
{file = "astroid-2.4.1-py3-none-any.whl", hash = "sha256:d8506842a3faf734b81599c8b98dcc423de863adcc1999248480b18bd31a0f38"},
@ -646,7 +684,7 @@ attrs = [
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
]
autopep8 = [
{file = "autopep8-1.5.2.tar.gz", hash = "sha256:152fd8fe47d02082be86e05001ec23d6f420086db56b17fc883f3f965fb34954"},
{file = "autopep8-1.5.3.tar.gz", hash = "sha256:60fd8c4341bab59963dafd5d2a566e94f547e660b9b396f772afe67d8481dbf0"},
]
black = [
{file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"},
@ -727,12 +765,19 @@ filelock = [
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
]
identify = [
{file = "identify-1.4.15-py2.py3-none-any.whl", hash = "sha256:88ed90632023e52a6495749c6732e61e08ec9f4f04e95484a5c37b9caf40283c"},
{file = "identify-1.4.15.tar.gz", hash = "sha256:23c18d97bb50e05be1a54917ee45cc61d57cb96aedc06aabb2b02331edf0dbf0"},
{file = "identify-1.4.19-py2.py3-none-any.whl", hash = "sha256:781fd3401f5d2b17b22a8b18b493a48d5d948e3330634e82742e23f9c20234ef"},
{file = "identify-1.4.19.tar.gz", hash = "sha256:249ebc7e2066d6393d27c1b1be3b70433f824a120b1d8274d362f1eb419e3b52"},
]
importlib-metadata = [
{file = "importlib_metadata-1.6.0-py2.py3-none-any.whl", hash = "sha256:2a688cbaa90e0cc587f1df48bdc97a6eadccdcd9c35fb3f976a09e3b5016d90f"},
{file = "importlib_metadata-1.6.0.tar.gz", hash = "sha256:34513a8a0c4962bc66d35b359558fd8a5e10cd472d37aec5f66858addef32c1e"},
{file = "importlib_metadata-1.6.1-py2.py3-none-any.whl", hash = "sha256:15ec6c0fd909e893e3a08b3a7c76ecb149122fb14b7efe1199ddd4c7c57ea958"},
{file = "importlib_metadata-1.6.1.tar.gz", hash = "sha256:0505dd08068cfec00f53a74a0ad927676d7757da81b7436a6eefe4c7cf75c545"},
]
ipaddress = [
{file = "ipaddress-1.0.23-py2.py3-none-any.whl", hash = "sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc"},
{file = "ipaddress-1.0.23.tar.gz", hash = "sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2"},
]
ipy = [
{file = "IPy-1.00.tar.gz", hash = "sha256:2f2bf658a858d43868d8a4352b3889cf78c66e2ce678b300dcf518c9149ba621"},
]
isort = [
{file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"},
@ -809,15 +854,15 @@ mccabe = [
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
more-itertools = [
{file = "more-itertools-8.2.0.tar.gz", hash = "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507"},
{file = "more_itertools-8.2.0-py3-none-any.whl", hash = "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c"},
{file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"},
{file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"},
]
nodeenv = [
{file = "nodeenv-1.3.5-py2.py3-none-any.whl", hash = "sha256:5b2438f2e42af54ca968dd1b374d14a1194848955187b0e5e4be1f73813a5212"},
{file = "nodeenv-1.4.0-py2.py3-none-any.whl", hash = "sha256:4b0b77afa3ba9b54f4b6396e60b0c83f59eaeb2d63dc3cc7a70f7f4af96c82bc"},
]
packaging = [
{file = "packaging-20.3-py2.py3-none-any.whl", hash = "sha256:82f77b9bee21c1bafbf35a84905d604d5d1223801d639cf3ed140bd651c08752"},
{file = "packaging-20.3.tar.gz", hash = "sha256:3c292b474fda1671ec57d46d739d072bfd495a4f51ad01a055121d81e952b7a3"},
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
{file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
]
parso = [
{file = "parso-0.7.0-py2.py3-none-any.whl", hash = "sha256:158c140fc04112dc45bca311633ae5033c2c2a7b732fa33d0955bad8152a8dd0"},
@ -835,8 +880,8 @@ pluggy = [
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
]
pre-commit = [
{file = "pre_commit-2.3.0-py2.py3-none-any.whl", hash = "sha256:979b53dab1af35063a483bfe13b0fcbbf1a2cf8c46b60e0a9a8d08e8269647a1"},
{file = "pre_commit-2.3.0.tar.gz", hash = "sha256:f3e85e68c6d1cbe7828d3471896f1b192cfcf1c4d83bf26e26beeb5941855257"},
{file = "pre_commit-2.4.0-py2.py3-none-any.whl", hash = "sha256:5559e09afcac7808933951ffaf4ff9aac524f31efbc3f24d021540b6c579813c"},
{file = "pre_commit-2.4.0.tar.gz", hash = "sha256:703e2e34cbe0eedb0d319eff9f7b83e2022bb5a3ab5289a6a8841441076514d0"},
]
prompt-toolkit = [
{file = "prompt_toolkit-3.0.5-py3-none-any.whl", hash = "sha256:df7e9e63aea609b1da3a65641ceaf5bc7d05e0a04de5bd45d05dbeffbabf9e04"},
@ -851,8 +896,8 @@ py = [
{file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"},
]
pycodestyle = [
{file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"},
{file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"},
{file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
{file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"},
]
pycparser = [
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
@ -893,7 +938,8 @@ pycryptodome = [
{file = "pycryptodome-3.9.4.tar.gz", hash = "sha256:a168e73879619b467072509a223282a02c8047d932a48b74fbd498f27224aa04"},
]
pyentrypoint = [
{file = "pyentrypoint-0.5.2.tar.gz", hash = "sha256:5f2f74b3d63b55a54c53a88f3e1c042b37c9e6b139150c2e1b3a5ff8f948de0b"},
{file = "pyentrypoint-0.7.3-py3-none-any.whl", hash = "sha256:aa4b3016466b398d379a974e01c363ed12618652adbe6a193ced43ed0fcefacc"},
{file = "pyentrypoint-0.7.3.tar.gz", hash = "sha256:59c02957ec82e9ca53997e66f75d0f375f1a1b39373074d790307d6a159a1e06"},
]
pyfakefs = [
{file = "pyfakefs-4.0.2-py3-none-any.whl", hash = "sha256:42cf165adc821fc9e205d3fc14033d45e0b8224e1d2fea4f67b487c6b7b3230e"},
@ -912,8 +958,8 @@ pyparsing = [
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pytest = [
{file = "pytest-5.4.2-py3-none-any.whl", hash = "sha256:95c710d0a72d91c13fae35dce195633c929c3792f54125919847fdcdf7caa0d3"},
{file = "pytest-5.4.2.tar.gz", hash = "sha256:eb2b5e935f6a019317e455b6da83dd8650ac9ffd2ee73a7b657a30873d67a698"},
{file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
{file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
]
pytor = [
{file = "pytor-0.1.5.tar.gz", hash = "sha256:ebd118a68e23ed3eee4125755ed99ccd3068f75532b8c277c204bb7a4e6e72bf"},
@ -932,40 +978,42 @@ pyyaml = [
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"},
]
regex = [
{file = "regex-2020.5.7-cp27-cp27m-win32.whl", hash = "sha256:5493a02c1882d2acaaf17be81a3b65408ff541c922bfd002535c5f148aa29f74"},
{file = "regex-2020.5.7-cp27-cp27m-win_amd64.whl", hash = "sha256:021a0ae4d2baeeb60a3014805a2096cb329bd6d9f30669b7ad0da51a9cb73349"},
{file = "regex-2020.5.7-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4df91094ced6f53e71f695c909d9bad1cca8761d96fd9f23db12245b5521136e"},
{file = "regex-2020.5.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7ce4a213a96d6c25eeae2f7d60d4dad89ac2b8134ec3e69db9bc522e2c0f9388"},
{file = "regex-2020.5.7-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b059e2476b327b9794c792c855aa05531a3f3044737e455d283c7539bd7534d"},
{file = "regex-2020.5.7-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:652ab4836cd5531d64a34403c00ada4077bb91112e8bcdae933e2eae232cf4a8"},
{file = "regex-2020.5.7-cp36-cp36m-win32.whl", hash = "sha256:1e2255ae938a36e9bd7db3b93618796d90c07e5f64dd6a6750c55f51f8b76918"},
{file = "regex-2020.5.7-cp36-cp36m-win_amd64.whl", hash = "sha256:8127ca2bf9539d6a64d03686fd9e789e8c194fc19af49b69b081f8c7e6ecb1bc"},
{file = "regex-2020.5.7-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f7f2f4226db6acd1da228adf433c5c3792858474e49d80668ea82ac87cf74a03"},
{file = "regex-2020.5.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2bc6a17a7fa8afd33c02d51b6f417fc271538990297167f68a98cae1c9e5c945"},
{file = "regex-2020.5.7-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:b7c9f65524ff06bf70c945cd8d8d1fd90853e27ccf86026af2afb4d9a63d06b1"},
{file = "regex-2020.5.7-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:fa09da4af4e5b15c0e8b4986a083f3fd159302ea115a6cc0649cd163435538b8"},
{file = "regex-2020.5.7-cp37-cp37m-win32.whl", hash = "sha256:669a8d46764a09f198f2e91fc0d5acdac8e6b620376757a04682846ae28879c4"},
{file = "regex-2020.5.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b5b5b2e95f761a88d4c93691716ce01dc55f288a153face1654f868a8034f494"},
{file = "regex-2020.5.7-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0ff50843535593ee93acab662663cb2f52af8e31c3f525f630f1dc6156247938"},
{file = "regex-2020.5.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1b17bf37c2aefc4cac8436971fe6ee52542ae4225cfc7762017f7e97a63ca998"},
{file = "regex-2020.5.7-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:04d6e948ef34d3eac133bedc0098364a9e635a7914f050edb61272d2ddae3608"},
{file = "regex-2020.5.7-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5b741ecc3ad3e463d2ba32dce512b412c319993c1bb3d999be49e6092a769fb2"},
{file = "regex-2020.5.7-cp38-cp38-win32.whl", hash = "sha256:099568b372bda492be09c4f291b398475587d49937c659824f891182df728cdf"},
{file = "regex-2020.5.7-cp38-cp38-win_amd64.whl", hash = "sha256:3ab5e41c4ed7cd4fa426c50add2892eb0f04ae4e73162155cd668257d02259dd"},
{file = "regex-2020.5.7.tar.gz", hash = "sha256:73a10404867b835f1b8a64253e4621908f0d71150eb4e97ab2e7e441b53e9451"},
{file = "regex-2020.6.7-cp27-cp27m-win32.whl", hash = "sha256:8d9bb2d90e23c51aacbc58c1a11320f49b335cd67a91986cdbebcc3e843e4de8"},
{file = "regex-2020.6.7-cp27-cp27m-win_amd64.whl", hash = "sha256:dcda6d4e1bbfc939b177c237aee41c9678eaaf71df482688f8986e8251e12345"},
{file = "regex-2020.6.7-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:af7209b2fcc79ee2b0ad4ea080d70bb748450ec4f282cc9e864861e469b1072e"},
{file = "regex-2020.6.7-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5735f26cacdb50b3d6d35ebf8fdeb504bd8b381e2d079d2d9f12ce534fc14ecd"},
{file = "regex-2020.6.7-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f6c8c3f56fef719180464855346e6e80971b86dfd9e5a0e356664b5baca53072"},
{file = "regex-2020.6.7-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:21fc17cb868c4264f0813f992f46f9ae6fc8c309d4741091de4153bd1f6a6176"},
{file = "regex-2020.6.7-cp36-cp36m-win32.whl", hash = "sha256:150125da109fccdcc8fec3b0b386b2a5d6ca7cff076f8b622486d1ca868b0c10"},
{file = "regex-2020.6.7-cp36-cp36m-win_amd64.whl", hash = "sha256:c0849b0864ff451f04c8afb5fc28e9ed592262e03debdd227cf0f53e04a55dcd"},
{file = "regex-2020.6.7-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8d1ee3796795e609ef7a3a5a35eaf4728038d986aa12c06b3fd1b92ee81911f4"},
{file = "regex-2020.6.7-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:7606dba82435429641efe4fbc580574942f89cf2b9c5c1f8bc1eab2bacbf7e8b"},
{file = "regex-2020.6.7-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6edc5c190248d3b612f2cca45448cf8ebc3621d41afcd1c5708853cbb1dbb3b3"},
{file = "regex-2020.6.7-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:2c928bc8e0c453d73dffa3193a6e37ee752ea36df0dd4601e21024d98274dfad"},
{file = "regex-2020.6.7-cp37-cp37m-win32.whl", hash = "sha256:97d414c41f19fd2362e493810caa8445c05e0a2d63a14081c972aad66284a8d2"},
{file = "regex-2020.6.7-cp37-cp37m-win_amd64.whl", hash = "sha256:9e37502817225ee99d91d8418f5119e98c380b00e772d06915690c05290f32ee"},
{file = "regex-2020.6.7-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c4ac9215650688e78dea29b46adbdafb7b85058eebe92ef6ea848e14466c915f"},
{file = "regex-2020.6.7-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:20c513893ff80bdbe4b4ce11ea2e93d49481f05b270595d82af69ffc402010a6"},
{file = "regex-2020.6.7-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:163bc0805e46acfa098dfc8c0b07f371577d505f603e48afc425ff475cdac3a5"},
{file = "regex-2020.6.7-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:2d9beca70e36f9c60d679e108c5fe49f3d4da79d13a13f91e5e759443bd954f9"},
{file = "regex-2020.6.7-cp38-cp38-win32.whl", hash = "sha256:ec0e509ed1877ff1cbc6f0864689bb60384a303502c4d72d9a635f8a4676fd3f"},
{file = "regex-2020.6.7-cp38-cp38-win_amd64.whl", hash = "sha256:dd8501b8d9ea1aba53c4bc7d47bc72933f9b4213d534cf400f16c1431f51c8ba"},
{file = "regex-2020.6.7.tar.gz", hash = "sha256:ffd4f80602490a309064cf2b203e220d581c51660e01055c64bf5da450485ee6"},
]
six = [
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
]
stem = [
{file = "stem-1.8.0.tar.gz", hash = "sha256:a0b48ea6224e95f22aa34c0bc3415f0eb4667ddeae3dfb5e32a6920c185568c2"},
]
toml = [
{file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"},
{file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"},
{file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"},
{file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"},
{file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
]
tox = [
{file = "tox-3.15.0-py2.py3-none-any.whl", hash = "sha256:8d97bfaf70053ed3db56f57377288621f1bcc7621446d301927d18df93b1c4c3"},
{file = "tox-3.15.0.tar.gz", hash = "sha256:af09c19478e8fc7ce7555b3d802ddf601b82684b874812c5857f774b8aee1b67"},
{file = "tox-3.15.2-py2.py3-none-any.whl", hash = "sha256:50a188b8e17580c1fb931f494a754e6507d4185f54fb18aca5ba3e12d2ffd55e"},
{file = "tox-3.15.2.tar.gz", hash = "sha256:c696d36cd7c6a28ada2da780400e44851b20ee19ef08cfe73344a1dcebbbe9f3"},
]
typed-ast = [
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
@ -990,16 +1038,20 @@ typed-ast = [
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
]
vanguards = [
{file = "vanguards-0.3.1-py2.py3-none-any.whl", hash = "sha256:ef3751d47263483a040486cff920841e937fdea4f892c1791191dfd8c9f20ebf"},
{file = "vanguards-0.3.1.tar.gz", hash = "sha256:04049fafd433bb747fbe27b404413ce09b441d5e0e6cc5d81debaac2192567b7"},
]
virtualenv = [
{file = "virtualenv-20.0.20-py2.py3-none-any.whl", hash = "sha256:b4c14d4d73a0c23db267095383c4276ef60e161f94fde0427f2f21a0132dde74"},
{file = "virtualenv-20.0.20.tar.gz", hash = "sha256:fd0e54dec8ac96c1c7c87daba85f0a59a7c37fe38748e154306ca21c73244637"},
{file = "virtualenv-20.0.21-py2.py3-none-any.whl", hash = "sha256:a730548b27366c5e6cbdf6f97406d861cccece2e22275e8e1a757aeff5e00c70"},
{file = "virtualenv-20.0.21.tar.gz", hash = "sha256:a116629d4e7f4d03433b8afa27f43deba09d48bc48f5ecefa4f015a178efb6cf"},
]
watchdog = [
{file = "watchdog-0.10.2.tar.gz", hash = "sha256:c560efb643faed5ef28784b2245cf8874f939569717a4a12826a173ac644456b"},
]
wcwidth = [
{file = "wcwidth-0.1.9-py2.py3-none-any.whl", hash = "sha256:cafe2186b3c009a04067022ce1dcd79cb38d8d65ee4f4791b8888d6599d1bbe1"},
{file = "wcwidth-0.1.9.tar.gz", hash = "sha256:ee73862862a156bf77ff92b09034fc4825dd3af9cf81bc5b360668d425f3c5f1"},
{file = "wcwidth-0.2.3-py2.py3-none-any.whl", hash = "sha256:980fbf4f3c196c0f329cdcd1e84c554d6a211f18e252e525a0cf4223154a41d6"},
{file = "wcwidth-0.2.3.tar.gz", hash = "sha256:edbc2b718b4db6cdf393eefe3a420183947d6aa312505ce6754516f458ff8830"},
]
wrapt = [
{file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"},

@ -26,8 +26,10 @@ onions = "onions:main"
python = ">= 3.7, < 3.8"
pytor = "^0.1.5"
Jinja2 = "^2.10"
pyentrypoint = "^0.5.2"
pyentrypoint = "^0.7.3"
importlib_metadata = "^1.6.0"
vanguards = "^0.3.1"
ipy = "^1.00"
[tool.poetry.dev-dependencies]
autopep8 = "^1.5.2"

@ -59,33 +59,53 @@ m9/hW13isA==
def get_torrc_template():
return r'''
{% for service_group in services %}
{% for service_group in onion.services %}
HiddenServiceDir {{service_group.hidden_service_dir}}
{% if service_group.version == 3 %}
{% if service_group.version == 3 %}
HiddenServiceVersion 3
{% endif %}
{% for service in service_group.services %}
{% for port in service.ports %}
{% if port.is_socket %}
{% endif %}
{% for service in service_group.services %}
{% for port in service.ports %}
{% if port.is_socket %}
HiddenServicePort {{port.port_from}} {{port.dest}}
{% endif %}
{% if not port.is_socket %}
{% endif %}
{% if not port.is_socket %}
HiddenServicePort {{port.port_from}} {{service.host}}:{{port.dest}}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% if 'RELAY' in env %}
ORPort 9001
{% endif %}
DataDirectory {{ onion.data_directory }}
{% if 'TOR_SOCKS_PORT' in env %}
SocksPort {{env['TOR_SOCKS_PORT']}}
{% else %}
SocksPort 0
{% endif %}
{% if envtobool('TOR_EXIT_RELAY', False) %}
ExitRelay 1
{% else %}
ExitRelay 0
{% endif %}
{% if onion.enable_control_port %}
{% if onion.control_socket %}
ControlPort unix:{{onion.control_socket}}
{% endif %}
{% if not onion.control_socket %}
{% if onion.control_ip_binding.version() == 4 %}
ControlPort {{onion.control_ip_binding}}:{{ onion.control_port }}
{% endif %}
{% if onion.control_ip_binding.version() == 6 %}
ControlPort [{{onion.control_ip_binding}}]:{{ onion.control_port }}
{% endif %}
{% endif %}
{% if onion.control_hashed_password %}
HashedControlPassword {{ onion.control_hashed_password }}
{% endif %}
{% endif %}
{% if 'TOR_EXTRA_OPTIONS' in env %}
{{env['TOR_EXTRA_OPTIONS']}}
{% endif %}

Loading…
Cancel
Save