Surgery on ConnectionController! Huge separation of ConnectionController & ProfileController into naked function modules for enabling a connection, registering wireguard keys, coordinating proxy configs, subscriptions, endpoint verification, and the logistical flow. Additionally enums were used for type checking, instead of polymorphic functions. This version is stable and confirmed working for systemwide and session wireguard, but not yet proxies.
This commit is contained in:
parent
9740e0f53b
commit
2ccbdba06b
10 changed files with 375 additions and 129 deletions
|
|
@ -1,5 +1,11 @@
|
|||
# Major Change Log:
|
||||
|
||||
|
||||
# 2.4.2
|
||||
### Surgery on ConnectionController
|
||||
Huge separation of ConnectionController & ProfileController into naked function modules for enabling a connection, registering wireguard keys, coordinating proxy configs, subscriptions, endpoint verification, and the logistical flow. Additionally enums were used for type checking, instead of polymorphic functions. This version is stable and confirmed working for systemwide and session wireguard, but not yet proxies.
|
||||
<br/>
|
||||
|
||||
# 2.4.1
|
||||
### Enums for Profile types.
|
||||
July 18, 2026
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ 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 core.services.keys_and_verifications.endpoint_verification import verify_wireguard_endpoint
|
||||
|
||||
|
||||
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.ProfileController import ProfileController
|
||||
from core.controllers.SessionStateController import SessionStateController
|
||||
from core.controllers.SystemStateController import SystemStateController
|
||||
from core.models.BaseProfile import ProfileType
|
||||
|
|
@ -60,86 +60,87 @@ class ConnectionController:
|
|||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def establish_connection(profile: Union[SessionProfile, SystemProfile], ignore: tuple[type[Exception]] = (), connection_observer: Optional[ConnectionObserver] = None):
|
||||
# @staticmethod
|
||||
# def establish_connection(profile: Union[SessionProfile, SystemProfile], ignore: tuple[type[Exception]] = (), connection_observer: Optional[ConnectionObserver] = None):
|
||||
|
||||
connection = profile.connection
|
||||
# connection = profile.connection
|
||||
|
||||
# needs_proxy_configuration comes from the child connection models
|
||||
# for the system it returns false blindly. for the session is checks if the connection type is masked.
|
||||
# if connection.masked and not profile.has_proxy_configuration():
|
||||
if connection.needs_proxy_configuration() and not profile.has_proxy_configuration():
|
||||
# # needs_proxy_configuration comes from the child connection models
|
||||
# # for the system it returns false blindly. for the session is checks if the connection type is masked.
|
||||
# # if connection.masked and not profile.has_proxy_configuration():
|
||||
# if connection.needs_proxy_configuration() and not profile.has_proxy_configuration():
|
||||
|
||||
if profile.has_subscription():
|
||||
# if profile.has_subscription():
|
||||
|
||||
if not profile.subscription.has_been_activated():
|
||||
ProfileController.activate_subscription(profile, connection_observer=connection_observer)
|
||||
# if not profile.subscription.has_been_activated():
|
||||
# ProfileController.activate_subscription(profile, connection_observer=connection_observer)
|
||||
|
||||
proxy_configuration = ConnectionController.with_preferred_connection(profile.subscription.billing_code, task=WebServiceApiService.get_proxy_configuration, connection_observer=connection_observer)
|
||||
# proxy_configuration = ConnectionController.with_preferred_connection(profile.subscription.billing_code, task=WebServiceApiService.get_proxy_configuration, connection_observer=connection_observer)
|
||||
|
||||
if proxy_configuration is None:
|
||||
raise InvalidSubscriptionError()
|
||||
# if proxy_configuration is None:
|
||||
# raise InvalidSubscriptionError()
|
||||
|
||||
profile.attach_proxy_configuration(proxy_configuration)
|
||||
# profile.attach_proxy_configuration(proxy_configuration)
|
||||
|
||||
else:
|
||||
raise MissingSubscriptionError()
|
||||
# else:
|
||||
# raise MissingSubscriptionError()
|
||||
|
||||
# The needs_wireguard_configuration comes from the connection model, and can be transitioned to get it directly from the object's data
|
||||
# The has_wireguard_configuration comes from each polymorph object doing an os check on if the wg config exists
|
||||
if connection.needs_wireguard_configuration() and not profile.has_wireguard_configuration():
|
||||
# # The needs_wireguard_configuration comes from the connection model,
|
||||
# # and can be transitioned to get it directly from the object's data
|
||||
# # The has_wireguard_configuration comes from each polymorph object doing an os check on if the wg config exists
|
||||
# if connection.needs_wireguard_configuration() and not profile.has_wireguard_configuration():
|
||||
|
||||
if profile.has_subscription():
|
||||
# if profile.has_subscription():
|
||||
|
||||
if not profile.subscription.has_been_activated():
|
||||
ProfileController.activate_subscription(profile, connection_observer=connection_observer)
|
||||
# if not profile.subscription.has_been_activated():
|
||||
# ProfileController.activate_subscription(profile, connection_observer=connection_observer)
|
||||
|
||||
ProfileController.register_wireguard_session(profile, connection_observer=connection_observer)
|
||||
# ProfileController.register_wireguard_session(profile, connection_observer=connection_observer)
|
||||
|
||||
else:
|
||||
# else:
|
||||
|
||||
if profile.is_system_profile():
|
||||
# if profile.is_system_profile():
|
||||
|
||||
if system_uses_wireguard_interface() and SystemStateController.exists():
|
||||
# if system_uses_wireguard_interface() and SystemStateController.exists():
|
||||
|
||||
try:
|
||||
terminate_system_connection()
|
||||
except ConnectionTerminationError:
|
||||
pass
|
||||
# try:
|
||||
# terminate_system_connection()
|
||||
# except ConnectionTerminationError:
|
||||
# pass
|
||||
|
||||
raise MissingSubscriptionError()
|
||||
# raise MissingSubscriptionError()
|
||||
|
||||
if profile.is_session_profile():
|
||||
# if profile.is_session_profile():
|
||||
|
||||
try:
|
||||
return ConnectionController.establish_session_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
# try:
|
||||
# return ConnectionController.establish_session_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)
|
||||
return ConnectionController.establish_session_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
# ProfileController.register_wireguard_session(profile, connection_observer=connection_observer)
|
||||
# return ConnectionController.establish_session_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
|
||||
else:
|
||||
raise ConnectionError('The connection could not be established.')
|
||||
# else:
|
||||
# raise ConnectionError('The connection could not be established.')
|
||||
|
||||
if profile.is_system_profile():
|
||||
# if profile.is_system_profile():
|
||||
|
||||
try:
|
||||
return establish_system_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
# try:
|
||||
# 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)
|
||||
return establish_system_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
# ProfileController.register_wireguard_session(profile, connection_observer=connection_observer)
|
||||
# return establish_system_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
|
||||
else:
|
||||
raise ConnectionError('The connection could not be established.')
|
||||
# else:
|
||||
# raise ConnectionError('The connection could not be established.')
|
||||
|
||||
return None
|
||||
# return None
|
||||
|
||||
@staticmethod
|
||||
def establish_session_connection(profile: SessionProfile, ignore: tuple[type[Exception]] = (), connection_observer: Optional[ConnectionObserver] = None):
|
||||
|
|
@ -158,6 +159,7 @@ class ConnectionController:
|
|||
if not ConnectionUnprotectedError in ignore:
|
||||
raise ConnectionUnprotectedError('Connection unprotected while the system is not using a WireGuard interface.')
|
||||
else:
|
||||
from core.controllers.ProfileController import ProfileController
|
||||
ProfileController.disable(profile)
|
||||
|
||||
if profile.connection.code == 'tor':
|
||||
|
|
@ -509,15 +511,15 @@ class ConnectionController:
|
|||
|
||||
# raise ConnectionError('The connection could not be established.')
|
||||
|
||||
@staticmethod
|
||||
def __should_renegotiate(profile: Union[SessionProfile, SystemProfile]):
|
||||
# @staticmethod
|
||||
# def __should_renegotiate(profile: Union[SessionProfile, SystemProfile]):
|
||||
|
||||
if not profile.has_subscription():
|
||||
raise MissingSubscriptionError()
|
||||
# if not profile.has_subscription():
|
||||
# raise MissingSubscriptionError()
|
||||
|
||||
if profile.connection.needs_wireguard_configuration() and profile.has_wireguard_configuration():
|
||||
# if profile.connection.needs_wireguard_configuration() and profile.has_wireguard_configuration():
|
||||
|
||||
if profile.subscription.has_been_activated():
|
||||
return True
|
||||
# if profile.subscription.has_been_activated():
|
||||
# return True
|
||||
|
||||
return False
|
||||
# return False
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
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.services.networking.general_connection_tools.connection_enable import establish_connection
|
||||
|
||||
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
||||
from core.controllers.ApplicationController import ApplicationController
|
||||
|
|
@ -41,20 +41,31 @@ class ProfileController:
|
|||
|
||||
|
||||
@staticmethod
|
||||
def enable(profile: Union[SessionProfile, SystemProfile], ignore: tuple[type[Exception]] = (), pristine: bool = False, asynchronous: bool = False, profile_observer: ProfileObserver = None, application_version_observer: ApplicationVersionObserver = None, connection_observer: ConnectionObserver = None):
|
||||
def enable(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
ignore: tuple[type[Exception]] = (),
|
||||
pristine: bool = False,
|
||||
asynchronous: bool = False,
|
||||
profile_observer: ProfileObserver = None,
|
||||
application_version_observer: ApplicationVersionObserver = None,
|
||||
connection_observer: ConnectionObserver = None):
|
||||
|
||||
from core.controllers.ConnectionController import ConnectionController
|
||||
|
||||
# =========== ALREADY ENABLED ============
|
||||
if ProfileController.is_enabled(profile):
|
||||
|
||||
if not ProfileStateConflictError in ignore:
|
||||
raise ProfileStateConflictError('The profile is already enabled or its session was not properly terminated.')
|
||||
else:
|
||||
ProfileController.disable(profile)
|
||||
|
||||
# =========== PRISTINE ============
|
||||
if pristine:
|
||||
profile.delete_data()
|
||||
|
||||
# ============================================================================
|
||||
# SESSION
|
||||
# ============================================================================
|
||||
if profile.is_session_profile():
|
||||
|
||||
application_version = profile.application_version
|
||||
|
|
@ -63,7 +74,7 @@ class ProfileController:
|
|||
ApplicationVersionController.install(application_version, application_version_observer=application_version_observer, connection_observer=connection_observer)
|
||||
|
||||
try:
|
||||
port_number = ConnectionController.establish_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
port_number = establish_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
except ConnectionError:
|
||||
raise ProfileActivationError('The profile could not be enabled.')
|
||||
|
||||
|
|
@ -72,10 +83,12 @@ class ProfileController:
|
|||
|
||||
ApplicationController.launch(application_version, profile, port_number, asynchronous=asynchronous, profile_observer=profile_observer)
|
||||
|
||||
# ============================================================================
|
||||
# SYSTEMWIDE
|
||||
# ============================================================================
|
||||
if profile.is_system_profile():
|
||||
|
||||
try:
|
||||
ConnectionController.establish_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
establish_connection(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
except ConnectionError:
|
||||
raise ProfileActivationError('The profile could not be enabled.')
|
||||
|
||||
|
|
@ -215,28 +228,28 @@ class ProfileController:
|
|||
def has_proxy_configuration(profile: Union[SessionProfile, SystemProfile]):
|
||||
profile.has_proxy_configuration()
|
||||
|
||||
@staticmethod
|
||||
def register_wireguard_session(profile: Union[SessionProfile, SystemProfile], connection_observer: Optional[ConnectionObserver] = None):
|
||||
# @staticmethod
|
||||
# def register_wireguard_session(profile: Union[SessionProfile, SystemProfile], connection_observer: Optional[ConnectionObserver] = None):
|
||||
|
||||
from core.controllers.ConnectionController import ConnectionController
|
||||
# from core.controllers.ConnectionController import ConnectionController
|
||||
|
||||
if not profile.has_subscription():
|
||||
raise MissingSubscriptionError()
|
||||
# if not profile.has_subscription():
|
||||
# raise MissingSubscriptionError()
|
||||
|
||||
if not profile.has_location():
|
||||
raise MissingLocationError()
|
||||
# if not profile.has_location():
|
||||
# raise MissingLocationError()
|
||||
|
||||
wireguard_keys = ProfileController.__generate_wireguard_keys()
|
||||
# wireguard_keys = ProfileController.__generate_wireguard_keys()
|
||||
|
||||
wireguard_configuration = ConnectionController.with_preferred_connection(profile.location.country_code, profile.location.code, profile.subscription.billing_code, wireguard_keys.get('public'), task=WebServiceApiService.post_wireguard_session, connection_observer=connection_observer)
|
||||
# wireguard_configuration = ConnectionController.with_preferred_connection(profile.location.country_code, profile.location.code, profile.subscription.billing_code, wireguard_keys.get('public'), task=WebServiceApiService.post_wireguard_session, connection_observer=connection_observer)
|
||||
|
||||
if wireguard_configuration is None:
|
||||
raise InvalidSubscriptionError()
|
||||
# if wireguard_configuration is None:
|
||||
# raise InvalidSubscriptionError()
|
||||
|
||||
expression = re.compile(r'^(PrivateKey =)\s?$', re.MULTILINE)
|
||||
wireguard_configuration = re.sub(expression, r'\1 ' + wireguard_keys.get('private'), wireguard_configuration)
|
||||
# expression = re.compile(r'^(PrivateKey =)\s?$', re.MULTILINE)
|
||||
# wireguard_configuration = re.sub(expression, r'\1 ' + wireguard_keys.get('private'), wireguard_configuration)
|
||||
|
||||
profile.attach_wireguard_configuration(wireguard_configuration)
|
||||
# profile.attach_wireguard_configuration(wireguard_configuration)
|
||||
|
||||
@staticmethod
|
||||
def get_wireguard_configuration_path(profile: Union[SessionProfile, SystemProfile]):
|
||||
|
|
@ -288,23 +301,23 @@ class ProfileController:
|
|||
# except Exception:
|
||||
# raise EndpointVerificationError('The WireGuard endpoint could not be verified.')
|
||||
|
||||
@staticmethod
|
||||
def __generate_wireguard_keys():
|
||||
# @staticmethod
|
||||
# def __generate_wireguard_keys():
|
||||
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
|
||||
# from cryptography.hazmat.primitives import serialization
|
||||
# from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
|
||||
|
||||
raw_private_key = X25519PrivateKey.generate()
|
||||
# raw_private_key = X25519PrivateKey.generate()
|
||||
|
||||
public_key = raw_private_key.public_key().public_bytes(
|
||||
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
|
||||
)
|
||||
# public_key = raw_private_key.public_key().public_bytes(
|
||||
# encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
|
||||
# )
|
||||
|
||||
private_key = raw_private_key.private_bytes(
|
||||
encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption()
|
||||
)
|
||||
# private_key = raw_private_key.private_bytes(
|
||||
# encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption()
|
||||
# )
|
||||
|
||||
return dict(
|
||||
private=base64.b64encode(private_key).decode(),
|
||||
public=base64.b64encode(public_key).decode()
|
||||
)
|
||||
# return dict(
|
||||
# private=base64.b64encode(private_key).decode(),
|
||||
# public=base64.b64encode(public_key).decode()
|
||||
# )
|
||||
|
|
|
|||
66
core/services/keys_and_verifications/wireguard_keys.py
Normal file
66
core/services/keys_and_verifications/wireguard_keys.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
from core.models.session.SessionProfile import SessionProfile
|
||||
from core.models.system.SystemProfile import SystemProfile
|
||||
from core.Errors import MissingSubscriptionError, MissingLocationError, InvalidSubscriptionError
|
||||
from core.services.WebServiceApiService import WebServiceApiService
|
||||
from core.controllers.ConnectionController import ConnectionController
|
||||
from core.observers.ConnectionObserver import ConnectionObserver
|
||||
from typing import Union, Optional
|
||||
import base64
|
||||
import re
|
||||
|
||||
def register_wireguard_session(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
connection_observer: Optional[ConnectionObserver] = None
|
||||
):
|
||||
"""Register a WireGuard session for the given profile."""
|
||||
|
||||
if not profile.has_subscription():
|
||||
raise MissingSubscriptionError()
|
||||
|
||||
if not profile.has_location():
|
||||
raise MissingLocationError()
|
||||
|
||||
wireguard_keys = _generate_wireguard_keys()
|
||||
|
||||
wireguard_configuration = ConnectionController.with_preferred_connection(
|
||||
profile.location.country_code,
|
||||
profile.location.code,
|
||||
profile.subscription.billing_code,
|
||||
wireguard_keys.get('public'),
|
||||
task=WebServiceApiService.post_wireguard_session,
|
||||
connection_observer=connection_observer
|
||||
)
|
||||
|
||||
if wireguard_configuration is None:
|
||||
raise InvalidSubscriptionError()
|
||||
|
||||
wireguard_configuration = _inject_private_key(wireguard_configuration, wireguard_keys.get('private'))
|
||||
profile.attach_wireguard_configuration(wireguard_configuration)
|
||||
|
||||
|
||||
def _generate_wireguard_keys() -> dict:
|
||||
"""Generate WireGuard public/private key pair."""
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
|
||||
|
||||
raw_private_key = X25519PrivateKey.generate()
|
||||
|
||||
public_key = raw_private_key.public_key().public_bytes(
|
||||
encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
|
||||
)
|
||||
|
||||
private_key = raw_private_key.private_bytes(
|
||||
encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption()
|
||||
)
|
||||
|
||||
return dict(
|
||||
private=base64.b64encode(private_key).decode(),
|
||||
public=base64.b64encode(public_key).decode()
|
||||
)
|
||||
|
||||
|
||||
def _inject_private_key(config: str, private_key: str) -> str:
|
||||
"""Inject private key into WireGuard config."""
|
||||
expression = re.compile(r'^(PrivateKey =)\s?$', re.MULTILINE)
|
||||
return re.sub(expression, r'\1 ' + private_key, config)
|
||||
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
from core.services.networking.general_connection_tools.testing_evaluating import system_uses_wireguard_interface
|
||||
from core.services.networking.systemwide.systemwide_wireguard import establish_system_connection, terminate_system_connection
|
||||
from core.services.keys_and_verifications.wireguard_keys import register_wireguard_session
|
||||
from core.models.session.SessionConnection import SessionConnectionTypes
|
||||
from core.models.system.SystemConnection import SystemConnectionTypes
|
||||
|
||||
from core.errors.logger import logger
|
||||
from core.errors.exceptions import *
|
||||
from typing import Union, Optional, Callable
|
||||
from core.models.session.SessionProfile import SessionProfile
|
||||
from core.models.system.SystemProfile import SystemProfile
|
||||
from core.Errors import ConnectionTerminationError, InvalidSubscriptionError
|
||||
from core.services.WebServiceApiService import WebServiceApiService
|
||||
from core.controllers.ConnectionController import ConnectionController
|
||||
from core.models.BaseProfile import ProfileType
|
||||
from core.services.subscriptions.subscriptions import activate_subscription
|
||||
from core.observers.ConnectionObserver import ConnectionObserver
|
||||
from core.controllers.SystemStateController import SystemStateController
|
||||
|
||||
wireguard_types = [SystemConnectionTypes.WIREGUARD, SessionConnectionTypes.WIREGUARD]
|
||||
|
||||
def establish_connection(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
ignore: tuple[type[Exception]] = (),
|
||||
connection_observer: Optional[ConnectionObserver] = None,
|
||||
):
|
||||
"""Establish a connection for the given profile."""
|
||||
|
||||
logger.info(f"[CONNECTION] Checking subscription..")
|
||||
_ensure_subscription_ready(profile, connection_observer)
|
||||
|
||||
logger.info(f"[CONNECTION] Checking proxy configuration..")
|
||||
_ensure_proxy_configured(profile, connection_observer)
|
||||
|
||||
logger.info(f"[CONNECTION] Checking Wireguard configuration..")
|
||||
_ensure_wireguard_configured(profile, connection_observer)
|
||||
|
||||
establish_fn = {
|
||||
ProfileType.SESSION: ConnectionController.establish_session_connection,
|
||||
ProfileType.SYSTEM: establish_system_connection,
|
||||
}[profile.type]
|
||||
|
||||
return _establish_with_renegotiation(profile, establish_fn, ignore, connection_observer)
|
||||
|
||||
|
||||
def _ensure_subscription_ready(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
connection_observer: Optional[ConnectionObserver],
|
||||
):
|
||||
"""Activate subscription (idempotent)."""
|
||||
activate_subscription(profile, connection_observer=connection_observer)
|
||||
|
||||
|
||||
def _ensure_proxy_configured(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
connection_observer: Optional[ConnectionObserver],
|
||||
):
|
||||
"""Setup proxy config if needed."""
|
||||
if not profile.connection.needs_proxy_configuration():
|
||||
return
|
||||
|
||||
_ensure_subscription_ready(profile, connection_observer)
|
||||
|
||||
proxy_config = ConnectionController.with_preferred_connection(
|
||||
profile.subscription.billing_code,
|
||||
task=WebServiceApiService.get_proxy_configuration,
|
||||
connection_observer=connection_observer
|
||||
)
|
||||
|
||||
if proxy_config is None:
|
||||
raise InvalidSubscriptionError()
|
||||
|
||||
profile.attach_proxy_configuration(proxy_config)
|
||||
|
||||
|
||||
def _ensure_wireguard_configured(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
connection_observer: Optional[ConnectionObserver],
|
||||
):
|
||||
"""Setup WireGuard config if needed."""
|
||||
|
||||
logger.info(f"[CONNECTION] Checking if this profile needs a wg config. The profile.connection.code is {profile.connection.code}")
|
||||
if profile.connection.code not in wireguard_types:
|
||||
logger.info(f"[CONNECTION] This profile {profile.id} does NOT need a wireguard config")
|
||||
return
|
||||
|
||||
if profile.type == ProfileType.SYSTEM:
|
||||
if system_uses_wireguard_interface() and SystemStateController.exists():
|
||||
logger.info(f"[CONNECTION] There is a systemwide profile that is already is active.")
|
||||
try:
|
||||
terminate_system_connection()
|
||||
except ConnectionTerminationError as e:
|
||||
logger.error(f"[CONNECTION] Previous Systemwide Wireguard connection could not be disabled. {e}")
|
||||
|
||||
_ensure_subscription_ready(profile, connection_observer)
|
||||
logger.info(f"[CONNECTION] Checking if the profile already has a wg config..")
|
||||
if not profile.has_wireguard_configuration():
|
||||
logger.info(f"[CONNECTION] Profile does NOT have WG keys and it needs it. Registering a NEW wg session..")
|
||||
register_wireguard_session(profile, connection_observer=connection_observer)
|
||||
|
||||
|
||||
def _establish_with_renegotiation(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
establish_fn: Callable,
|
||||
ignore: tuple[type[Exception]],
|
||||
connection_observer: Optional[ConnectionObserver],
|
||||
):
|
||||
"""Attempt connection, renegotiate WireGuard once if needed."""
|
||||
try:
|
||||
logger.info(f"[CONNECTION] Connecting..")
|
||||
return establish_fn(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
except ConnectionError:
|
||||
if __should_renegotiate(profile):
|
||||
logger.info(f"[CONNECTION] Renegotiating a new wg key session with API..")
|
||||
register_wireguard_session(profile, connection_observer=connection_observer)
|
||||
return establish_fn(profile, ignore=ignore, connection_observer=connection_observer)
|
||||
raise ConnectionError('The connection could not be established.')
|
||||
|
||||
|
||||
def __should_renegotiate(profile: Union[SessionProfile, SystemProfile]):
|
||||
|
||||
if not profile.has_subscription():
|
||||
raise MissingSubscriptionError()
|
||||
|
||||
if profile.connection.code in wireguard_types and profile.has_wireguard_configuration():
|
||||
if profile.subscription.has_been_activated():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
@ -1,23 +1,7 @@
|
|||
# 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 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 Optional
|
||||
import os
|
||||
import random
|
||||
|
|
@ -25,7 +9,6 @@ import re
|
|||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
# import tempfile
|
||||
import time
|
||||
|
||||
|
||||
|
|
@ -105,7 +88,7 @@ def __test_connection(port_number: Optional[int] = None, timeout: float = 4.0):
|
|||
raise ConnectionError('The connection could not be established.')
|
||||
|
||||
|
||||
# Kept a duplicate in connection controller
|
||||
# Kept a duplicate in connection controller, because Tor uses it. and circular imports are an issue for now. Refactor later.
|
||||
def get_proxies(port_number: int):
|
||||
|
||||
return dict(
|
||||
|
|
|
|||
|
|
@ -1,35 +1,21 @@
|
|||
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.services.keys_and_verifications.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 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 Optional
|
||||
import os
|
||||
# import random
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
# import sys
|
||||
# import tempfile
|
||||
import time
|
||||
|
||||
def terminate_system_connection():
|
||||
|
|
|
|||
61
core/services/subscriptions/subscriptions.py
Normal file
61
core/services/subscriptions/subscriptions.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
from typing import Union, Optional
|
||||
from core.models.session.SessionProfile import SessionProfile
|
||||
from core.models.system.SystemProfile import SystemProfile
|
||||
from core.Errors import MissingSubscriptionError, InvalidSubscriptionError
|
||||
from core.services.WebServiceApiService import WebServiceApiService
|
||||
from core.controllers.ConnectionController import ConnectionController
|
||||
from core.observers.ConnectionObserver import ConnectionObserver
|
||||
|
||||
def activate_subscription(
|
||||
profile: Union[SessionProfile, SystemProfile],
|
||||
connection_observer: Optional[ConnectionObserver] = None
|
||||
) -> bool:
|
||||
"""
|
||||
Purpose:
|
||||
Ensure subscription is ready.
|
||||
|
||||
Features:
|
||||
Idempotent.
|
||||
Checks local first
|
||||
|
||||
Confusion:
|
||||
This returns True both if was already active or just activated.
|
||||
|
||||
Returns:
|
||||
Returns True if subscription was already active.
|
||||
Returns True if subscription was just activated.
|
||||
|
||||
Errors:
|
||||
True.
|
||||
Raises if subscription is missing or invalid. (not false)
|
||||
"""
|
||||
|
||||
if not profile.has_subscription():
|
||||
raise MissingSubscriptionError()
|
||||
|
||||
# Already activated—nothing to do
|
||||
if profile.subscription.has_been_activated():
|
||||
return True
|
||||
|
||||
# Fetch and activate
|
||||
subscription = ConnectionController.with_preferred_connection(
|
||||
profile.subscription.billing_code,
|
||||
task=WebServiceApiService.get_subscription,
|
||||
connection_observer=connection_observer
|
||||
)
|
||||
|
||||
if subscription is None:
|
||||
raise InvalidSubscriptionError()
|
||||
|
||||
profile.subscription = subscription
|
||||
profile.save()
|
||||
return True
|
||||
|
||||
|
||||
def is_subscription_ready(profile: Union[SessionProfile, SystemProfile]) -> bool:
|
||||
"""Check if subscription exists and is activated (no side effects)."""
|
||||
return (
|
||||
profile.has_subscription()
|
||||
and profile.subscription.has_been_activated()
|
||||
)
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "sp-hydra-veil-core"
|
||||
version = "2.4.1"
|
||||
version = "2.4.2"
|
||||
authors = [
|
||||
{ name = "Simplified Privacy" },
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue