From d35fc0db4b978c727b9c22342e49fd226f2488c6 Mon Sep 17 00:00:00 2001 From: SimplifiedPrivacy Date: Mon, 21 Sep 2026 12:35:37 -0400 Subject: [PATCH] Bug fixes and tweaks for transitions --- broken_pipe_test.py | 3 -- .../tickets/UseTicketController.py | 2 +- core/models/manage/denormalize.py | 6 +++- core/services/networking/httpx/endpoints.py | 2 +- .../encrypted_proxy/close_singbox.py | 4 +++ .../encrypted_proxy/configure_singbox.py | 7 ++-- .../encrypted_proxy/singbox_runner.py | 32 +++++++++++++------ core/services/subscriptions/subscriptions.py | 2 ++ core/services/sync/sync_service.py | 16 ++++++---- .../using_tickets/use_ticket_orchestrator.py | 1 + 10 files changed, 51 insertions(+), 24 deletions(-) delete mode 100644 broken_pipe_test.py diff --git a/broken_pipe_test.py b/broken_pipe_test.py deleted file mode 100644 index d4608b2..0000000 --- a/broken_pipe_test.py +++ /dev/null @@ -1,3 +0,0 @@ -from core.utils.run_commands import test_broken_pipe_on_process_death - -test_broken_pipe_on_process_death() diff --git a/core/controllers/tickets/UseTicketController.py b/core/controllers/tickets/UseTicketController.py index cb1aac3..9d4f3da 100644 --- a/core/controllers/tickets/UseTicketController.py +++ b/core/controllers/tickets/UseTicketController.py @@ -8,7 +8,7 @@ if TYPE_CHECKING: from core.Constants import Constants # from core.observers.BaseObserver import BaseObserver from core.services.using_tickets.use_ticket_orchestrator import use_ticket_orchestrator - +from core.models.Result import Result, ResultError from core.services.prepare_tickets.ticket_tracker import does_ticket_tracker_exist # from core.services.prepare_tickets import setup_ticket_tracker diff --git a/core/models/manage/denormalize.py b/core/models/manage/denormalize.py index c6e3f4c..309cb71 100644 --- a/core/models/manage/denormalize.py +++ b/core/models/manage/denormalize.py @@ -52,7 +52,11 @@ def denormalize(data, mapping_file): extract_from_nested - This function checks it's actually a dictionary and extracts it """ value = extract_from_nested(each_item, field['path']) - + + # If nested path didn't work, try using the field name as a flat key + if value is None: + value = each_item.get(field['name']) + # Store the extracted value. If it wasn't there, then it's None each_denormalized_piece[field['name']] = value diff --git a/core/services/networking/httpx/endpoints.py b/core/services/networking/httpx/endpoints.py index baa57aa..4712ef9 100644 --- a/core/services/networking/httpx/endpoints.py +++ b/core/services/networking/httpx/endpoints.py @@ -8,7 +8,7 @@ def switch_endpoint_domain(domain: str) -> dict: "operators": f"https://{domain}/api/v1/operators", "client_version": f"https://{domain}/api/v1/platforms/linux-x86_64/appimage/client-versions", "subscriptions": f"https://{domain}/api/v1/subscription-plans", - "applications": f"https://{domain}/api/v1/platforms/linux-x86_64/applications", + # "applications": f"https://{domain}/api/v1/platforms/linux-x86_64/applications", "application_versions": f"https://{domain}/api/v1/platforms/linux-x86_64/application-versions", "dependencies": f"https://{domain}/api/v1/dependencies" } diff --git a/core/services/networking/systemwide/encrypted_proxy/close_singbox.py b/core/services/networking/systemwide/encrypted_proxy/close_singbox.py index e14ac52..617a6b8 100644 --- a/core/services/networking/systemwide/encrypted_proxy/close_singbox.py +++ b/core/services/networking/systemwide/encrypted_proxy/close_singbox.py @@ -161,8 +161,12 @@ def orchestrate_closing(current_state: SystemState, interface: str) -> Result: for strategy in strategies: result = _try_with_permission_fallback(strategy, interface) if result.valid: + # remove state json: + SystemState.dissolve() return result if not interface_tools.exists(interface): + # remove state json: + SystemState.dissolve() return Result(valid=True, message="Tunnel inactive despite strategy failure") return Result(valid=False, message=f"All {quantity_of_strategies} strategies tried, we simply can not bring down the proxy, which is still up.") diff --git a/core/services/networking/systemwide/encrypted_proxy/configure_singbox.py b/core/services/networking/systemwide/encrypted_proxy/configure_singbox.py index edc5353..d531a8d 100644 --- a/core/services/networking/systemwide/encrypted_proxy/configure_singbox.py +++ b/core/services/networking/systemwide/encrypted_proxy/configure_singbox.py @@ -6,6 +6,8 @@ from core.services.networking.systemwide.encrypted_proxy.hysteria_config import from core.services.networking.systemwide.encrypted_proxy.vless_config import build_vless_config, parse_vless_link from core.utils.basic_operations.write_or_read_from_json import write_json_to_file from core.utils.run_commands import run_generic_command +from core.utils.basic_operations.does_file_exist import does_file_exist + # Models from core.models.pydantic_models.HysteriaData import HysteriaData @@ -191,7 +193,7 @@ def attach_config_to_sudo_folder( human_readable_goal = f"Attempt {failed_attempt_count} to write to the sudo folder" logger.info(human_readable_goal) command = ['pkexec', 'install', '-D', backup_path, sudo_filepath, '-o', 'root', '-m', '744'] - result_object = run_generic_command(command, human_readable_goal, timeout=5) + result_object = run_generic_command(command, human_readable_goal, timeout=40) if result_object.valid: configuration_is_attached = True else: @@ -202,7 +204,8 @@ def attach_config_to_sudo_folder( raise ProfileModificationError('The configuration could not be attached.') return False # redundant - return True + # confirm file exists before we continue, + return does_file_exist(sudo_filepath) def post_operator_proxy(billing_code: str, protocol: str, connection_observer: ConnectionObserver) -> dict: diff --git a/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py b/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py index 50ca5b9..49d338b 100644 --- a/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py +++ b/core/services/networking/systemwide/encrypted_proxy/singbox_runner.py @@ -297,15 +297,22 @@ def start_singbox( if not ip_result.valid: logger.error(f"IP address check is unable to connect. Killing Singbox pid {process_id}") closed = orchestrate_closing(current_state=current_state, interface=Constants.SINGBOX_TUN_IF) - raise ConnectionError("Could not connect with IP adddress check.") - # return Result(valid=False, error_type=ResultError.CONNECTION, message="Could not connect with IP adddress check.") + if closed.valid: + logger.info("Closed singbox. Redundant state removal now taking place..") + # redundant state removal. This is a repeat of the close_Singbox doing it. + SystemState.dissolve() + + # raise ConnectionError("Could not connect with IP adddress check.") + return Result(valid=False, error_type=ResultError.CONNECTION, message="Could not connect with IP adddress check.") observed_ip_address = ip_result.data - if observed_ip_address == server_ip: - logger.info("Observed IP matches the intended server IP. Proceeding..") - if connection_observer: - connection_observer.notify("connecting", f"IP Matched! {server_ip}") - else: + logger.info(f""" + observed_ip_address: {observed_ip_address} + observed_ip_address type: {type(observed_ip_address)} + server_ip: {server_ip} + server_ip type: {type(server_ip)} + """) + if str(observed_ip_address) != str(server_ip): error_msg = f"Connection didn't work, it's leaking! IP address check of {observed_ip_address} does NOT match the intended {server_ip}." logger.error(f"{error_msg} Killing Singbox pid {process_id}") closed = orchestrate_closing(current_state=current_state, interface=Constants.SINGBOX_TUN_IF) @@ -314,12 +321,17 @@ def start_singbox( connection_observer.notify("connecting", error_for_user) return Result(valid=False, error_type=ResultError.LEAK_ISSUE, message=error_msg) + + logger.info("Observed IP matches the intended server IP. Proceeding..") + if connection_observer: + connection_observer.notify("connecting", f"IP Matched! {server_ip}") + # ============= FIREWALL ============= logger.info(f"Attempting to enable the Firewall for {Constants.SINGBOX_TUN_IF} and {Constants.SINGBOX_INTERNAL_SUBNET}...") firewall_result = enable_firewall_w_retry( # this function is "generic" as it's protocol neutral - interface_name=Constants.SINGBOX_TUN_IF, - server_ip=server_ip, - internal_subnet = Constants.SINGBOX_INTERNAL_SUBNET, + interface_name=str(Constants.SINGBOX_TUN_IF), + server_ip=str(server_ip), + internal_subnet = (Constants.SINGBOX_INTERNAL_SUBNET), max_retries = 2 ) diff --git a/core/services/subscriptions/subscriptions.py b/core/services/subscriptions/subscriptions.py index 742f3ad..2cd1fa2 100644 --- a/core/services/subscriptions/subscriptions.py +++ b/core/services/subscriptions/subscriptions.py @@ -101,6 +101,7 @@ def is_subscription_ready(profile: Union[SessionProfile, SystemProfile]) -> bool def get_subscription(billing_code: str, connection_observer: ConnectionObserver) -> Subscription: + print(f"calling get_subscription with {billing_code}") billing_code = billing_code.replace('-', '').upper() billing_code_fragments = re.findall('....?', billing_code) @@ -126,6 +127,7 @@ def get_subscription(billing_code: str, connection_observer: ConnectionObserver) def get_invoice(billing_code: str, connection_observer: ConnectionObserver) -> Invoice: + print(f"calling get_invoice to get an invoice") url = f'{Constants.SP_API_BASE_URL}/invoices/current' diff --git a/core/services/sync/sync_service.py b/core/services/sync/sync_service.py index cd7955a..4c6d5c3 100644 --- a/core/services/sync/sync_service.py +++ b/core/services/sync/sync_service.py @@ -197,15 +197,15 @@ def coordinate_cache_sync( # ================== VALIDATE DATA ================== # Extract the data from our own trusted function without type checking, - new_data = api_result.data + original_data = api_result.data - if new_data: + if original_data: logger.debug(f"We got an API response with some data, let's check if it's a valid format...") # Validate the API's payload, (we don't trust the API's structure) - if not isinstance(new_data, dict): - error_msg = f"API returned invalid metadata of {type(new_data)}. When 'new_data' has to be in dictionary format. The raw data is {new_data}" - client_observer.notify('synchronizing', f'Server replied with invalid metadata of type {type(new_data)}') + if not isinstance(original_data, dict): + error_msg = f"API returned invalid metadata of {type(original_data)}. When 'original_data' has to be in dictionary format. The raw data is {original_data}" + client_observer.notify('synchronizing', f'Server replied with invalid metadata of type {type(original_data)}') logger.error(error_msg) return { "success": False, @@ -214,8 +214,12 @@ def coordinate_cache_sync( "error": error_msg, } + # de-"data" it if it has it: + new_data = original_data.get('data', original_data) + print(f"new_data is {new_data}") + if "version" not in new_data: - error_msg = "API returned invalid metadata: missing 'version' key" + error_msg = f"API returned invalid metadata: missing 'version' key. The data is {new_data}" logger.error(error_msg) return { "success": False, diff --git a/core/services/using_tickets/use_ticket_orchestrator.py b/core/services/using_tickets/use_ticket_orchestrator.py index 5c3406f..e9de5a4 100644 --- a/core/services/using_tickets/use_ticket_orchestrator.py +++ b/core/services/using_tickets/use_ticket_orchestrator.py @@ -94,6 +94,7 @@ def use_ticket_orchestrator( # even if not saved return it back, so it can be saved with the profile by other functions, return Result(valid=True, data=billing_code) + # return {"valid": True, "data": billing_code} # EXPIRED if not valid and message == "expired":