diff --git a/core/Constants.py b/core/Constants.py index dd5629e..73f37c7 100644 --- a/core/Constants.py +++ b/core/Constants.py @@ -11,7 +11,6 @@ class Constants: CONNECTION_RETRY_INTERVAL: Final[int] = int(os.environ.get('CONNECTION_RETRY_INTERVAL', '5')) MAX_CONNECTION_ATTEMPTS: Final[int] = int(os.environ.get('MAX_CONNECTION_ATTEMPTS', '2')) - TOR_BOOTSTRAP_TIMEOUT: Final[int] = int(os.environ.get('TOR_BOOTSTRAP_TIMEOUT', '90')) HV_CLIENT_PATH: Final[str] = os.environ.get('HV_CLIENT_PATH') HV_CLIENT_VERSION_NUMBER: Final[str] = os.environ.get('HV_CLIENT_VERSION_NUMBER') @@ -48,7 +47,3 @@ class Constants: HV_SESSION_STATE_HOME: Final[str] = f'{HV_STATE_HOME}/sessions' HV_TOR_STATE_HOME: Final[str] = f'{HV_STATE_HOME}/tor' - - HV_TOR_CONTROL_SOCKET_PATH: Final[str] = f'{HV_TOR_STATE_HOME}/tor.sock' - HV_TOR_PROCESS_IDENTIFIER_PATH: Final[str] = f'{HV_TOR_STATE_HOME}/tor.pid' - HV_TOR_INSTANCE_LOCK_PATH: Final[str] = f'{HV_TOR_STATE_HOME}/lock' diff --git a/core/Errors.py b/core/Errors.py index 84f4337..cdbd85d 100644 --- a/core/Errors.py +++ b/core/Errors.py @@ -26,10 +26,6 @@ class ConnectionTerminationError(Exception): pass -class TorServiceInitializationError(Exception): - pass - - class PolicyAssignmentError(Exception): pass diff --git a/core/controllers/ConnectionController.py b/core/controllers/ConnectionController.py index 6e017b4..db1b93b 100644 --- a/core/controllers/ConnectionController.py +++ b/core/controllers/ConnectionController.py @@ -1,7 +1,6 @@ from collections.abc import Callable -from concurrent.futures import ThreadPoolExecutor, TimeoutError as FutureTimeoutError from core.Constants import Constants -from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionUnprotectedError, ConnectionTerminationError, CommandNotFoundError, TorServiceInitializationError +from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionUnprotectedError, ConnectionTerminationError, CommandNotFoundError from core.controllers.ConfigurationController import ConfigurationController from core.controllers.ProfileController import ProfileController from core.controllers.SessionStateController import SessionStateController @@ -9,20 +8,17 @@ from core.controllers.SystemStateController import SystemStateController from core.models.session.SessionProfile import SessionProfile from core.models.system.SystemProfile import SystemProfile from core.models.system.SystemState import SystemState -from core.observers import ConnectionObserver +from core.observers.ConnectionObserver import ConnectionObserver from core.services.WebServiceApiService import WebServiceApiService +from essentials.modules.TorModule import TorModule from pathlib import Path from subprocess import CalledProcessError from typing import Union, Optional, Any import os -import psutil import random import re import shutil import socket -import stem -import stem.control -import stem.process import subprocess import sys import tempfile @@ -209,123 +205,34 @@ class ConnectionController: ConnectionController.terminate_tor_connection() time.sleep(1.0) - @staticmethod - def establish_tor_session_connection(port_number: int, connection_observer: Optional[ConnectionObserver] = None): - - try: - - controller = stem.control.Controller.from_socket_file(Constants.HV_TOR_CONTROL_SOCKET_PATH) - controller.authenticate() - - except (FileNotFoundError, stem.SocketError, TypeError, IndexError): - - ConnectionController.establish_tor_connection(connection_observer=connection_observer) - - controller = stem.control.Controller.from_socket_file(Constants.HV_TOR_CONTROL_SOCKET_PATH) - controller.authenticate() - - socks_port_numbers = [str(port_number) for port_number in controller.get_ports('socks')] - socks_port_numbers.append(str(port_number)) - - controller.set_conf('SocksPort', socks_port_numbers) - - @staticmethod - def terminate_tor_session_connection(port_number: int): - - try: - - controller = stem.control.Controller.from_socket_file(Constants.HV_TOR_CONTROL_SOCKET_PATH) - controller.authenticate() - - socks_port_numbers = [str(port_number) for port_number in controller.get_ports('socks')] - - if len(socks_port_numbers) > 1: - - socks_port_numbers = [socks_port_number for socks_port_number in socks_port_numbers if socks_port_number != port_number] - controller.set_conf('SocksPort', socks_port_numbers) - - else: - controller.set_conf('SocksPort', '0') - - except (FileNotFoundError, stem.SocketError, TypeError, IndexError): - pass - @staticmethod def establish_tor_connection(connection_observer: Optional[ConnectionObserver] = None): - Path(Constants.HV_TOR_STATE_HOME).mkdir(mode=0o700, parents=True, exist_ok=True) - - ConnectionController.terminate_tor_connection() - - if connection_observer is not None: - connection_observer.notify('tor_bootstrapping') - - with ThreadPoolExecutor(max_workers=1) as executor: - - future = executor.submit( - stem.process.launch_tor_with_config, - config={ - 'DataDirectory': Constants.HV_TOR_STATE_HOME, - 'ControlSocket': Constants.HV_TOR_CONTROL_SOCKET_PATH, - 'PIDFile': Constants.HV_TOR_PROCESS_IDENTIFIER_PATH, - 'SocksPort': '0' - }, - init_msg_handler=lambda contents: ConnectionController.__on_tor_initialization_message(contents, connection_observer) - ) - - try: - future.result(timeout=Constants.TOR_BOOTSTRAP_TIMEOUT) - - except FutureTimeoutError: - - ConnectionController.terminate_tor_connection() - raise TorServiceInitializationError('The dedicated Tor service could not be initialized.') - - if connection_observer is not None: - connection_observer.notify('tor_bootstrapped') - - try: - - controller = stem.control.Controller.from_socket_file(Constants.HV_TOR_CONTROL_SOCKET_PATH) - controller.authenticate() - - except (FileNotFoundError, stem.SocketError, TypeError, IndexError): - - ConnectionController.terminate_tor_connection() - raise TorServiceInitializationError('The dedicated Tor service could not be initialized.') + tor_module = TorModule(Constants.HV_TOR_STATE_HOME) + tor_module.start_service(connection_observer) for session_state in SessionStateController.all(): for port_number in session_state.network_port_numbers.tor: - ConnectionController.establish_tor_session_connection(port_number) + tor_module.create_session(port_number) @staticmethod def terminate_tor_connection(): - control_socket_file = Path(Constants.HV_TOR_CONTROL_SOCKET_PATH) - process_identifier_file = Path(Constants.HV_TOR_PROCESS_IDENTIFIER_PATH) - instance_lock_file = Path(Constants.HV_TOR_INSTANCE_LOCK_PATH) + tor_module = TorModule(Constants.HV_TOR_STATE_HOME) + tor_module.stop_service() - try: - process_identifier = int(process_identifier_file.read_text().strip()) - except (OSError, ValueError): - process_identifier = None + @staticmethod + def establish_tor_session_connection(port_number: int, connection_observer: Optional[ConnectionObserver] = None): - if process_identifier is not None: + tor_module = TorModule(Constants.HV_TOR_STATE_HOME) + tor_module.create_session(port_number, connection_observer) - try: + @staticmethod + def terminate_tor_session_connection(port_number: int): - process = psutil.Process(process_identifier) - - if process.is_running(): - process.terminate() - - except psutil.NoSuchProcess: - pass - - control_socket_file.unlink(missing_ok=True) - process_identifier_file.unlink(missing_ok=True) - instance_lock_file.unlink(missing_ok=True) + tor_module = TorModule(Constants.HV_TOR_STATE_HOME) + tor_module.destroy_session(port_number) @staticmethod def establish_wireguard_session_connection(profile: SessionProfile, session_directory: str, port_number: int): @@ -586,16 +493,3 @@ class ConnectionController: return True return False - - @staticmethod - def __on_tor_initialization_message(contents, connection_observer: Optional[ConnectionObserver] = None): - - if connection_observer is not None: - - if 'Bootstrapped ' in contents: - - progress = (m := re.search(r' (\d{1,3})% ', contents)) and int(m.group(1)) - - connection_observer.notify('tor_bootstrap_progressing', None, dict( - progress=progress - )) diff --git a/core/models/Event.py b/core/models/Event.py deleted file mode 100644 index 5e254cf..0000000 --- a/core/models/Event.py +++ /dev/null @@ -1,6 +0,0 @@ -class Event: - - def __init__(self, subject = None, meta = None): - - self.subject = subject - self.meta = meta or {} diff --git a/core/observers/ApplicationVersionObserver.py b/core/observers/ApplicationVersionObserver.py index ea20100..dce766e 100644 --- a/core/observers/ApplicationVersionObserver.py +++ b/core/observers/ApplicationVersionObserver.py @@ -1,4 +1,4 @@ -from core.observers.BaseObserver import BaseObserver +from essentials.observers.BaseObserver import BaseObserver class ApplicationVersionObserver(BaseObserver): diff --git a/core/observers/BaseObserver.py b/core/observers/BaseObserver.py deleted file mode 100644 index 7068c22..0000000 --- a/core/observers/BaseObserver.py +++ /dev/null @@ -1,25 +0,0 @@ -from core.models.Event import Event - - -class BaseObserver: - - def subscribe(self, topic, callback): - - callbacks = getattr(self, f'on_{topic}', None) - - if callbacks is None: - return - - callbacks.append(callback) - - def notify(self, topic, subject = None, meta = None): - - callbacks = getattr(self, f'on_{topic}', None) - - if callbacks is None: - return - - event = Event(subject, meta) - - for callback in callbacks: - callback(event) diff --git a/core/observers/ClientObserver.py b/core/observers/ClientObserver.py index 5b06c83..bb28bc2 100644 --- a/core/observers/ClientObserver.py +++ b/core/observers/ClientObserver.py @@ -1,4 +1,4 @@ -from core.observers.BaseObserver import BaseObserver +from essentials.observers.BaseObserver import BaseObserver class ClientObserver(BaseObserver): diff --git a/core/observers/ConnectionObserver.py b/core/observers/ConnectionObserver.py index 303560a..88ad874 100644 --- a/core/observers/ConnectionObserver.py +++ b/core/observers/ConnectionObserver.py @@ -1,10 +1,5 @@ -from core.observers.BaseObserver import BaseObserver +from essentials.observers.ConnectionObserver import ConnectionObserver as BaseConnectionObserver -class ConnectionObserver(BaseObserver): - - def __init__(self): - self.on_connecting = [] - self.on_tor_bootstrapping = [] - self.on_tor_bootstrap_progressing = [] - self.on_tor_bootstrapped = [] +class ConnectionObserver(BaseConnectionObserver): + pass diff --git a/core/observers/InvoiceObserver.py b/core/observers/InvoiceObserver.py index 6a7106f..7fa6a23 100644 --- a/core/observers/InvoiceObserver.py +++ b/core/observers/InvoiceObserver.py @@ -1,4 +1,4 @@ -from core.observers.BaseObserver import BaseObserver +from essentials.observers.BaseObserver import BaseObserver class InvoiceObserver(BaseObserver): diff --git a/core/observers/ProfileObserver.py b/core/observers/ProfileObserver.py index 8071dbf..e9c62f7 100644 --- a/core/observers/ProfileObserver.py +++ b/core/observers/ProfileObserver.py @@ -1,4 +1,4 @@ -from core.observers.BaseObserver import BaseObserver +from essentials.observers.BaseObserver import BaseObserver class ProfileObserver(BaseObserver): diff --git a/pyproject.toml b/pyproject.toml index 40a2837..299983f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "sp-hydra-veil-core" version = "2.2.1" authors = [ - { name = "Simplified Privacy" }, + { name = "Simplified Privacy" }, ] description = "A library that exposes core logic to higher-level components." readme = "README.md" @@ -19,7 +19,7 @@ dependencies = [ "pysocks ~= 1.7.1", "python-dateutil ~= 2.9.0.post0", "requests ~= 2.32.5", - "stem ~= 1.8.2", + "sp-essentials ~= 1.0.0", ] [project.urls]