mirror of
https://github.com/cmehay/docker-tor-hidden-service.git
synced 2025-04-19 13:29:11 +00:00
WIP: Adding vanguard...
This commit is contained in:
parent
af0cbea44f
commit
0334d7eb6b
13 changed files with 682 additions and 127 deletions
11
Dockerfile
11
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/"]
|
||||
|
||||
|
|
6
Makefile
6
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
|
||||
|
|
31
README.md
31
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
52
assets/torrc
52
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 %}
|
||||
|
|
137
assets/vanguards.conf.tpl
Normal file
137
assets/vanguards.conf.tpl
Normal file
|
@ -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
|
99
docker-compose.vanguards-network.yml
Normal file
99
docker-compose.vanguards-network.yml
Normal file
|
@ -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
|
36
docker-compose.vanguards.yml
Normal file
36
docker-compose.vanguards.yml
Normal file
|
@ -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
|
132
onions/Onions.py
132
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)
|
||||
|
|
|
@ -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
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 %}
|
||||
{% 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 %}
|
||||
|
|
Loading…
Add table
Reference in a new issue