Autoformat
This commit is contained in:
@@ -1,7 +1,3 @@
|
||||
from .onion import Onion
|
||||
from .onion import get_available_port
|
||||
from .onion import Onion, get_available_port
|
||||
|
||||
__all__ = [
|
||||
'Onion',
|
||||
'get_available_port'
|
||||
]
|
||||
__all__ = ["Onion", "get_available_port"]
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
from stem.control import Controller
|
||||
from .stem_process import launch_tor_with_config
|
||||
from stem import ProtocolError
|
||||
|
||||
import socket
|
||||
import random
|
||||
import base64
|
||||
import os
|
||||
import psutil
|
||||
import platform
|
||||
import random
|
||||
import socket
|
||||
import subprocess
|
||||
import tempfile
|
||||
import platform
|
||||
import time
|
||||
import base64
|
||||
|
||||
import nacl.public
|
||||
|
||||
import psutil
|
||||
from rich import print
|
||||
from stem import ProtocolError
|
||||
from stem.control import Controller
|
||||
|
||||
from dragonion_server.utils.core import dirs
|
||||
from dragonion_server.utils import config
|
||||
from dragonion_server.utils.config.db import services
|
||||
from dragonion_server.utils.core import dirs
|
||||
|
||||
from .stem_process import launch_tor_with_config
|
||||
|
||||
|
||||
def get_available_port(min_port: int = 1000, max_port: int = 65535):
|
||||
@@ -61,9 +61,9 @@ class Onion(object):
|
||||
try:
|
||||
cmdline = proc.cmdline()
|
||||
if (
|
||||
cmdline[0] == self.tor_path
|
||||
and cmdline[1] == "-f"
|
||||
and cmdline[2] == self.tor_torrc
|
||||
cmdline[0] == self.tor_path
|
||||
and cmdline[1] == "-f"
|
||||
and cmdline[2] == self.tor_torrc
|
||||
):
|
||||
proc.terminate()
|
||||
proc.wait()
|
||||
@@ -82,18 +82,18 @@ class Onion(object):
|
||||
self.kill_same_tor()
|
||||
|
||||
tor_config = {
|
||||
'DataDirectory': tor_data_directory_name,
|
||||
'SocksPort': str(self.tor_socks_port),
|
||||
'CookieAuthentication': '1',
|
||||
'CookieAuthFile': self.tor_cookie_auth_file,
|
||||
'AvoidDiskWrites': '1',
|
||||
'Log': [
|
||||
'NOTICE stdout'
|
||||
]
|
||||
"DataDirectory": tor_data_directory_name,
|
||||
"SocksPort": str(self.tor_socks_port),
|
||||
"CookieAuthentication": "1",
|
||||
"CookieAuthFile": self.tor_cookie_auth_file,
|
||||
"AvoidDiskWrites": "1",
|
||||
"Log": ["NOTICE stdout"],
|
||||
}
|
||||
|
||||
if platform.system() in ["Windows", "Darwin"] or \
|
||||
len(tor_data_directory_name) > 90:
|
||||
if (
|
||||
platform.system() in ["Windows", "Darwin"]
|
||||
or len(tor_data_directory_name) > 90
|
||||
):
|
||||
try:
|
||||
self.tor_control_port = get_available_port(1000, 65535)
|
||||
tor_config = tor_config | {"ControlPort": str(self.tor_control_port)}
|
||||
@@ -102,24 +102,22 @@ class Onion(object):
|
||||
self.tor_control_socket = None
|
||||
else:
|
||||
self.tor_control_port = None
|
||||
self.tor_control_socket = os.path.abspath(os.path.join(
|
||||
tor_data_directory_name, "control_socket"
|
||||
))
|
||||
self.tor_control_socket = os.path.abspath(
|
||||
os.path.join(tor_data_directory_name, "control_socket")
|
||||
)
|
||||
tor_config = tor_config | {"ControlSocket": str(self.tor_control_socket)}
|
||||
|
||||
return tor_config
|
||||
|
||||
|
||||
def connect(self):
|
||||
self.tor_data_directory = tempfile.TemporaryDirectory(
|
||||
dir=dirs.build_tmp_dir()
|
||||
)
|
||||
self.tor_data_directory = tempfile.TemporaryDirectory(dir=dirs.build_tmp_dir())
|
||||
self.tor_data_directory_name = self.tor_data_directory.name
|
||||
|
||||
self.tor_proc = launch_tor_with_config(
|
||||
config=self.get_config(self.tor_data_directory_name),
|
||||
tor_cmd=self.tor_path,
|
||||
take_ownership=True,
|
||||
init_msg_handler=print
|
||||
init_msg_handler=print,
|
||||
)
|
||||
|
||||
time.sleep(2)
|
||||
@@ -149,14 +147,12 @@ class Onion(object):
|
||||
|
||||
client_auth_priv_key_raw = nacl.public.PrivateKey.generate()
|
||||
client_auth_priv_key = key_str(client_auth_priv_key_raw)
|
||||
client_auth_pub_key = key_str(
|
||||
client_auth_priv_key_raw.public_key
|
||||
)
|
||||
client_auth_pub_key = key_str(client_auth_priv_key_raw.public_key)
|
||||
|
||||
services[name] = config.models.ServiceModel(
|
||||
port=port,
|
||||
client_auth_priv_key=client_auth_priv_key,
|
||||
client_auth_pub_key=client_auth_pub_key
|
||||
client_auth_pub_key=client_auth_pub_key,
|
||||
)
|
||||
return services[name]
|
||||
|
||||
@@ -167,7 +163,7 @@ class Onion(object):
|
||||
:return: .onion url
|
||||
"""
|
||||
if name not in services.keys():
|
||||
raise 'Service not created'
|
||||
raise "Service not created"
|
||||
|
||||
service: config.models.ServiceModel = services[name]
|
||||
|
||||
@@ -193,8 +189,9 @@ class Onion(object):
|
||||
service.key_type = "ED25519-V3"
|
||||
service.key_content = res.private_key
|
||||
|
||||
self.auth_string = f'{res.service_id}:descriptor:' \
|
||||
f'x25519:{service.client_auth_priv_key}'
|
||||
self.auth_string = (
|
||||
f"{res.service_id}:descriptor:" f"x25519:{service.client_auth_priv_key}"
|
||||
)
|
||||
|
||||
services[name] = service
|
||||
|
||||
@@ -204,9 +201,7 @@ class Onion(object):
|
||||
service: config.models.ServiceModel = services[name]
|
||||
if service.service_id:
|
||||
try:
|
||||
self.c.remove_ephemeral_hidden_service(
|
||||
service.service_id
|
||||
)
|
||||
self.c.remove_ephemeral_hidden_service(service.service_id)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@@ -222,8 +217,8 @@ class Onion(object):
|
||||
rendezvous_circuit_ids = []
|
||||
for c in self.c.get_circuits():
|
||||
if (
|
||||
c.purpose == "HS_SERVICE_REND"
|
||||
and c.rend_query in self.graceful_close_onions
|
||||
c.purpose == "HS_SERVICE_REND"
|
||||
and c.rend_query in self.graceful_close_onions
|
||||
):
|
||||
rendezvous_circuit_ids.append(c.id)
|
||||
|
||||
@@ -237,9 +232,7 @@ class Onion(object):
|
||||
num_rend_circuits += 1
|
||||
|
||||
if num_rend_circuits == 0:
|
||||
print(
|
||||
"\rTor rendezvous circuits have closed" + " " * 20
|
||||
)
|
||||
print("\rTor rendezvous circuits have closed" + " " * 20)
|
||||
break
|
||||
|
||||
if num_rend_circuits == 1:
|
||||
@@ -271,7 +264,7 @@ class Onion(object):
|
||||
try:
|
||||
self.tor_data_directory.cleanup()
|
||||
except Exception as e:
|
||||
print(f'Cannot cleanup temporary directory: {e}')
|
||||
print(f"Cannot cleanup temporary directory: {e}")
|
||||
|
||||
@property
|
||||
def get_tor_socks_port(self):
|
||||
|
||||
@@ -15,13 +15,21 @@ import stem.util.str_tools
|
||||
import stem.util.system
|
||||
import stem.version
|
||||
|
||||
NO_TORRC = '<no torrc>'
|
||||
NO_TORRC = "<no torrc>"
|
||||
DEFAULT_INIT_TIMEOUT = 90
|
||||
|
||||
|
||||
def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100,
|
||||
init_msg_handler=None, timeout=DEFAULT_INIT_TIMEOUT,
|
||||
take_ownership=False, close_output=True, stdin=None):
|
||||
def launch_tor(
|
||||
tor_cmd="tor",
|
||||
args=None,
|
||||
torrc_path=None,
|
||||
completion_percent=100,
|
||||
init_msg_handler=None,
|
||||
timeout=DEFAULT_INIT_TIMEOUT,
|
||||
take_ownership=False,
|
||||
close_output=True,
|
||||
stdin=None,
|
||||
):
|
||||
"""
|
||||
Initializes a tor process. This blocks until initialization completes or we
|
||||
error out.
|
||||
@@ -68,13 +76,14 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
|
||||
if stem.util.system.is_windows():
|
||||
if timeout is not None and timeout != DEFAULT_INIT_TIMEOUT:
|
||||
raise OSError('You cannot launch tor with a timeout on Windows')
|
||||
raise OSError("You cannot launch tor with a timeout on Windows")
|
||||
|
||||
timeout = None
|
||||
elif threading.current_thread().__class__.__name__ != '_MainThread':
|
||||
elif threading.current_thread().__class__.__name__ != "_MainThread":
|
||||
if timeout is not None and timeout != DEFAULT_INIT_TIMEOUT:
|
||||
raise OSError(
|
||||
'Launching tor with a timeout can only be done in the main thread')
|
||||
"Launching tor with a timeout can only be done in the main thread"
|
||||
)
|
||||
|
||||
timeout = None
|
||||
|
||||
@@ -88,8 +97,10 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
elif not os.path.isfile(tor_cmd):
|
||||
raise OSError("'%s' doesn't exist" % tor_cmd)
|
||||
elif not stem.util.system.is_available(tor_cmd):
|
||||
raise OSError(f"{tor_cmd} isn't available on your system. "
|
||||
f"Maybe it's not in your PATH?")
|
||||
raise OSError(
|
||||
f"{tor_cmd} isn't available on your system. "
|
||||
f"Maybe it's not in your PATH?"
|
||||
)
|
||||
|
||||
# double check that we have a torrc to work with
|
||||
if torrc_path not in (None, NO_TORRC) and not os.path.exists(torrc_path):
|
||||
@@ -103,13 +114,13 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
|
||||
if torrc_path:
|
||||
if torrc_path == NO_TORRC:
|
||||
temp_file = tempfile.mkstemp(prefix='empty-torrc-', text=True)[1]
|
||||
runtime_args += ['-f', temp_file]
|
||||
temp_file = tempfile.mkstemp(prefix="empty-torrc-", text=True)[1]
|
||||
runtime_args += ["-f", temp_file]
|
||||
else:
|
||||
runtime_args += ['-f', torrc_path]
|
||||
runtime_args += ["-f", torrc_path]
|
||||
|
||||
if take_ownership:
|
||||
runtime_args += ['__OwningControllerProcess', str(os.getpid())]
|
||||
runtime_args += ["__OwningControllerProcess", str(os.getpid())]
|
||||
|
||||
tor_process = None
|
||||
|
||||
@@ -119,8 +130,9 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
stdout=subprocess.PIPE,
|
||||
stdin=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=None if platform.system() == 'Windows' else
|
||||
{"LD_LIBRARY_PATH": os.path.dirname(tor_cmd)}
|
||||
env=None
|
||||
if platform.system() == "Windows"
|
||||
else {"LD_LIBRARY_PATH": os.path.dirname(tor_cmd)},
|
||||
)
|
||||
|
||||
if stdin:
|
||||
@@ -129,15 +141,16 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
tor_process.stdin.close()
|
||||
|
||||
if timeout:
|
||||
|
||||
def timeout_handler(*_):
|
||||
raise OSError('reached a %i second timeout without success' % timeout)
|
||||
raise OSError("reached a %i second timeout without success" % timeout)
|
||||
|
||||
signal.signal(signal.SIGALRM, timeout_handler)
|
||||
signal.setitimer(signal.ITIMER_REAL, timeout)
|
||||
|
||||
bootstrap_line = re.compile('Bootstrapped ([0-9]+)%')
|
||||
problem_line = re.compile('\\[(warn|err)] (.*)$')
|
||||
last_problem = 'Timed out'
|
||||
bootstrap_line = re.compile("Bootstrapped ([0-9]+)%")
|
||||
problem_line = re.compile("\\[(warn|err)] (.*)$")
|
||||
last_problem = "Timed out"
|
||||
|
||||
while True:
|
||||
# Tor's stdout will be read as ASCII bytes. This is fine for python 2, but
|
||||
@@ -147,12 +160,12 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
# It seems like python 2.x is perfectly happy for this to be unicode, so
|
||||
# normalizing to that.
|
||||
|
||||
init_line = tor_process.stdout.readline().decode('utf-8', 'replace').strip()
|
||||
init_line = tor_process.stdout.readline().decode("utf-8", "replace").strip()
|
||||
|
||||
# this will provide empty results if the process is terminated
|
||||
|
||||
if not init_line:
|
||||
raise OSError('Process terminated: %s' % last_problem)
|
||||
raise OSError("Process terminated: %s" % last_problem)
|
||||
|
||||
# provide the caller with the initialization message if they want it
|
||||
|
||||
@@ -169,9 +182,9 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
elif problem_match:
|
||||
runlevel, msg = problem_match.groups()
|
||||
|
||||
if 'see warnings above' not in msg:
|
||||
if ': ' in msg:
|
||||
msg = msg.split(': ')[-1].strip()
|
||||
if "see warnings above" not in msg:
|
||||
if ": " in msg:
|
||||
msg = msg.split(": ")[-1].strip()
|
||||
|
||||
last_problem = msg
|
||||
except Exception as e:
|
||||
@@ -199,9 +212,15 @@ def launch_tor(tor_cmd='tor', args=None, torrc_path=None, completion_percent=100
|
||||
assert e
|
||||
|
||||
|
||||
def launch_tor_with_config(config, tor_cmd='tor', completion_percent=100,
|
||||
init_msg_handler=None, timeout=DEFAULT_INIT_TIMEOUT,
|
||||
take_ownership=False, close_output=True):
|
||||
def launch_tor_with_config(
|
||||
config,
|
||||
tor_cmd="tor",
|
||||
completion_percent=100,
|
||||
init_msg_handler=None,
|
||||
timeout=DEFAULT_INIT_TIMEOUT,
|
||||
take_ownership=False,
|
||||
close_output=True,
|
||||
):
|
||||
"""
|
||||
Initializes a tor process, like :func:`~stem.process.launch_tor`, but with a
|
||||
customized configuration. This writes a temporary torrc to disk, launches
|
||||
@@ -246,62 +265,71 @@ def launch_tor_with_config(config, tor_cmd='tor', completion_percent=100,
|
||||
"""
|
||||
|
||||
try:
|
||||
use_stdin = stem.version.get_system_tor_version(
|
||||
tor_cmd) >= stem.version.Requirement.TORRC_VIA_STDIN
|
||||
use_stdin = (
|
||||
stem.version.get_system_tor_version(tor_cmd)
|
||||
>= stem.version.Requirement.TORRC_VIA_STDIN
|
||||
)
|
||||
except IOError:
|
||||
use_stdin = False
|
||||
|
||||
# we need to be sure that we're logging to stdout to figure out when we're
|
||||
# done bootstrapping
|
||||
|
||||
if 'Log' in config:
|
||||
stdout_options = ['DEBUG stdout', 'INFO stdout', 'NOTICE stdout']
|
||||
if "Log" in config:
|
||||
stdout_options = ["DEBUG stdout", "INFO stdout", "NOTICE stdout"]
|
||||
|
||||
if isinstance(config['Log'], str):
|
||||
config['Log'] = [config['Log']]
|
||||
if isinstance(config["Log"], str):
|
||||
config["Log"] = [config["Log"]]
|
||||
|
||||
has_stdout = False
|
||||
|
||||
for log_config in config['Log']:
|
||||
for log_config in config["Log"]:
|
||||
if log_config in stdout_options:
|
||||
has_stdout = True
|
||||
break
|
||||
|
||||
if not has_stdout:
|
||||
config['Log'].append('NOTICE stdout')
|
||||
config["Log"].append("NOTICE stdout")
|
||||
|
||||
config_str = ''
|
||||
config_str = ""
|
||||
|
||||
for key, values in list(config.items()):
|
||||
if isinstance(values, str):
|
||||
config_str += '%s %s\n' % (key, values)
|
||||
config_str += "%s %s\n" % (key, values)
|
||||
else:
|
||||
for value in values:
|
||||
config_str += '%s %s\n' % (key, value)
|
||||
config_str += "%s %s\n" % (key, value)
|
||||
|
||||
if use_stdin:
|
||||
return launch_tor(
|
||||
tor_cmd=tor_cmd,
|
||||
args=['-f', '-'],
|
||||
args=["-f", "-"],
|
||||
completion_percent=completion_percent,
|
||||
init_msg_handler=init_msg_handler,
|
||||
timeout=timeout,
|
||||
take_ownership=take_ownership,
|
||||
close_output=close_output,
|
||||
stdin=config_str
|
||||
stdin=config_str,
|
||||
)
|
||||
else:
|
||||
torrc_descriptor, torrc_path = tempfile.mkstemp(prefix='torrc-', text=True)
|
||||
torrc_descriptor, torrc_path = tempfile.mkstemp(prefix="torrc-", text=True)
|
||||
|
||||
try:
|
||||
with open(torrc_path, 'w') as torrc_file:
|
||||
with open(torrc_path, "w") as torrc_file:
|
||||
torrc_file.write(config_str)
|
||||
|
||||
# prevents tor from error-ing out due to a missing torrc if it gets a sighup
|
||||
args = ['__ReloadTorrcOnSIGHUP', '0']
|
||||
args = ["__ReloadTorrcOnSIGHUP", "0"]
|
||||
|
||||
return launch_tor(tor_cmd, args, torrc_path, completion_percent,
|
||||
init_msg_handler, timeout, take_ownership)
|
||||
return launch_tor(
|
||||
tor_cmd,
|
||||
args,
|
||||
torrc_path,
|
||||
completion_percent,
|
||||
init_msg_handler,
|
||||
timeout,
|
||||
take_ownership,
|
||||
)
|
||||
finally:
|
||||
try:
|
||||
os.close(torrc_descriptor)
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
import os
|
||||
import io
|
||||
import tarfile
|
||||
import requests
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tarfile
|
||||
from typing import Literal
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def get_latest_version() -> str:
|
||||
"""
|
||||
Gets latest non-alfa version name from dist.torproject.org
|
||||
:return:
|
||||
"""
|
||||
r = requests.get('https://dist.torproject.org/torbrowser/').text
|
||||
r = requests.get("https://dist.torproject.org/torbrowser/").text
|
||||
|
||||
results = re.findall(r'<a href=".+/">(.+)/</a>', r)
|
||||
for res in results:
|
||||
if 'a' not in res:
|
||||
if "a" not in res:
|
||||
return res
|
||||
|
||||
|
||||
def get_build() -> Literal[
|
||||
'windows-x86_64',
|
||||
'linux-x86_64',
|
||||
'macos-x86_64',
|
||||
'macos-aarch64'
|
||||
"windows-x86_64", "linux-x86_64", "macos-x86_64", "macos-aarch64"
|
||||
]:
|
||||
"""
|
||||
Gets proper build name for your system
|
||||
:return:
|
||||
"""
|
||||
if sys.platform == 'win32':
|
||||
return 'windows-x86_64'
|
||||
elif sys.platform == 'linux':
|
||||
return 'linux-x86_64'
|
||||
elif sys.platform == 'darwin':
|
||||
if sys.platform == "win32":
|
||||
return "windows-x86_64"
|
||||
elif sys.platform == "linux":
|
||||
return "linux-x86_64"
|
||||
elif sys.platform == "darwin":
|
||||
import platform
|
||||
if platform.uname().machine == 'arm64':
|
||||
return 'macos-aarch64'
|
||||
|
||||
if platform.uname().machine == "arm64":
|
||||
return "macos-aarch64"
|
||||
else:
|
||||
return 'macos-x86_64'
|
||||
return "macos-x86_64"
|
||||
else:
|
||||
raise 'System not supported'
|
||||
raise "System not supported"
|
||||
|
||||
|
||||
def get_tor_expert_bundles(version: str = get_latest_version(),
|
||||
platform: str = get_build()):
|
||||
def get_tor_expert_bundles(
|
||||
version: str = get_latest_version(), platform: str = get_build()
|
||||
):
|
||||
"""
|
||||
Returns a link for downloading tor expert bundle by version and platform
|
||||
:param version: Tor expert bundle version that exists in dist.torproject.org
|
||||
@@ -53,11 +53,13 @@ def get_tor_expert_bundles(version: str = get_latest_version(),
|
||||
get_build()
|
||||
:return:
|
||||
"""
|
||||
return f'https://dist.torproject.org/torbrowser/{version}/tor-expert-bundle-' \
|
||||
f'{version}-{platform}.tar.gz'
|
||||
return (
|
||||
f"https://dist.torproject.org/torbrowser/{version}/tor-expert-bundle-"
|
||||
f"{version}-{platform}.tar.gz"
|
||||
)
|
||||
|
||||
|
||||
def download_tor(url: str = get_tor_expert_bundles(), dist: str = 'tor'):
|
||||
def download_tor(url: str = get_tor_expert_bundles(), dist: str = "tor"):
|
||||
"""
|
||||
Downloads tor from url and unpacks it to specified directory. Note, that
|
||||
it doesn't unpack only tor executable to dist folder, but creates there
|
||||
@@ -69,15 +71,15 @@ def download_tor(url: str = get_tor_expert_bundles(), dist: str = 'tor'):
|
||||
if not os.path.exists(dist):
|
||||
os.makedirs(dist)
|
||||
|
||||
(tar := tarfile.open(fileobj=io.BytesIO(requests.get(url).content),
|
||||
mode='r:gz')).extractall(
|
||||
(
|
||||
tar := tarfile.open(fileobj=io.BytesIO(requests.get(url).content), mode="r:gz")
|
||||
).extractall(
|
||||
members=[
|
||||
tarinfo
|
||||
for tarinfo
|
||||
in tar.getmembers()
|
||||
if tarinfo.name.startswith("tor/")
|
||||
], path=dist)
|
||||
tarinfo for tarinfo in tar.getmembers() if tarinfo.name.startswith("tor/")
|
||||
],
|
||||
path=dist,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
download_tor()
|
||||
|
||||
Reference in New Issue
Block a user