From 0334d7eb6b72d6f1bb906f2336c24faacf35296c Mon Sep 17 00:00:00 2001 From: Christophe Mehay Date: Mon, 1 Jun 2020 00:57:35 +0200 Subject: [PATCH] WIP: Adding vanguard... --- Dockerfile | 11 +- Makefile | 6 + README.md | 31 ++++ assets/entrypoint-config.yml | 25 ++- assets/torrc | 52 +++++-- assets/vanguards.conf.tpl | 137 +++++++++++++++++ docker-compose.vanguards-network.yml | 99 ++++++++++++ docker-compose.vanguards.yml | 36 +++++ onions/Onions.py | 132 +++++++++++++++- onions/Service.py | 2 +- poetry.lock | 222 +++++++++++++++++---------- pyproject.toml | 4 +- tests/onions_test.py | 52 +++++-- 13 files changed, 682 insertions(+), 127 deletions(-) create mode 100644 assets/vanguards.conf.tpl create mode 100644 docker-compose.vanguards-network.yml create mode 100644 docker-compose.vanguards.yml diff --git a/Dockerfile b/Dockerfile index d277663..cd0546a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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/"] diff --git a/Makefile b/Makefile index 60f5fbd..c79da27 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index cdcb761..4148f6a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/assets/entrypoint-config.yml b/assets/entrypoint-config.yml index 3ad29ed..8ddcb1a 100644 --- a/assets/entrypoint-config.yml +++ b/assets/entrypoint-config.yml @@ -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 diff --git a/assets/torrc b/assets/torrc index be007c8..f829733 100644 --- a/assets/torrc +++ b/assets/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 %} + {% endif %} + {% endfor %} + {% 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 %} diff --git a/assets/vanguards.conf.tpl b/assets/vanguards.conf.tpl new file mode 100644 index 0000000..14edc94 --- /dev/null +++ b/assets/vanguards.conf.tpl @@ -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 diff --git a/docker-compose.vanguards-network.yml b/docker-compose.vanguards-network.yml new file mode 100644 index 0000000..1f86ab2 --- /dev/null +++ b/docker-compose.vanguards-network.yml @@ -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 diff --git a/docker-compose.vanguards.yml b/docker-compose.vanguards.yml new file mode 100644 index 0000000..f45c60a --- /dev/null +++ b/docker-compose.vanguards.yml @@ -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 diff --git a/onions/Onions.py b/onions/Onions.py index 2a36d40..17c77bf 100644 --- a/onions/Onions.py +++ b/onions/Onions.py @@ -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) diff --git a/onions/Service.py b/onions/Service.py index af04d74..fa4fdf0 100644 --- a/onions/Service.py +++ b/onions/Service.py @@ -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]() diff --git a/poetry.lock b/poetry.lock index f80c4f2..3932972 100644 --- a/poetry.lock +++ b/poetry.lock @@ -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"}, diff --git a/pyproject.toml b/pyproject.toml index d416d34..1a0d8b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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" diff --git a/tests/onions_test.py b/tests/onions_test.py index 1573043..1936afc 100644 --- a/tests/onions_test.py +++ b/tests/onions_test.py @@ -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 %} + {% endif %} + {% endfor %} + {% 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 %}