From d33a73bb96686375326336a938c15909031ac474 Mon Sep 17 00:00:00 2001 From: codeking Date: Fri, 14 Mar 2025 02:43:13 +0100 Subject: [PATCH] Add support for embedded time zone data --- core/Errors.py | 4 ++ core/controllers/ApplicationController.py | 3 +- .../ApplicationVersionController.py | 11 +++-- core/models/BaseProfile.py | 3 ++ core/models/Location.py | 7 +-- core/models/session/ProxyConfiguration.py | 13 +++++- core/models/session/SessionProfile.py | 46 +++++++++++++++++++ core/services/WebServiceApiService.py | 2 +- pyproject.toml | 1 - 9 files changed, 75 insertions(+), 15 deletions(-) diff --git a/core/Errors.py b/core/Errors.py index b08a031..bff83e7 100644 --- a/core/Errors.py +++ b/core/Errors.py @@ -14,6 +14,10 @@ class UnknownConnectionTypeError(Exception): pass +class UnknownTimeZoneError(Exception): + pass + + class ConnectionTerminationError(Exception): pass diff --git a/core/controllers/ApplicationController.py b/core/controllers/ApplicationController.py index 8343350..3d4ecb6 100644 --- a/core/controllers/ApplicationController.py +++ b/core/controllers/ApplicationController.py @@ -39,9 +39,10 @@ class ApplicationController: shutil.copytree(f'{version.get_installation_path()}/resources/initial-state', persistent_state_path) display = ApplicationController.__find_unused_display() + time_zone = profile.determine_timezone() base_initialization_file_template = open(f'/{Constants.HV_RUNTIME_DATA_HOME}/.init.ptpl', 'r').read() - base_initialization_file_contents = base_initialization_file_template.format(display=display, time_zone=profile.location.time_zone, hv_data_home=Constants.HV_DATA_HOME) + base_initialization_file_contents = base_initialization_file_template.format(display=display, time_zone=time_zone, hv_data_home=Constants.HV_DATA_HOME) application_initialization_file_template = open(f'/{version.get_installation_path()}/.init.ptpl', 'r').read() application_initialization_file_contents = application_initialization_file_template.format(application_version_home=version.get_installation_path(), port_number=port_number or -1, home=Constants.HOME, profile_data_path=profile.get_data_path(), config_home=Constants.CONFIG_HOME, application_version_number=version.version_number) diff --git a/core/controllers/ApplicationVersionController.py b/core/controllers/ApplicationVersionController.py index 7fe43be..eec635e 100644 --- a/core/controllers/ApplicationVersionController.py +++ b/core/controllers/ApplicationVersionController.py @@ -83,11 +83,14 @@ class ApplicationVersionController: response_buffer.write(data) progress = (bytes_written / response_size) * 100 if response_size > 0 else 0 - application_version_observer.notify('download_progressing', application_version, dict( - progress=progress - )) + if application_version_observer is not None: + + application_version_observer.notify('download_progressing', application_version, dict( + progress=progress + )) + + application_version_observer.notify('downloaded', application_version) - application_version_observer.notify('downloaded', application_version) response_buffer.seek(0) file_hash = ApplicationVersionController.__calculate_file_hash(response_buffer) diff --git a/core/models/BaseProfile.py b/core/models/BaseProfile.py index f4d76f1..5dd92e7 100644 --- a/core/models/BaseProfile.py +++ b/core/models/BaseProfile.py @@ -31,6 +31,9 @@ class BaseProfile: def has_subscription(self): return self.subscription is not None + def has_location(self): + return self.location is not None + def is_session_profile(self): return type(self).__name__ == 'SessionProfile' diff --git a/core/models/Location.py b/core/models/Location.py index 69b37de..87a2f91 100644 --- a/core/models/Location.py +++ b/core/models/Location.py @@ -1,7 +1,6 @@ from core.models.Model import Model from dataclasses import dataclass, field from dataclasses_json import config, Exclude -from pytz import country_timezones from typing import Optional _table_name: str = 'locations' @@ -33,17 +32,13 @@ class Location(Model): default=None, metadata=config(exclude=Exclude.ALWAYS) ) - time_zone: str = None + time_zone: Optional[str] = None available: Optional[bool] = field( default=False, metadata=config(exclude=Exclude.ALWAYS) ) def __post_init__(self): - - if self.time_zone is None: - self.time_zone = country_timezones[self.country_code][0] - self.available = self.exists(self.country_code, self.code) def is_available(self): diff --git a/core/models/session/ProxyConfiguration.py b/core/models/session/ProxyConfiguration.py index 745617b..ccb1700 100644 --- a/core/models/session/ProxyConfiguration.py +++ b/core/models/session/ProxyConfiguration.py @@ -1,5 +1,7 @@ -from dataclasses import dataclass -from dataclasses_json import dataclass_json +from dataclasses import dataclass, field +from dataclasses_json import dataclass_json, config +from typing import Optional +import dataclasses_json @dataclass_json @@ -9,3 +11,10 @@ class ProxyConfiguration: port_number: int username: str password: str + time_zone: Optional[str] = field( + default=None, + metadata=config( + undefined=dataclasses_json.Undefined.EXCLUDE, + exclude=lambda value: value is None + ) + ) diff --git a/core/models/session/SessionProfile.py b/core/models/session/SessionProfile.py index 9294a53..7e1dbd7 100644 --- a/core/models/session/SessionProfile.py +++ b/core/models/session/SessionProfile.py @@ -1,4 +1,5 @@ from core.Constants import Constants +from core.Errors import UnknownTimeZoneError from core.models.BaseProfile import BaseProfile from core.models.session.ApplicationVersion import ApplicationVersion from core.models.session.ProxyConfiguration import ProxyConfiguration @@ -8,6 +9,7 @@ from json import JSONDecodeError from typing import Optional import json import os +import re import shutil @@ -17,6 +19,9 @@ class SessionProfile(BaseProfile): application_version: Optional[ApplicationVersion] connection: Optional[SessionConnection] + def has_connection(self): + return self.connection is not None + def save(self): if 'application_version' in self._get_dirty_keys(): @@ -76,3 +81,44 @@ class SessionProfile(BaseProfile): def has_wireguard_configuration(self): return os.path.isfile(f'{self.get_config_path()}/wg.conf') + + def determine_timezone(self): + + time_zone = None + + if self.has_connection(): + + if self.connection.needs_proxy_configuration(): + + if self.has_proxy_configuration(): + time_zone = self.get_proxy_configuration().time_zone + + elif self.connection.needs_wireguard_configuration(): + + if self.has_wireguard_configuration(): + time_zone = self.__get_wireguard_configuration_metadata('TZ') + + if time_zone is None and self.has_location(): + time_zone = self.location.time_zone + + if time_zone is None: + raise UnknownTimeZoneError('The preferred time zone could not be determined.') + + return time_zone + + def __get_wireguard_configuration(self): + + try: + with open(self.get_wireguard_configuration_path(), 'r') as file: + return file.readlines() + + except FileNotFoundError: + return None + + def __get_wireguard_configuration_metadata(self, key): + + for line in self.__get_wireguard_configuration(): + match = re.match(r'^# {} = (.*)$'.format(re.escape(key)), line) + + if match: + return re.sub(r'[^a-zA-Z0-9+\- /]', '', match.group(1).strip()) diff --git a/core/services/WebServiceApiService.py b/core/services/WebServiceApiService.py index 19f7ab6..6c390c7 100644 --- a/core/services/WebServiceApiService.py +++ b/core/services/WebServiceApiService.py @@ -129,7 +129,7 @@ class WebServiceApiService: if response.status_code == requests.codes.ok: proxy_configuration = response.json()['data'] - return ProxyConfiguration(proxy_configuration['ip_address'], proxy_configuration['port'], proxy_configuration['username'], proxy_configuration['password']) + return ProxyConfiguration(proxy_configuration['ip_address'], proxy_configuration['port'], proxy_configuration['username'], proxy_configuration['password'], proxy_configuration['location']['time_zone']['code']) else: return None diff --git a/pyproject.toml b/pyproject.toml index c359af0..960f0a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,6 @@ dependencies = [ "psutil ~= 5.9.8", "pysocks ~= 1.7.1", "python-dateutil ~= 2.9.0.post0", - "pytz ~= 2024.1", "requests ~= 2.32.0", ]