Integrate Simplified Privacy essentials library
This commit is contained in:
parent
0ab1ac4168
commit
a3a9fb8843
11 changed files with 25 additions and 176 deletions
|
|
@ -11,7 +11,6 @@ class Constants:
|
||||||
|
|
||||||
CONNECTION_RETRY_INTERVAL: Final[int] = int(os.environ.get('CONNECTION_RETRY_INTERVAL', '5'))
|
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'))
|
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_PATH: Final[str] = os.environ.get('HV_CLIENT_PATH')
|
||||||
HV_CLIENT_VERSION_NUMBER: Final[str] = os.environ.get('HV_CLIENT_VERSION_NUMBER')
|
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_SESSION_STATE_HOME: Final[str] = f'{HV_STATE_HOME}/sessions'
|
||||||
HV_TOR_STATE_HOME: Final[str] = f'{HV_STATE_HOME}/tor'
|
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'
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,6 @@ class ConnectionTerminationError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TorServiceInitializationError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PolicyAssignmentError(Exception):
|
class PolicyAssignmentError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from concurrent.futures import ThreadPoolExecutor, TimeoutError as FutureTimeoutError
|
|
||||||
from core.Constants import Constants
|
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.ConfigurationController import ConfigurationController
|
||||||
from core.controllers.ProfileController import ProfileController
|
from core.controllers.ProfileController import ProfileController
|
||||||
from core.controllers.SessionStateController import SessionStateController
|
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.session.SessionProfile import SessionProfile
|
||||||
from core.models.system.SystemProfile import SystemProfile
|
from core.models.system.SystemProfile import SystemProfile
|
||||||
from core.models.system.SystemState import SystemState
|
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 core.services.WebServiceApiService import WebServiceApiService
|
||||||
|
from essentials.modules.TorModule import TorModule
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from subprocess import CalledProcessError
|
from subprocess import CalledProcessError
|
||||||
from typing import Union, Optional, Any
|
from typing import Union, Optional, Any
|
||||||
import os
|
import os
|
||||||
import psutil
|
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import stem
|
|
||||||
import stem.control
|
|
||||||
import stem.process
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
@ -209,123 +205,34 @@ class ConnectionController:
|
||||||
ConnectionController.terminate_tor_connection()
|
ConnectionController.terminate_tor_connection()
|
||||||
time.sleep(1.0)
|
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
|
@staticmethod
|
||||||
def establish_tor_connection(connection_observer: Optional[ConnectionObserver] = None):
|
def establish_tor_connection(connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
||||||
Path(Constants.HV_TOR_STATE_HOME).mkdir(mode=0o700, parents=True, exist_ok=True)
|
tor_module = TorModule(Constants.HV_TOR_STATE_HOME)
|
||||||
|
tor_module.start_service(connection_observer)
|
||||||
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.')
|
|
||||||
|
|
||||||
for session_state in SessionStateController.all():
|
for session_state in SessionStateController.all():
|
||||||
|
|
||||||
for port_number in session_state.network_port_numbers.tor:
|
for port_number in session_state.network_port_numbers.tor:
|
||||||
ConnectionController.establish_tor_session_connection(port_number)
|
tor_module.create_session(port_number)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def terminate_tor_connection():
|
def terminate_tor_connection():
|
||||||
|
|
||||||
control_socket_file = Path(Constants.HV_TOR_CONTROL_SOCKET_PATH)
|
tor_module = TorModule(Constants.HV_TOR_STATE_HOME)
|
||||||
process_identifier_file = Path(Constants.HV_TOR_PROCESS_IDENTIFIER_PATH)
|
tor_module.stop_service()
|
||||||
instance_lock_file = Path(Constants.HV_TOR_INSTANCE_LOCK_PATH)
|
|
||||||
|
|
||||||
try:
|
@staticmethod
|
||||||
process_identifier = int(process_identifier_file.read_text().strip())
|
def establish_tor_session_connection(port_number: int, connection_observer: Optional[ConnectionObserver] = None):
|
||||||
except (OSError, ValueError):
|
|
||||||
process_identifier = 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)
|
tor_module = TorModule(Constants.HV_TOR_STATE_HOME)
|
||||||
|
tor_module.destroy_session(port_number)
|
||||||
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)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def establish_wireguard_session_connection(profile: SessionProfile, session_directory: str, port_number: int):
|
def establish_wireguard_session_connection(profile: SessionProfile, session_directory: str, port_number: int):
|
||||||
|
|
@ -586,16 +493,3 @@ class ConnectionController:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
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
|
|
||||||
))
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
class Event:
|
|
||||||
|
|
||||||
def __init__(self, subject = None, meta = None):
|
|
||||||
|
|
||||||
self.subject = subject
|
|
||||||
self.meta = meta or {}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from core.observers.BaseObserver import BaseObserver
|
from essentials.observers.BaseObserver import BaseObserver
|
||||||
|
|
||||||
|
|
||||||
class ApplicationVersionObserver(BaseObserver):
|
class ApplicationVersionObserver(BaseObserver):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from core.observers.BaseObserver import BaseObserver
|
from essentials.observers.BaseObserver import BaseObserver
|
||||||
|
|
||||||
|
|
||||||
class ClientObserver(BaseObserver):
|
class ClientObserver(BaseObserver):
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
from core.observers.BaseObserver import BaseObserver
|
from essentials.observers.ConnectionObserver import ConnectionObserver as BaseConnectionObserver
|
||||||
|
|
||||||
|
|
||||||
class ConnectionObserver(BaseObserver):
|
class ConnectionObserver(BaseConnectionObserver):
|
||||||
|
pass
|
||||||
def __init__(self):
|
|
||||||
self.on_connecting = []
|
|
||||||
self.on_tor_bootstrapping = []
|
|
||||||
self.on_tor_bootstrap_progressing = []
|
|
||||||
self.on_tor_bootstrapped = []
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from core.observers.BaseObserver import BaseObserver
|
from essentials.observers.BaseObserver import BaseObserver
|
||||||
|
|
||||||
|
|
||||||
class InvoiceObserver(BaseObserver):
|
class InvoiceObserver(BaseObserver):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from core.observers.BaseObserver import BaseObserver
|
from essentials.observers.BaseObserver import BaseObserver
|
||||||
|
|
||||||
|
|
||||||
class ProfileObserver(BaseObserver):
|
class ProfileObserver(BaseObserver):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
name = "sp-hydra-veil-core"
|
name = "sp-hydra-veil-core"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Simplified Privacy" },
|
{ name = "Simplified Privacy" },
|
||||||
]
|
]
|
||||||
description = "A library that exposes core logic to higher-level components."
|
description = "A library that exposes core logic to higher-level components."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
@ -19,7 +19,7 @@ dependencies = [
|
||||||
"pysocks ~= 1.7.1",
|
"pysocks ~= 1.7.1",
|
||||||
"python-dateutil ~= 2.9.0.post0",
|
"python-dateutil ~= 2.9.0.post0",
|
||||||
"requests ~= 2.32.5",
|
"requests ~= 2.32.5",
|
||||||
"stem ~= 1.8.2",
|
"sp-essentials ~= 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue