Stable working version of ConnectionController being operated on, split up into systemwide and testing_evaluating. Then ProfileController had a split off of endpoint verification to avoid circular imports
This commit is contained in:
parent
fe3b7ad59e
commit
fd7949cea4
5 changed files with 513 additions and 182 deletions
|
|
@ -1,6 +1,11 @@
|
||||||
from core.errors.exceptions import *
|
from core.errors.exceptions import *
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
from core.services.networking.general_connection_tools.testing_evaluating import await_connection, system_uses_wireguard_interface, await_network_interface
|
||||||
|
from core.services.networking.systemwide.systemwide_wireguard import establish_system_connection, terminate_system_connection
|
||||||
|
from core.services.verification.endpoint_verification import verify_wireguard_endpoint
|
||||||
|
|
||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionUnprotectedError, ConnectionTerminationError, CommandNotFoundError
|
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionUnprotectedError, ConnectionTerminationError, CommandNotFoundError
|
||||||
|
|
@ -93,10 +98,10 @@ class ConnectionController:
|
||||||
|
|
||||||
if profile.is_system_profile():
|
if profile.is_system_profile():
|
||||||
|
|
||||||
if ConnectionController.system_uses_wireguard_interface() and SystemStateController.exists():
|
if system_uses_wireguard_interface() and SystemStateController.exists():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ConnectionController.terminate_system_connection()
|
terminate_system_connection()
|
||||||
except ConnectionTerminationError:
|
except ConnectionTerminationError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -120,14 +125,14 @@ class ConnectionController:
|
||||||
if profile.is_system_profile():
|
if profile.is_system_profile():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return ConnectionController.establish_system_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
return establish_system_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||||
|
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
|
|
||||||
if ConnectionController.__should_renegotiate(profile):
|
if ConnectionController.__should_renegotiate(profile):
|
||||||
|
|
||||||
ProfileController.register_wireguard_session(profile, connection_observer=connection_observer)
|
ProfileController.register_wireguard_session(profile, connection_observer=connection_observer)
|
||||||
return ConnectionController.establish_system_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
return establish_system_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ConnectionError('The connection could not be established.')
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
@ -146,7 +151,7 @@ class ConnectionController:
|
||||||
# this is a check from SessionConnection of if there's a systemwide with mask
|
# this is a check from SessionConnection of if there's a systemwide with mask
|
||||||
if profile.connection.is_unprotected():
|
if profile.connection.is_unprotected():
|
||||||
|
|
||||||
if not ConnectionController.system_uses_wireguard_interface():
|
if not system_uses_wireguard_interface():
|
||||||
|
|
||||||
if not ConnectionUnprotectedError in ignore:
|
if not ConnectionUnprotectedError in ignore:
|
||||||
raise ConnectionUnprotectedError('Connection unprotected while the system is not using a WireGuard interface.')
|
raise ConnectionUnprotectedError('Connection unprotected while the system is not using a WireGuard interface.')
|
||||||
|
|
@ -163,7 +168,7 @@ class ConnectionController:
|
||||||
elif profile.connection.code == 'wireguard':
|
elif profile.connection.code == 'wireguard':
|
||||||
|
|
||||||
if ConfigurationController.get_endpoint_verification_enabled():
|
if ConfigurationController.get_endpoint_verification_enabled():
|
||||||
ProfileController.verify_wireguard_endpoint(profile, ignore=ignore)
|
verify_wireguard_endpoint(profile, ignore=ignore)
|
||||||
|
|
||||||
port_number = ConnectionService.get_random_available_port_number()
|
port_number = ConnectionService.get_random_available_port_number()
|
||||||
ConnectionController.establish_wireguard_session_connection(profile, session_directory, port_number)
|
ConnectionController.establish_wireguard_session_connection(profile, session_directory, port_number)
|
||||||
|
|
@ -178,57 +183,51 @@ class ConnectionController:
|
||||||
session_state.network_port_numbers.proxy.append(proxy_port_number)
|
session_state.network_port_numbers.proxy.append(proxy_port_number)
|
||||||
|
|
||||||
if not profile.connection.is_unprotected():
|
if not profile.connection.is_unprotected():
|
||||||
ConnectionController.await_connection(proxy_port_number or port_number, connection_observer=connection_observer)
|
await_connection(proxy_port_number or port_number, connection_observer=connection_observer)
|
||||||
|
|
||||||
SessionStateController.update_or_create(session_state)
|
SessionStateController.update_or_create(session_state)
|
||||||
|
|
||||||
return proxy_port_number or port_number
|
return proxy_port_number or port_number
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def establish_system_connection(profile: SystemProfile, ignore: tuple[type[Exception]] = (), connection_observer: Optional[ConnectionObserver] = None):
|
# def establish_system_connection(profile: SystemProfile, ignore: tuple[type[Exception]] = (), connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
||||||
if ConfigurationController.get_endpoint_verification_enabled():
|
# if ConfigurationController.get_endpoint_verification_enabled():
|
||||||
ProfileController.verify_wireguard_endpoint(profile, ignore=ignore)
|
# ProfileController.verify_wireguard_endpoint(profile, ignore=ignore)
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
ConnectionController.__establish_system_connection(profile, connection_observer)
|
# ConnectionController.__establish_system_connection(profile, connection_observer)
|
||||||
|
|
||||||
except ConnectionError:
|
# except ConnectionError:
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
ConnectionController.terminate_system_connection()
|
# ConnectionController.terminate_system_connection()
|
||||||
except ConnectionTerminationError:
|
# except ConnectionTerminationError:
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
except CalledProcessError:
|
# except CalledProcessError:
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
ConnectionController.terminate_system_connection()
|
# ConnectionController.terminate_system_connection()
|
||||||
except ConnectionTerminationError:
|
# except ConnectionTerminationError:
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
ConnectionController.__establish_system_connection(profile, connection_observer)
|
# ConnectionController.__establish_system_connection(profile, connection_observer)
|
||||||
|
|
||||||
except (ConnectionError, CalledProcessError):
|
# except (ConnectionError, CalledProcessError):
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
ConnectionController.terminate_system_connection()
|
# ConnectionController.terminate_system_connection()
|
||||||
except ConnectionTerminationError:
|
# except ConnectionTerminationError:
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
ConnectionController.terminate_tor_connection()
|
# ConnectionController.terminate_tor_connection()
|
||||||
time.sleep(1.0)
|
# time.sleep(1.0)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def test_observer(connection_observer: Optional[ConnectionObserver] = None):
|
|
||||||
if connection_observer is not None:
|
|
||||||
connection_observer.notify('custom_message', "HELLO")
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -245,11 +244,11 @@ class ConnectionController:
|
||||||
if connection_observer is not None:
|
if connection_observer is not None:
|
||||||
connection_observer.notify('custom_message', "Tor Can't Initialize")
|
connection_observer.notify('custom_message', "Tor Can't Initialize")
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def terminate_tor_connection():
|
# def terminate_tor_connection():
|
||||||
|
|
||||||
tor_module = TorModule(Constants.HV_TOR_STATE_HOME)
|
# tor_module = TorModule(Constants.HV_TOR_STATE_HOME)
|
||||||
tor_module.stop_service()
|
# tor_module.stop_service()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def establish_tor_session_connection(port_number: int, connection_observer: Optional[ConnectionObserver] = None):
|
def establish_tor_session_connection(port_number: int, connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
@ -323,26 +322,28 @@ class ConnectionController:
|
||||||
|
|
||||||
return subprocess.Popen(('proxychains4', '-f', proxychains_configuration_file_path, 'microsocks', '-p', str(proxy_port_number)), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
return subprocess.Popen(('proxychains4', '-f', proxychains_configuration_file_path, 'microsocks', '-p', str(proxy_port_number)), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def terminate_system_connection():
|
# def terminate_system_connection():
|
||||||
|
|
||||||
if shutil.which('nmcli') is None:
|
# if shutil.which('nmcli') is None:
|
||||||
raise CommandNotFoundError('nmcli')
|
# raise CommandNotFoundError('nmcli')
|
||||||
|
|
||||||
if SystemStateController.exists():
|
# if SystemStateController.exists():
|
||||||
|
|
||||||
process = subprocess.Popen(('nmcli', 'connection', 'delete', 'wg'), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
# process = subprocess.Popen(('nmcli', 'connection', 'delete', 'wg'), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||||
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
# completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
||||||
|
|
||||||
if completed_successfully or not ConnectionController.system_uses_wireguard_interface():
|
# if completed_successfully or not ConnectionController.system_uses_wireguard_interface():
|
||||||
|
|
||||||
subprocess.run(('nmcli', 'connection', 'delete', 'hv-ipv6-sink'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
# subprocess.run(('nmcli', 'connection', 'delete', 'hv-ipv6-sink'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
ConnectionController.terminate_tor_connection()
|
# ConnectionController.terminate_tor_connection()
|
||||||
SystemState.dissolve()
|
# SystemState.dissolve()
|
||||||
|
|
||||||
else:
|
# else:
|
||||||
raise ConnectionTerminationError('The connection could not be terminated.')
|
# raise ConnectionTerminationError('The connection could not be terminated.')
|
||||||
|
|
||||||
|
|
||||||
|
# Stays here for Tor based only. Will move with Tor later.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_proxies(port_number: int):
|
def get_proxies(port_number: int):
|
||||||
|
|
||||||
|
|
@ -351,107 +352,107 @@ class ConnectionController:
|
||||||
https=f'socks5h://127.0.0.1:{port_number}'
|
https=f'socks5h://127.0.0.1:{port_number}'
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def await_connection(port_number: Optional[int] = None, connection_observer: Optional[ConnectionObserver] = None):
|
# def await_connection(port_number: Optional[int] = None, connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
||||||
if port_number is None:
|
# if port_number is None:
|
||||||
ConnectionController.await_network_interface()
|
# ConnectionController.await_network_interface()
|
||||||
|
|
||||||
for retry_count in range(Constants.MAX_CONNECTION_ATTEMPTS):
|
# for retry_count in range(Constants.MAX_CONNECTION_ATTEMPTS):
|
||||||
|
|
||||||
if connection_observer is not None:
|
# if connection_observer is not None:
|
||||||
|
|
||||||
connection_observer.notify('connecting', dict(
|
# connection_observer.notify('connecting', dict(
|
||||||
retry_interval=Constants.CONNECTION_RETRY_INTERVAL,
|
# retry_interval=Constants.CONNECTION_RETRY_INTERVAL,
|
||||||
maximum_number_of_attempts=Constants.MAX_CONNECTION_ATTEMPTS,
|
# maximum_number_of_attempts=Constants.MAX_CONNECTION_ATTEMPTS,
|
||||||
attempt_count=retry_count + 1
|
# attempt_count=retry_count + 1
|
||||||
))
|
# ))
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
|
|
||||||
ConnectionController.__test_connection(port_number)
|
# ConnectionController.__test_connection(port_number)
|
||||||
return
|
# return
|
||||||
|
|
||||||
except ConnectionError:
|
# except ConnectionError:
|
||||||
|
|
||||||
time.sleep(Constants.CONNECTION_RETRY_INTERVAL)
|
# time.sleep(Constants.CONNECTION_RETRY_INTERVAL)
|
||||||
retry_count += 1
|
# retry_count += 1
|
||||||
|
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def await_network_interface():
|
# def await_network_interface():
|
||||||
|
|
||||||
network_interface_is_activated = False
|
# network_interface_is_activated = False
|
||||||
|
|
||||||
retry_interval = .5
|
# retry_interval = .5
|
||||||
maximum_number_of_attempts = 10
|
# maximum_number_of_attempts = 10
|
||||||
attempt = 0
|
# attempt = 0
|
||||||
|
|
||||||
while not network_interface_is_activated and attempt < maximum_number_of_attempts:
|
# while not network_interface_is_activated and attempt < maximum_number_of_attempts:
|
||||||
|
|
||||||
time.sleep(retry_interval)
|
# time.sleep(retry_interval)
|
||||||
|
|
||||||
network_interface_is_activated = ConnectionController.system_uses_wireguard_interface()
|
# network_interface_is_activated = ConnectionController.system_uses_wireguard_interface()
|
||||||
attempt += 1
|
# attempt += 1
|
||||||
|
|
||||||
if not network_interface_is_activated:
|
# if not network_interface_is_activated:
|
||||||
raise ConnectionError('The network interface could not be activated.')
|
# raise ConnectionError('The network interface could not be activated.')
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def system_uses_wireguard_interface():
|
# def system_uses_wireguard_interface():
|
||||||
|
|
||||||
if shutil.which('ip') is None:
|
# if shutil.which('ip') is None:
|
||||||
raise CommandNotFoundError('ip')
|
# raise CommandNotFoundError('ip')
|
||||||
|
|
||||||
process = subprocess.Popen(('ip', 'route', 'get', '192.0.2.1'), stdout=subprocess.PIPE)
|
# process = subprocess.Popen(('ip', 'route', 'get', '192.0.2.1'), stdout=subprocess.PIPE)
|
||||||
process_output = str(process.stdout.read())
|
# process_output = str(process.stdout.read())
|
||||||
|
|
||||||
return bool(re.search('dev wg', str(process_output)))
|
# return bool(re.search('dev wg', str(process_output)))
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def __establish_system_connection(profile: SystemProfile, connection_observer: Optional[ConnectionObserver] = None):
|
# def __establish_system_connection(profile: SystemProfile, connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
||||||
if shutil.which('dbus-send') is None:
|
# if shutil.which('dbus-send') is None:
|
||||||
raise CommandNotFoundError('dbus-send')
|
# raise CommandNotFoundError('dbus-send')
|
||||||
|
|
||||||
if shutil.which('nmcli') is None:
|
# if shutil.which('nmcli') is None:
|
||||||
raise CommandNotFoundError('nmcli')
|
# raise CommandNotFoundError('nmcli')
|
||||||
|
|
||||||
ConnectionController.terminate_system_connection()
|
# ConnectionController.terminate_system_connection()
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
process_output = subprocess.check_output(('nmcli', 'connection', 'import', '--temporary', 'type', 'wireguard', 'file', profile.get_wireguard_configuration_path()), text=True)
|
# process_output = subprocess.check_output(('nmcli', 'connection', 'import', '--temporary', 'type', 'wireguard', 'file', profile.get_wireguard_configuration_path()), text=True)
|
||||||
except CalledProcessError:
|
# except CalledProcessError:
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
|
|
||||||
connection_id = (m := re.search(r'(?<=\()([a-f0-9-]+?)(?=\))', process_output)) and m.group(1)
|
# connection_id = (m := re.search(r'(?<=\()([a-f0-9-]+?)(?=\))', process_output)) and m.group(1)
|
||||||
ipv6_method = subprocess.check_output(('nmcli', '-g', 'ipv6.method', 'connection', 'show', connection_id), text=True).strip()
|
# ipv6_method = subprocess.check_output(('nmcli', '-g', 'ipv6.method', 'connection', 'show', connection_id), text=True).strip()
|
||||||
|
|
||||||
except CalledProcessError:
|
# except CalledProcessError:
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
if ipv6_method in ('disabled', 'ignore'):
|
# if ipv6_method in ('disabled', 'ignore'):
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
subprocess.run(('dbus-send', '--system', '--print-reply', '--dest=org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager', 'org.freedesktop.DBus.Properties.Set', 'string:org.freedesktop.NetworkManager', 'string:ConnectivityCheckEnabled', 'variant:boolean:false'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
|
# subprocess.run(('dbus-send', '--system', '--print-reply', '--dest=org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager', 'org.freedesktop.DBus.Properties.Set', 'string:org.freedesktop.NetworkManager', 'string:ConnectivityCheckEnabled', 'variant:boolean:false'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
|
||||||
except CalledProcessError:
|
# except CalledProcessError:
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
subprocess.run(('nmcli', 'connection', 'add', 'type', 'dummy', 'save', 'no', 'con-name', 'hv-ipv6-sink', 'ifname', 'hvipv6sink0', 'ipv6.method', 'manual', 'ipv6.addresses', 'fd7a:fd4b:54e3:077c::/64', 'ipv6.gateway', 'fd7a:fd4b:54e3:077c::1', 'ipv6.dns', '::1', 'ipv6.route-metric', '72'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
|
# subprocess.run(('nmcli', 'connection', 'add', 'type', 'dummy', 'save', 'no', 'con-name', 'hv-ipv6-sink', 'ifname', 'hvipv6sink0', 'ipv6.method', 'manual', 'ipv6.addresses', 'fd7a:fd4b:54e3:077c::/64', 'ipv6.gateway', 'fd7a:fd4b:54e3:077c::1', 'ipv6.dns', '::1', 'ipv6.route-metric', '72'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
|
||||||
except CalledProcessError:
|
# except CalledProcessError:
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
SystemStateController.create(profile.id)
|
# SystemStateController.create(profile.id)
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
ConnectionController.await_connection(connection_observer=connection_observer)
|
# ConnectionController.await_connection(connection_observer=connection_observer)
|
||||||
|
|
||||||
except ConnectionError:
|
# except ConnectionError:
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __with_tor_connection(*args, task: Callable[..., Any], connection_observer: Optional[ConnectionObserver] = None, **kwargs):
|
def __with_tor_connection(*args, task: Callable[..., Any], connection_observer: Optional[ConnectionObserver] = None, **kwargs):
|
||||||
|
|
@ -459,52 +460,52 @@ class ConnectionController:
|
||||||
port_number = ConnectionService.get_random_available_port_number()
|
port_number = ConnectionService.get_random_available_port_number()
|
||||||
ConnectionController.establish_tor_session_connection(port_number, connection_observer=connection_observer)
|
ConnectionController.establish_tor_session_connection(port_number, connection_observer=connection_observer)
|
||||||
|
|
||||||
ConnectionController.await_connection(port_number, connection_observer=connection_observer)
|
await_connection(port_number, connection_observer=connection_observer)
|
||||||
task_output = task(*args, proxies=ConnectionController.get_proxies(port_number), **kwargs)
|
task_output = task(*args, proxies=ConnectionController.get_proxies(port_number), **kwargs)
|
||||||
|
|
||||||
ConnectionController.terminate_tor_session_connection(port_number)
|
ConnectionController.terminate_tor_session_connection(port_number)
|
||||||
|
|
||||||
return task_output
|
return task_output
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def __test_connection(port_number: Optional[int] = None, timeout: float = 4.0):
|
# def __test_connection(port_number: Optional[int] = None, timeout: float = 4.0):
|
||||||
|
|
||||||
request_urls = [Constants.PING_URL]
|
# request_urls = [Constants.PING_URL]
|
||||||
proxies = None
|
# proxies = None
|
||||||
|
|
||||||
if os.environ.get('PING_URL') is None:
|
# if os.environ.get('PING_URL') is None:
|
||||||
|
|
||||||
request_urls.extend([
|
# request_urls.extend([
|
||||||
'https://hc1.simplifiedprivacy.net',
|
# 'https://hc1.simplifiedprivacy.net',
|
||||||
'https://hc2.simplifiedprivacy.org',
|
# 'https://hc2.simplifiedprivacy.org',
|
||||||
'https://hc3.hydraveil.net'
|
# 'https://hc3.hydraveil.net'
|
||||||
])
|
# ])
|
||||||
|
|
||||||
random.shuffle(request_urls)
|
# random.shuffle(request_urls)
|
||||||
|
|
||||||
if port_number is not None:
|
# if port_number is not None:
|
||||||
proxies = ConnectionController.get_proxies(port_number)
|
# proxies = ConnectionController.get_proxies(port_number)
|
||||||
|
|
||||||
for request_url in request_urls:
|
# for request_url in request_urls:
|
||||||
|
|
||||||
command = [
|
# command = [
|
||||||
sys.executable, '-u', '-c', 'import requests, sys\n'
|
# sys.executable, '-u', '-c', 'import requests, sys\n'
|
||||||
'try:\n'
|
# 'try:\n'
|
||||||
f' response = requests.get(\'{request_url}\', proxies={proxies}, timeout={timeout})\n'
|
# f' response = requests.get(\'{request_url}\', proxies={proxies}, timeout={timeout})\n'
|
||||||
' response.raise_for_status(); print(response.text)\n'
|
# ' response.raise_for_status(); print(response.text)\n'
|
||||||
'except requests.exceptions.RequestException:\n'
|
# 'except requests.exceptions.RequestException:\n'
|
||||||
' sys.exit(1)'
|
# ' sys.exit(1)'
|
||||||
]
|
# ]
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
|
|
||||||
_response = subprocess.check_output(command, text=True, timeout=timeout)
|
# _response = subprocess.check_output(command, text=True, timeout=timeout)
|
||||||
return None
|
# return None
|
||||||
|
|
||||||
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
|
# except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __should_renegotiate(profile: Union[SessionProfile, SystemProfile]):
|
def __should_renegotiate(profile: Union[SessionProfile, SystemProfile]):
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
from core.services.networking.systemwide.systemwide_wireguard import terminate_system_connection
|
||||||
|
from core.services.networking.general_connection_tools.testing_evaluating import system_uses_wireguard_interface
|
||||||
|
from core.services.verification.endpoint_verification import verify_wireguard_endpoint
|
||||||
|
|
||||||
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
||||||
from core.controllers.ApplicationController import ApplicationController
|
from core.controllers.ApplicationController import ApplicationController
|
||||||
from core.controllers.ApplicationVersionController import ApplicationVersionController
|
from core.controllers.ApplicationVersionController import ApplicationVersionController
|
||||||
|
|
@ -115,7 +119,7 @@ class ProfileController:
|
||||||
raise ProfileDeactivationError('The profile could not be disabled.')
|
raise ProfileDeactivationError('The profile could not be disabled.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ConnectionController.terminate_system_connection()
|
terminate_system_connection()
|
||||||
except ConnectionTerminationError:
|
except ConnectionTerminationError:
|
||||||
raise ProfileDeactivationError('The profile could not be disabled.')
|
raise ProfileDeactivationError('The profile could not be disabled.')
|
||||||
|
|
||||||
|
|
@ -177,7 +181,7 @@ class ProfileController:
|
||||||
system_state = SystemStateController.get()
|
system_state = SystemStateController.get()
|
||||||
|
|
||||||
if system_state is not None and system_state.profile_id is profile.id:
|
if system_state is not None and system_state.profile_id is profile.id:
|
||||||
return ConnectionController.system_uses_wireguard_interface()
|
return system_uses_wireguard_interface()
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -242,47 +246,47 @@ class ProfileController:
|
||||||
def has_wireguard_configuration(profile: Union[SessionProfile, SystemProfile]):
|
def has_wireguard_configuration(profile: Union[SessionProfile, SystemProfile]):
|
||||||
return profile.has_wireguard_configuration()
|
return profile.has_wireguard_configuration()
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def verify_wireguard_endpoint(profile: Union[SessionProfile, SystemProfile], ignore: tuple[type[Exception]] = ()):
|
# def verify_wireguard_endpoint(profile: Union[SessionProfile, SystemProfile], ignore: tuple[type[Exception]] = ()):
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
ProfileController.__verify_wireguard_endpoint(profile)
|
# ProfileController.__verify_wireguard_endpoint(profile)
|
||||||
|
|
||||||
except EndpointVerificationError as error:
|
# except EndpointVerificationError as error:
|
||||||
|
|
||||||
if not EndpointVerificationError in ignore:
|
# if not EndpointVerificationError in ignore:
|
||||||
|
|
||||||
profile.address_security_incident()
|
# profile.address_security_incident()
|
||||||
raise error
|
# raise error
|
||||||
|
|
||||||
@staticmethod
|
# @staticmethod
|
||||||
def __verify_wireguard_endpoint(profile: Union[SessionProfile, SystemProfile]):
|
# def __verify_wireguard_endpoint(profile: Union[SessionProfile, SystemProfile]):
|
||||||
|
|
||||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
# from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||||
import base64
|
# import base64
|
||||||
|
|
||||||
signature = profile.get_wireguard_configuration_metadata('Signature')
|
# signature = profile.get_wireguard_configuration_metadata('Signature')
|
||||||
wireguard_public_keys = profile.get_wireguard_public_keys()
|
# wireguard_public_keys = profile.get_wireguard_public_keys()
|
||||||
operator = profile.location.operator
|
# operator = profile.location.operator
|
||||||
|
|
||||||
if signature is None:
|
# if signature is None:
|
||||||
raise EndpointVerificationError('The WireGuard endpoint\'s signature could not be determined.')
|
# raise EndpointVerificationError('The WireGuard endpoint\'s signature could not be determined.')
|
||||||
|
|
||||||
if not wireguard_public_keys:
|
# if not wireguard_public_keys:
|
||||||
raise EndpointVerificationError('The WireGuard endpoint\'s public key could not be determined.')
|
# raise EndpointVerificationError('The WireGuard endpoint\'s public key could not be determined.')
|
||||||
|
|
||||||
if operator is None:
|
# if operator is None:
|
||||||
raise EndpointVerificationError('The WireGuard endpoint\'s operator could not be determined.')
|
# raise EndpointVerificationError('The WireGuard endpoint\'s operator could not be determined.')
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
|
|
||||||
operator_public_key = ed25519.Ed25519PublicKey.from_public_bytes(bytes.fromhex(operator.public_key))
|
# operator_public_key = ed25519.Ed25519PublicKey.from_public_bytes(bytes.fromhex(operator.public_key))
|
||||||
|
|
||||||
for wireguard_public_key in wireguard_public_keys:
|
# for wireguard_public_key in wireguard_public_keys:
|
||||||
operator_public_key.verify(base64.b64decode(signature), wireguard_public_key.encode('utf-8'))
|
# operator_public_key.verify(base64.b64decode(signature), wireguard_public_key.encode('utf-8'))
|
||||||
|
|
||||||
except Exception:
|
# except Exception:
|
||||||
raise EndpointVerificationError('The WireGuard endpoint could not be verified.')
|
# raise EndpointVerificationError('The WireGuard endpoint could not be verified.')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __generate_wireguard_keys():
|
def __generate_wireguard_keys():
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
from core.errors.exceptions import *
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from core.Constants import Constants
|
||||||
|
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
|
||||||
|
from core.controllers.SystemStateController import SystemStateController
|
||||||
|
from core.models.BaseProfile import ProfileType
|
||||||
|
from core.models.session.SessionProfile import SessionProfile
|
||||||
|
from core.models.system.SystemProfile import SystemProfile
|
||||||
|
from core.models.system.SystemState import SystemState
|
||||||
|
from core.observers.ConnectionObserver import ConnectionObserver
|
||||||
|
from core.services.WebServiceApiService import WebServiceApiService
|
||||||
|
from essentials.modules.TorModule import TorModule
|
||||||
|
from essentials.services.ConnectionService import ConnectionService
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import CalledProcessError
|
||||||
|
from typing import Union, Optional, Any
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def terminate_tor_connection():
|
||||||
|
|
||||||
|
tor_module = TorModule(Constants.HV_TOR_STATE_HOME)
|
||||||
|
tor_module.stop_service()
|
||||||
|
|
||||||
|
|
||||||
|
def await_network_interface():
|
||||||
|
|
||||||
|
network_interface_is_activated = False
|
||||||
|
|
||||||
|
retry_interval = .5
|
||||||
|
maximum_number_of_attempts = 10
|
||||||
|
attempt = 0
|
||||||
|
|
||||||
|
while not network_interface_is_activated and attempt < maximum_number_of_attempts:
|
||||||
|
|
||||||
|
time.sleep(retry_interval)
|
||||||
|
|
||||||
|
network_interface_is_activated = system_uses_wireguard_interface()
|
||||||
|
attempt += 1
|
||||||
|
|
||||||
|
if not network_interface_is_activated:
|
||||||
|
raise ConnectionError('The network interface could not be activated.')
|
||||||
|
|
||||||
|
|
||||||
|
def system_uses_wireguard_interface():
|
||||||
|
|
||||||
|
if shutil.which('ip') is None:
|
||||||
|
raise CommandNotFoundError('ip')
|
||||||
|
|
||||||
|
process = subprocess.Popen(('ip', 'route', 'get', '192.0.2.1'), stdout=subprocess.PIPE)
|
||||||
|
process_output = str(process.stdout.read())
|
||||||
|
|
||||||
|
return bool(re.search('dev wg', str(process_output)))
|
||||||
|
|
||||||
|
|
||||||
|
def __test_connection(port_number: Optional[int] = None, timeout: float = 4.0):
|
||||||
|
|
||||||
|
request_urls = [Constants.PING_URL]
|
||||||
|
proxies = None
|
||||||
|
|
||||||
|
if os.environ.get('PING_URL') is None:
|
||||||
|
|
||||||
|
request_urls.extend([
|
||||||
|
'https://hc1.simplifiedprivacy.net',
|
||||||
|
'https://hc2.simplifiedprivacy.org',
|
||||||
|
'https://hc3.hydraveil.net'
|
||||||
|
])
|
||||||
|
|
||||||
|
random.shuffle(request_urls)
|
||||||
|
|
||||||
|
if port_number is not None:
|
||||||
|
proxies = get_proxies(port_number)
|
||||||
|
|
||||||
|
for request_url in request_urls:
|
||||||
|
|
||||||
|
command = [
|
||||||
|
sys.executable, '-u', '-c', 'import requests, sys\n'
|
||||||
|
'try:\n'
|
||||||
|
f' response = requests.get(\'{request_url}\', proxies={proxies}, timeout={timeout})\n'
|
||||||
|
' response.raise_for_status(); print(response.text)\n'
|
||||||
|
'except requests.exceptions.RequestException:\n'
|
||||||
|
' sys.exit(1)'
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
_response = subprocess.check_output(command, text=True, timeout=timeout)
|
||||||
|
return None
|
||||||
|
|
||||||
|
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
|
||||||
|
pass
|
||||||
|
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
|
||||||
|
# Kept a duplicate in connection controller
|
||||||
|
def get_proxies(port_number: int):
|
||||||
|
|
||||||
|
return dict(
|
||||||
|
http=f'socks5h://127.0.0.1:{port_number}',
|
||||||
|
https=f'socks5h://127.0.0.1:{port_number}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def await_connection(port_number: Optional[int] = None, connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
||||||
|
if port_number is None:
|
||||||
|
await_network_interface()
|
||||||
|
|
||||||
|
for retry_count in range(Constants.MAX_CONNECTION_ATTEMPTS):
|
||||||
|
|
||||||
|
if connection_observer is not None:
|
||||||
|
|
||||||
|
connection_observer.notify('connecting', dict(
|
||||||
|
retry_interval=Constants.CONNECTION_RETRY_INTERVAL,
|
||||||
|
maximum_number_of_attempts=Constants.MAX_CONNECTION_ATTEMPTS,
|
||||||
|
attempt_count=retry_count + 1
|
||||||
|
))
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
__test_connection(port_number)
|
||||||
|
return
|
||||||
|
|
||||||
|
except ConnectionError:
|
||||||
|
|
||||||
|
time.sleep(Constants.CONNECTION_RETRY_INTERVAL)
|
||||||
|
retry_count += 1
|
||||||
|
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
136
core/services/networking/systemwide/systemwide_wireguard.py
Normal file
136
core/services/networking/systemwide/systemwide_wireguard.py
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
from core.services.networking.general_connection_tools.testing_evaluating import await_connection, system_uses_wireguard_interface, terminate_tor_connection
|
||||||
|
from core.services.verification.endpoint_verification import verify_wireguard_endpoint
|
||||||
|
|
||||||
|
from core.errors.exceptions import *
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from core.Constants import Constants
|
||||||
|
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
|
||||||
|
from core.controllers.SystemStateController import SystemStateController
|
||||||
|
from core.models.BaseProfile import ProfileType
|
||||||
|
from core.models.session.SessionProfile import SessionProfile
|
||||||
|
from core.models.system.SystemProfile import SystemProfile
|
||||||
|
from core.models.system.SystemState import SystemState
|
||||||
|
from core.observers.ConnectionObserver import ConnectionObserver
|
||||||
|
from core.services.WebServiceApiService import WebServiceApiService
|
||||||
|
from essentials.modules.TorModule import TorModule
|
||||||
|
from essentials.services.ConnectionService import ConnectionService
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import CalledProcessError
|
||||||
|
from typing import Union, Optional, Any
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
|
||||||
|
def terminate_system_connection():
|
||||||
|
|
||||||
|
if shutil.which('nmcli') is None:
|
||||||
|
raise CommandNotFoundError('nmcli')
|
||||||
|
|
||||||
|
if SystemStateController.exists():
|
||||||
|
|
||||||
|
process = subprocess.Popen(('nmcli', 'connection', 'delete', 'wg'), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||||
|
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
||||||
|
|
||||||
|
if completed_successfully or not system_uses_wireguard_interface():
|
||||||
|
|
||||||
|
subprocess.run(('nmcli', 'connection', 'delete', 'hv-ipv6-sink'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
|
terminate_tor_connection()
|
||||||
|
SystemState.dissolve()
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ConnectionTerminationError('The connection could not be terminated.')
|
||||||
|
|
||||||
|
|
||||||
|
def __establish_system_connection(profile: SystemProfile, connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
||||||
|
if shutil.which('dbus-send') is None:
|
||||||
|
raise CommandNotFoundError('dbus-send')
|
||||||
|
|
||||||
|
if shutil.which('nmcli') is None:
|
||||||
|
raise CommandNotFoundError('nmcli')
|
||||||
|
|
||||||
|
terminate_system_connection()
|
||||||
|
|
||||||
|
try:
|
||||||
|
process_output = subprocess.check_output(('nmcli', 'connection', 'import', '--temporary', 'type', 'wireguard', 'file', profile.get_wireguard_configuration_path()), text=True)
|
||||||
|
except CalledProcessError:
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
connection_id = (m := re.search(r'(?<=\()([a-f0-9-]+?)(?=\))', process_output)) and m.group(1)
|
||||||
|
ipv6_method = subprocess.check_output(('nmcli', '-g', 'ipv6.method', 'connection', 'show', connection_id), text=True).strip()
|
||||||
|
|
||||||
|
except CalledProcessError:
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
if ipv6_method in ('disabled', 'ignore'):
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(('dbus-send', '--system', '--print-reply', '--dest=org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager', 'org.freedesktop.DBus.Properties.Set', 'string:org.freedesktop.NetworkManager', 'string:ConnectivityCheckEnabled', 'variant:boolean:false'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
|
||||||
|
except CalledProcessError:
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(('nmcli', 'connection', 'add', 'type', 'dummy', 'save', 'no', 'con-name', 'hv-ipv6-sink', 'ifname', 'hvipv6sink0', 'ipv6.method', 'manual', 'ipv6.addresses', 'fd7a:fd4b:54e3:077c::/64', 'ipv6.gateway', 'fd7a:fd4b:54e3:077c::1', 'ipv6.dns', '::1', 'ipv6.route-metric', '72'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
|
||||||
|
except CalledProcessError:
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
SystemStateController.create(profile.id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await_connection(connection_observer=connection_observer)
|
||||||
|
|
||||||
|
except ConnectionError:
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def establish_system_connection(profile: SystemProfile, ignore: tuple[type[Exception]] = (), connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
|
||||||
|
if ConfigurationController.get_endpoint_verification_enabled():
|
||||||
|
verify_wireguard_endpoint(profile, ignore=ignore)
|
||||||
|
|
||||||
|
try:
|
||||||
|
__establish_system_connection(profile, connection_observer)
|
||||||
|
|
||||||
|
except ConnectionError:
|
||||||
|
|
||||||
|
try:
|
||||||
|
terminate_system_connection()
|
||||||
|
except ConnectionTerminationError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
except CalledProcessError:
|
||||||
|
|
||||||
|
try:
|
||||||
|
terminate_system_connection()
|
||||||
|
except ConnectionTerminationError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
__establish_system_connection(profile, connection_observer)
|
||||||
|
|
||||||
|
except (ConnectionError, CalledProcessError):
|
||||||
|
|
||||||
|
try:
|
||||||
|
terminate_system_connection()
|
||||||
|
except ConnectionTerminationError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
terminate_tor_connection()
|
||||||
|
time.sleep(1.0)
|
||||||
48
core/services/verification/endpoint_verification.py
Normal file
48
core/services/verification/endpoint_verification.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
from core.models.session.SessionProfile import SessionProfile
|
||||||
|
from core.models.system.SystemProfile import SystemProfile
|
||||||
|
from core.models.BaseProfile import BaseProfile as Profile
|
||||||
|
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
||||||
|
from typing import Union, Optional
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
|
def verify_wireguard_endpoint(profile: Union[SessionProfile, SystemProfile], ignore: tuple[type[Exception]] = ()):
|
||||||
|
|
||||||
|
try:
|
||||||
|
__verify_wireguard_endpoint(profile)
|
||||||
|
|
||||||
|
except EndpointVerificationError as error:
|
||||||
|
|
||||||
|
if not EndpointVerificationError in ignore:
|
||||||
|
|
||||||
|
profile.address_security_incident()
|
||||||
|
raise error
|
||||||
|
|
||||||
|
def __verify_wireguard_endpoint(profile: Union[SessionProfile, SystemProfile]):
|
||||||
|
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||||
|
import base64
|
||||||
|
|
||||||
|
signature = profile.get_wireguard_configuration_metadata('Signature')
|
||||||
|
wireguard_public_keys = profile.get_wireguard_public_keys()
|
||||||
|
operator = profile.location.operator
|
||||||
|
|
||||||
|
if signature is None:
|
||||||
|
raise EndpointVerificationError('The WireGuard endpoint\'s signature could not be determined.')
|
||||||
|
|
||||||
|
if not wireguard_public_keys:
|
||||||
|
raise EndpointVerificationError('The WireGuard endpoint\'s public key could not be determined.')
|
||||||
|
|
||||||
|
if operator is None:
|
||||||
|
raise EndpointVerificationError('The WireGuard endpoint\'s operator could not be determined.')
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
operator_public_key = ed25519.Ed25519PublicKey.from_public_bytes(bytes.fromhex(operator.public_key))
|
||||||
|
|
||||||
|
for wireguard_public_key in wireguard_public_keys:
|
||||||
|
operator_public_key.verify(base64.b64decode(signature), wireguard_public_key.encode('utf-8'))
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
raise EndpointVerificationError('The WireGuard endpoint could not be verified.')
|
||||||
|
|
||||||
Loading…
Reference in a new issue