Adjusted Tor Module to work within gui and core's new frameworks. As well as changed the dict observer feedback to string
This commit is contained in:
parent
f913d8a082
commit
fe9a60563b
7 changed files with 98 additions and 44 deletions
|
|
@ -6,8 +6,10 @@ import os
|
|||
@dataclass(frozen=True)
|
||||
class Constants:
|
||||
|
||||
TOR_BOOTSTRAP_TIMEOUT: Final[int] = int(os.environ.get('TOR_BOOTSTRAP_TIMEOUT', '90'))
|
||||
TOR_BOOTSTRAP_TIMEOUT: Final[int] = int(
|
||||
os.environ.get("TOR_BOOTSTRAP_TIMEOUT", "90")
|
||||
)
|
||||
|
||||
TOR_CONTROL_SOCKET_FILENAME: Final[str] = 'tor.sock'
|
||||
TOR_PROCESS_IDENTIFIER_FILENAME: Final[str] = 'tor.pid'
|
||||
TOR_INSTANCE_LOCK_FILENAME: Final[str] = 'lock'
|
||||
TOR_CONTROL_SOCKET_FILENAME: Final[str] = "tor.sock"
|
||||
TOR_PROCESS_IDENTIFIER_FILENAME: Final[str] = "tor.pid"
|
||||
TOR_INSTANCE_LOCK_FILENAME: Final[str] = "lock"
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@ class CommandNotFoundError(OSError):
|
|||
self.subject = subject
|
||||
super().__init__(f"Command '{subject}' could not be found.")
|
||||
|
||||
|
||||
class TorServiceInitializationError(Exception):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
class Event:
|
||||
|
||||
def __init__(self, subject = None, meta = None):
|
||||
def __init__(self, subject=None, meta=None):
|
||||
|
||||
self.subject = subject
|
||||
self.meta = meta or {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from concurrent.futures import ThreadPoolExecutor, TimeoutError as FutureTimeout
|
|||
from essentials.Constants import Constants
|
||||
from essentials.Errors import TorServiceInitializationError
|
||||
from essentials.observers.ConnectionObserver import ConnectionObserver
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import os
|
||||
|
|
@ -20,30 +21,40 @@ class TorModule:
|
|||
self.state_home = state_home
|
||||
self.bootstrap_timeout = Constants.TOR_BOOTSTRAP_TIMEOUT
|
||||
|
||||
self.control_socket_path = f'{self.state_home}/{Constants.TOR_CONTROL_SOCKET_FILENAME}'
|
||||
self.process_identifier_path = f'{self.state_home}/{Constants.TOR_PROCESS_IDENTIFIER_FILENAME}'
|
||||
self.instance_lock_path = f'{self.state_home}/{Constants.TOR_INSTANCE_LOCK_FILENAME}'
|
||||
self.control_socket_path = (
|
||||
f"{self.state_home}/{Constants.TOR_CONTROL_SOCKET_FILENAME}"
|
||||
)
|
||||
self.process_identifier_path = (
|
||||
f"{self.state_home}/{Constants.TOR_PROCESS_IDENTIFIER_FILENAME}"
|
||||
)
|
||||
self.instance_lock_path = (
|
||||
f"{self.state_home}/{Constants.TOR_INSTANCE_LOCK_FILENAME}"
|
||||
)
|
||||
|
||||
def start_service(self, connection_observer: Optional[ConnectionObserver] = None):
|
||||
|
||||
print("started tor service")
|
||||
|
||||
Path(self.state_home).mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
|
||||
self.stop_service()
|
||||
|
||||
if connection_observer is not None:
|
||||
connection_observer.notify('tor_bootstrapping')
|
||||
# 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': self.state_home,
|
||||
'ControlSocket': self.control_socket_path,
|
||||
'PIDFile': self.process_identifier_path,
|
||||
'SocksPort': '0'
|
||||
"DataDirectory": self.state_home,
|
||||
"ControlSocket": self.control_socket_path,
|
||||
"PIDFile": self.process_identifier_path,
|
||||
"SocksPort": "0",
|
||||
},
|
||||
init_msg_handler=lambda contents: TorModule.__on_initialization_message(contents, connection_observer)
|
||||
init_msg_handler=lambda contents: TorModule.__on_initialization_message(
|
||||
contents, connection_observer
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
@ -52,23 +63,28 @@ class TorModule:
|
|||
except FutureTimeoutError:
|
||||
|
||||
self.stop_service()
|
||||
raise TorServiceInitializationError('The dedicated Tor service could not be initialized.')
|
||||
|
||||
if connection_observer is not None:
|
||||
connection_observer.notify('tor_bootstrapped')
|
||||
raise TorServiceInitializationError(
|
||||
"The dedicated Tor service could not be initialized."
|
||||
)
|
||||
|
||||
# if connection_observer is not None:
|
||||
# connection_observer.notify("tor_bootstrapped")
|
||||
print("tor bootstrapped")
|
||||
try:
|
||||
|
||||
controller = stem.control.Controller.from_socket_file(self.control_socket_path)
|
||||
controller = stem.control.Controller.from_socket_file(
|
||||
self.control_socket_path
|
||||
)
|
||||
controller.authenticate()
|
||||
|
||||
except (FileNotFoundError, stem.SocketError, TypeError, IndexError):
|
||||
|
||||
self.stop_service()
|
||||
raise TorServiceInitializationError('The dedicated Tor service could not be initialized.')
|
||||
raise TorServiceInitializationError(
|
||||
"The dedicated Tor service could not be initialized."
|
||||
)
|
||||
|
||||
def stop_service(self):
|
||||
|
||||
control_socket_file = Path(self.control_socket_path)
|
||||
process_identifier_file = Path(self.process_identifier_path)
|
||||
instance_lock_file = Path(self.instance_lock_path)
|
||||
|
|
@ -88,6 +104,8 @@ class TorModule:
|
|||
except ProcessLookupError:
|
||||
pass
|
||||
|
||||
try:
|
||||
|
||||
process = psutil.Process(process_identifier)
|
||||
|
||||
if process.is_running():
|
||||
|
|
@ -100,54 +118,87 @@ class TorModule:
|
|||
process_identifier_file.unlink(missing_ok=True)
|
||||
instance_lock_file.unlink(missing_ok=True)
|
||||
|
||||
def create_session(self, port_number: int, connection_observer: Optional[ConnectionObserver] = None):
|
||||
def create_session(
|
||||
self, port_number: int, connection_observer: Optional[ConnectionObserver] = None
|
||||
):
|
||||
print("created a session")
|
||||
|
||||
try:
|
||||
|
||||
controller = stem.control.Controller.from_socket_file(self.control_socket_path)
|
||||
controller = stem.control.Controller.from_socket_file(
|
||||
self.control_socket_path
|
||||
)
|
||||
controller.authenticate()
|
||||
|
||||
except (FileNotFoundError, stem.SocketError, TypeError, IndexError):
|
||||
|
||||
self.start_service(connection_observer=connection_observer)
|
||||
|
||||
controller = stem.control.Controller.from_socket_file(self.control_socket_path)
|
||||
controller = stem.control.Controller.from_socket_file(
|
||||
self.control_socket_path
|
||||
)
|
||||
controller.authenticate()
|
||||
|
||||
socks_port_numbers = [str(port_number) for port_number in controller.get_ports('socks')]
|
||||
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)
|
||||
controller.set_conf("SocksPort", socks_port_numbers)
|
||||
|
||||
def destroy_session(self, port_number: int):
|
||||
print("destroying session")
|
||||
|
||||
try:
|
||||
|
||||
controller = stem.control.Controller.from_socket_file(self.control_socket_path)
|
||||
controller = stem.control.Controller.from_socket_file(
|
||||
self.control_socket_path
|
||||
)
|
||||
controller.authenticate()
|
||||
|
||||
socks_port_numbers = [str(port_number) for port_number in controller.get_ports('socks')]
|
||||
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)
|
||||
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')
|
||||
controller.set_conf("SocksPort", "0")
|
||||
|
||||
except (FileNotFoundError, stem.SocketError, TypeError, IndexError):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def __on_initialization_message(contents, connection_observer: Optional[ConnectionObserver] = None):
|
||||
|
||||
def __on_initialization_message(
|
||||
contents, connection_observer: Optional[ConnectionObserver] = None
|
||||
):
|
||||
if connection_observer is not None:
|
||||
|
||||
if 'Bootstrapped ' in contents:
|
||||
if "Bootstrapped " in contents:
|
||||
|
||||
progress = (m := re.search(r' (\d{1,3})% ', contents)) and int(m.group(1))
|
||||
# original version,
|
||||
# progress = (m := re.search(r" (\d{1,3})% ", contents)) and int(
|
||||
# m.group(1)
|
||||
# )
|
||||
|
||||
# # Search for the pattern in the contents
|
||||
match = re.search(r" (\d{1,3})% ", contents)
|
||||
|
||||
# # Check if we found a match
|
||||
if match:
|
||||
# If we found it, get the number and convert to integer
|
||||
progress = int(match.group(1))
|
||||
else:
|
||||
# If we didn't find it, use a default value
|
||||
progress = 0
|
||||
|
||||
progress_string = f"Tor Bootstrap {progress}%"
|
||||
connection_observer.notify("tor_bootstrap_progressing", progress_string)
|
||||
|
||||
connection_observer.notify('tor_bootstrap_progressing', None, dict(
|
||||
progress=progress
|
||||
))
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ class BaseObserver:
|
|||
|
||||
def subscribe(self, topic, callback):
|
||||
|
||||
callbacks = getattr(self, f'on_{topic}', None)
|
||||
callbacks = getattr(self, f"on_{topic}", None)
|
||||
|
||||
if callbacks is None:
|
||||
return
|
||||
|
||||
callbacks.append(callback)
|
||||
|
||||
def notify(self, topic, subject = None, meta = None):
|
||||
def notify(self, topic, subject=None, meta=None):
|
||||
|
||||
callbacks = getattr(self, f'on_{topic}', None)
|
||||
callbacks = getattr(self, f"on_{topic}", None)
|
||||
|
||||
if callbacks is None:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ class ConnectionService:
|
|||
def get_random_available_port_number():
|
||||
|
||||
socket_instance = socket.socket()
|
||||
socket_instance.bind(('', 0))
|
||||
socket_instance.bind(("", 0))
|
||||
port_number = socket_instance.getsockname()[1]
|
||||
socket_instance.close()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "sp-essentials"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
authors = [
|
||||
{ name = "Simplified Privacy" },
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue