Compare commits
8 commits
core-larav
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a83d4bec07 | |||
| 8e2ea64b6b | |||
| dfdcb78fff | |||
| d602f251e0 | |||
| cf0f8cd4ea | |||
| 998f0dc883 | |||
| 38226f149a | |||
| 026b18b396 |
10 changed files with 127 additions and 90 deletions
|
|
@ -13,12 +13,14 @@ from core.services.payment_phase.check_if_paid import _check_if_paid
|
|||
from core.services.prepare_tickets.ticket_tracker import does_ticket_tracker_exist
|
||||
from core.services.networking.send_data_to_server import send_data_to_server
|
||||
from core.services.networking.make_url import make_url
|
||||
from core.utils.confirm_its_a_valid_key_choice import confirm_its_a_valid_key_choice
|
||||
# from core.utils.confirm_its_a_valid_key_choice import confirm_its_a_valid_key_choice
|
||||
from core.services.helpers.valid_profile_quantity import valid_profile_quantity
|
||||
from core.errors.exceptions import *
|
||||
from core.errors.logger import logger
|
||||
from core.controllers.tickets.TicketSyncController import sync_ticket_prices
|
||||
|
||||
from core.services.payment_phase.do_we_have_billing_id import do_we_have_billing_id
|
||||
|
||||
"""
|
||||
Inputs: Which plan (key), which crypto, and how many profiles
|
||||
|
||||
|
|
@ -47,6 +49,12 @@ def initiate_payment(
|
|||
invoice_data_object.add_error_code("already_exists")
|
||||
return invoice_data_object
|
||||
|
||||
billing_id = do_we_have_billing_id()
|
||||
if billing_id:
|
||||
invoice_data_object.add_error_code("billing_code_exists")
|
||||
invoice_data_object.temp_billing_code = billing_id
|
||||
return invoice_data_object
|
||||
|
||||
rejected_choices = [None, "", False]
|
||||
|
||||
if how_many_profiles in rejected_choices:
|
||||
|
|
@ -67,18 +75,6 @@ def initiate_payment(
|
|||
invoice_data_object.add_error_code("no_keyplan")
|
||||
return invoice_data_object
|
||||
|
||||
# confirm the key choice is among the choices from their sync file,
|
||||
# and if not, then sync again, and try the results from that new file,
|
||||
is_valid_key = confirm_its_a_valid_key_choice(which_key, ticket_observer)
|
||||
if not is_valid_key:
|
||||
sync_results = sync_ticket_prices(ticket_observer, connection_observer)
|
||||
second_try_to_match = confirm_its_a_valid_key_choice(
|
||||
which_key, ticket_observer
|
||||
)
|
||||
if not second_try_to_match:
|
||||
invoice_data_object.add_error_code("invalid_key")
|
||||
return invoice_data_object
|
||||
|
||||
# get & save the public key:
|
||||
public_key_results = get_pub_key(which_key, connection_observer, "local")
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ def prepare_tickets(
|
|||
ticket_observer.notify("failed_input", None)
|
||||
return {"valid": False, "error_code": "failed_input"}
|
||||
|
||||
notification = "Preparing Cryptography Locally"
|
||||
ticket_observer.notify("preparing", subject=notification)
|
||||
|
||||
# ok now we have the pre-reqs, let's use this high level orchestrator,
|
||||
prep_results = ticket_prep_orchestrator(
|
||||
how_many_profiles, ticket_observer, connection_observer
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ if TYPE_CHECKING:
|
|||
from core.Constants import Constants
|
||||
from core.observers.BaseObserver import BaseObserver
|
||||
from core.services.networking.get_data_from_server import get_data_from_server
|
||||
from core.services.helpers.save_sync_results import save_sync_results
|
||||
from core.errors.logger import logger
|
||||
|
||||
|
||||
|
|
@ -38,7 +37,4 @@ def sync_ticket_prices(
|
|||
except:
|
||||
return {"valid": False, "error_code": "sync_failed"}
|
||||
|
||||
did_it_save = save_sync_results(sync_results)
|
||||
logger.debug(f"Inside the sync controller, did_it_save is {did_it_save}")
|
||||
|
||||
return sync_results
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ class SystemProfile(BaseProfile):
|
|||
connection: Optional[SystemConnection]
|
||||
|
||||
def get_system_config_path(self):
|
||||
return self.__get_system_config_path(self.id)
|
||||
filepath = self.__get_system_config_path(self.id)
|
||||
the_id = self.id
|
||||
return filepath
|
||||
|
||||
def save(self):
|
||||
|
||||
|
|
@ -48,10 +50,15 @@ class SystemProfile(BaseProfile):
|
|||
raise ProfileModificationError('The WireGuard configuration could not be attached.')
|
||||
|
||||
def get_wireguard_configuration_path(self):
|
||||
return f'{self.get_system_config_path()}/wg.conf'
|
||||
filepath = f'{self.get_system_config_path()}/wg.conf'
|
||||
return filepath
|
||||
|
||||
def has_wireguard_configuration(self):
|
||||
return os.path.isfile(f'{self.get_system_config_path()}/wg.conf')
|
||||
filepath = f'{self.get_system_config_path()}/wg.conf'
|
||||
if os.path.isdir(os.path.dirname(filepath)):
|
||||
return os.path.isfile(filepath)
|
||||
else:
|
||||
return False
|
||||
|
||||
def address_security_incident(self):
|
||||
|
||||
|
|
@ -59,7 +66,6 @@ class SystemProfile(BaseProfile):
|
|||
self.__delete_wireguard_configuration()
|
||||
|
||||
def delete(self):
|
||||
|
||||
try:
|
||||
self.__delete_wireguard_configuration()
|
||||
except ProfileModificationError:
|
||||
|
|
@ -68,11 +74,13 @@ class SystemProfile(BaseProfile):
|
|||
if shutil.which('pkexec') is None:
|
||||
raise CommandNotFoundError('pkexec')
|
||||
|
||||
process = subprocess.Popen(('pkexec', 'rm', '-d', self.get_system_config_path()))
|
||||
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
||||
|
||||
if not completed_successfully:
|
||||
raise ProfileDeletionError('The profile could not be deleted.')
|
||||
try:
|
||||
process = subprocess.run(('pkexec', 'rm', '-rf', self.get_system_config_path()))
|
||||
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
||||
if not completed_successfully:
|
||||
raise ProfileDeletionError('The profile could not be deleted.')
|
||||
except:
|
||||
print("skipping the delete of the WG folder.")
|
||||
|
||||
super().delete()
|
||||
|
||||
|
|
@ -83,12 +91,19 @@ class SystemProfile(BaseProfile):
|
|||
if shutil.which('pkexec') is None:
|
||||
raise CommandNotFoundError('pkexec')
|
||||
|
||||
process = subprocess.Popen(('pkexec', 'rm', '-d', self.get_wireguard_configuration_path()))
|
||||
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
||||
try:
|
||||
process = subprocess.run(('pkexec', 'rm', '-rf', self.get_wireguard_configuration_path()), check=True)
|
||||
|
||||
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
||||
except subprocess.CalledProcessError as e:
|
||||
completed_successfully = True
|
||||
except:
|
||||
completed_successfully = True
|
||||
|
||||
if not completed_successfully:
|
||||
raise ProfileModificationError('The WireGuard configuration could not be deleted.')
|
||||
|
||||
@staticmethod
|
||||
def __get_system_config_path(id: int):
|
||||
return f'{Constants.HV_SYSTEM_PROFILE_CONFIG_PATH}/{str(id)}'
|
||||
config_path = f'{Constants.HV_SYSTEM_PROFILE_CONFIG_PATH}/{str(id)}'
|
||||
return config_path
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from core.Constants import Constants
|
|||
from core.models.ClientVersion import ClientVersion
|
||||
from core.models.Location import Location
|
||||
from core.models.Operator import Operator
|
||||
from core.models.OperatorProxySession import OperatorProxySession
|
||||
from core.models.Subscription import Subscription
|
||||
from core.models.SubscriptionPlan import SubscriptionPlan
|
||||
from core.models.invoice.Invoice import Invoice
|
||||
|
|
@ -18,12 +19,10 @@ class WebServiceApiService:
|
|||
@staticmethod
|
||||
def get_applications(proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get('/platforms/linux-x86_64/applications', None, proxies)
|
||||
applications = []
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
if 200 <= response.status_code < 300:
|
||||
for application in response.json()['data']:
|
||||
applications.append(Application(application['code'], application['name'], application['id']))
|
||||
|
||||
|
|
@ -32,12 +31,10 @@ class WebServiceApiService:
|
|||
@staticmethod
|
||||
def get_application_versions(code: str, proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get(f'/platforms/linux-x86_64/applications/{code}/application-versions', None, proxies)
|
||||
application_versions = []
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
if 200 <= response.status_code < 300:
|
||||
for application_version in response.json()['data']:
|
||||
application_versions.append(ApplicationVersion(code, application_version['version_number'], application_version['format_revision'], application_version['id'], application_version['download_path'], application_version['released_at'], application_version['file_hash']))
|
||||
|
||||
|
|
@ -46,12 +43,10 @@ class WebServiceApiService:
|
|||
@staticmethod
|
||||
def get_client_versions(proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get('/platforms/linux-x86_64/appimage/client-versions', None, proxies)
|
||||
client_versions = []
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
if 200 <= response.status_code < 300:
|
||||
for client_version in response.json()['data']:
|
||||
client_versions.append(ClientVersion(client_version['version_number'], client_version['released_at'], client_version['id'], client_version['download_path']))
|
||||
|
||||
|
|
@ -60,26 +55,22 @@ class WebServiceApiService:
|
|||
@staticmethod
|
||||
def get_operators(proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get('/operators', None, proxies)
|
||||
operators = []
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
if 200 <= response.status_code < 300:
|
||||
for operator in response.json()['data']:
|
||||
operators.append(Operator(operator['id'], operator['name'], operator['public_key'], operator['nostr_public_key'], operator['nostr_profile_reference'], operator['nostr_attestation']['event_reference']))
|
||||
operators.append(Operator(operator['id'], operator['name'], operator['type'], operator['public_key'], operator['nostr_public_key'], operator['nostr_profile_reference'], operator['nostr_attestation']['event_reference']))
|
||||
|
||||
return operators
|
||||
|
||||
@staticmethod
|
||||
def get_locations(proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get('/locations', None, proxies)
|
||||
locations = []
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
if 200 <= response.status_code < 300:
|
||||
for location in response.json()['data']:
|
||||
locations.append(Location(location['country']['code'], location['code'], location['id'], location['country']['name'], location['name'], location['time_zone']['code'], location['operator_id'], location['provider']['name'], location['is_proxy_capable'], location['is_wireguard_capable']))
|
||||
|
||||
|
|
@ -88,60 +79,57 @@ class WebServiceApiService:
|
|||
@staticmethod
|
||||
def get_subscription_plans(proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get('/subscription-plans', None, proxies)
|
||||
subscription_plans = []
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
if 200 <= response.status_code < 300:
|
||||
for subscription_plan in response.json()['data']:
|
||||
subscription_plans.append(SubscriptionPlan(subscription_plan['id'], subscription_plan['code'], subscription_plan['wireguard_session_limit'], subscription_plan['duration'], subscription_plan['price'], subscription_plan['features_proxy'], subscription_plan['features_wireguard']))
|
||||
|
||||
return subscription_plans
|
||||
|
||||
@staticmethod
|
||||
def post_subscription(subscription_plan_id, location_id, proxies: Optional[dict] = None):
|
||||
def post_subscription(subscription_plan_id, location_id=None, operator_id=None, proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__post('/subscriptions', None, {
|
||||
'subscription_plan_id': subscription_plan_id,
|
||||
'location_id': location_id
|
||||
}, proxies)
|
||||
|
||||
if response.status_code == status_codes.CREATED:
|
||||
return Subscription(response.headers['X-Billing-Code'])
|
||||
body = {'subscription_plan_id': subscription_plan_id}
|
||||
|
||||
if operator_id is not None:
|
||||
body['operator_id'] = operator_id
|
||||
else:
|
||||
return None
|
||||
body['location_id'] = location_id
|
||||
|
||||
response = WebServiceApiService.__post('/subscriptions', None, body, proxies)
|
||||
|
||||
if 200 <= response.status_code < 300:
|
||||
return Subscription(response.headers['X-Billing-Code'], operator_id=operator_id)
|
||||
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_subscription(billing_code: str, proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
billing_code = billing_code.replace('-', '').upper()
|
||||
billing_code_fragments = re.findall('....?', billing_code)
|
||||
billing_code = '-'.join(billing_code_fragments)
|
||||
|
||||
response = WebServiceApiService.__get('/subscriptions/current', billing_code, proxies)
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
|
||||
if 200 <= response.status_code < 300:
|
||||
subscription = response.json()['data']
|
||||
return Subscription(billing_code, Subscription.from_iso_format(subscription['expires_at']))
|
||||
return Subscription(
|
||||
billing_code,
|
||||
operator_id=subscription.get('operator_id'),
|
||||
expires_at=Subscription.from_iso_format(subscription['expires_at'])
|
||||
)
|
||||
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_invoice(billing_code: str, proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get('/invoices/current', billing_code, proxies)
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
if 200 <= response.status_code < 300:
|
||||
|
||||
response_data = response.json()['data']
|
||||
|
||||
|
|
@ -157,37 +145,54 @@ class WebServiceApiService:
|
|||
|
||||
return Invoice(billing_code, invoice['status'], invoice['expires_at'], tuple[PaymentMethod](payment_methods))
|
||||
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_proxy_configuration(billing_code: str, proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__get('/proxy-configurations/current', billing_code, proxies)
|
||||
|
||||
if response.status_code == status_codes.OK:
|
||||
|
||||
if 200 <= response.status_code < 300:
|
||||
proxy_configuration = response.json()['data']
|
||||
return ProxyConfiguration(proxy_configuration['ip_address'], proxy_configuration['port'], proxy_configuration['username'], proxy_configuration['password'], proxy_configuration['location']['time_zone']['code'])
|
||||
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def post_operator_proxy(billing_code: str, operator_id: int, protocol: str, proxies: Optional[dict] = None):
|
||||
|
||||
response = WebServiceApiService.__post('/subscriptions/current/operator-proxies', billing_code, {
|
||||
'operator_id': operator_id,
|
||||
'protocol': protocol,
|
||||
}, proxies)
|
||||
|
||||
if 200 <= response.status_code < 300:
|
||||
data = response.json()['data']
|
||||
return OperatorProxySession(
|
||||
data['id'],
|
||||
data['type'],
|
||||
data['username'],
|
||||
data.get('password'),
|
||||
data.get('links'),
|
||||
data.get('subscription_url'),
|
||||
data['operator']['id'],
|
||||
data['operator']['name'],
|
||||
data['operator'].get('domain'),
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def post_wireguard_session(country_code: str, location_code: str, billing_code: str, public_key: str, proxies: Optional[dict] = None):
|
||||
|
||||
from requests.status_codes import codes as status_codes
|
||||
|
||||
response = WebServiceApiService.__post(f'/countries/{country_code}/locations/{location_code}/wireguard-sessions', billing_code, {
|
||||
'public_key': public_key,
|
||||
}, proxies)
|
||||
|
||||
if response.status_code == status_codes.CREATED:
|
||||
if 200 <= response.status_code < 300:
|
||||
return response.text
|
||||
else:
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __get(path, billing_code: Optional[str] = None, proxies: Optional[dict] = None):
|
||||
|
|
@ -211,4 +216,4 @@ class WebServiceApiService:
|
|||
else:
|
||||
headers = None
|
||||
|
||||
return requests.post(Constants.SP_API_BASE_URL + path, headers=headers, json=body, proxies=proxies)
|
||||
return requests.post(Constants.SP_API_BASE_URL + path, headers=headers, json=body, proxies=proxies)
|
||||
|
|
@ -96,7 +96,7 @@ def is_the_key_to_blame(
|
|||
# invalid key
|
||||
notification = f"Invalid Numbers on the public_key"
|
||||
ticket_observer.notify("preparing", subject=notification)
|
||||
return {"valid": True, "message": "invalid_key"}
|
||||
return {"valid": False, "message": "invalid_key"}
|
||||
|
||||
new_public_key = get_new_pubkey_from_api(connection_observer)
|
||||
|
||||
|
|
@ -121,7 +121,7 @@ def is_the_key_to_blame(
|
|||
if not result_of_comparison:
|
||||
error_msg = "New key is the SAME as the old one."
|
||||
ticket_observer.notify("preparing", subject=error_msg)
|
||||
return {"valid": False, "message": "same"}
|
||||
return {"valid": False, "comparison": "same"}
|
||||
|
||||
status_update = "New key is DIFFERENT from the old one!"
|
||||
ticket_observer.notify("preparing", subject=status_update)
|
||||
|
|
@ -142,9 +142,9 @@ def is_the_key_to_blame(
|
|||
|
||||
if quantity_results > 0:
|
||||
logger.debug("Therefore, the new key works.")
|
||||
return {"valid": True, "comparison": "different", "matters": False}
|
||||
return {"valid": True, "comparison": "different"}
|
||||
else:
|
||||
logger.debug(
|
||||
"Therefore, the new key doesn't help. It is different, but also produces invalid blind signatures."
|
||||
)
|
||||
return {"valid": False, "comparison": "different", "matters": False}
|
||||
return {"valid": False, "comparison": "different"}
|
||||
|
|
|
|||
13
core/services/payment_phase/do_we_have_billing_id.py
Normal file
13
core/services/payment_phase/do_we_have_billing_id.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
from core.utils.basic_operations.write_or_read_from_json import get_value_from_json_file
|
||||
from core.Constants import Constants
|
||||
|
||||
def do_we_have_billing_id() -> str | None:
|
||||
try:
|
||||
billing_folder = Constants.HV_TICKETING_CONFIG_HOME
|
||||
filepath = f"{billing_folder}/billing_choices.json"
|
||||
|
||||
billing_id = get_value_from_json_file(filepath, "temp_billing_code")
|
||||
return billing_id
|
||||
|
||||
except:
|
||||
return None
|
||||
|
|
@ -37,7 +37,7 @@ def get_from_server_and_save(
|
|||
|
||||
if status == True:
|
||||
# extract:
|
||||
public_key = public_key_results.get("valid", False)
|
||||
public_key = public_key_results.get("data", False)
|
||||
|
||||
# save it:
|
||||
did_it_save = write_string_to_text_file(public_key, file_path)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ def ticket_prep_orchestrator(
|
|||
}
|
||||
|
||||
# assuming we actually saved the unblinding factors,
|
||||
notification = "Sending Blinded Package to the Server.."
|
||||
ticket_observer.notify("preparing", subject=notification)
|
||||
|
||||
# then send the entire blinded list to the server to sign:
|
||||
blind_signatures = send_blind_commitments(
|
||||
|
|
@ -56,9 +58,13 @@ def ticket_prep_orchestrator(
|
|||
|
||||
else:
|
||||
# regardless of the outcome of the verification, save all blind sigs, just in case, because the user can't get them again,
|
||||
notification = "Saving the Server's Blind Replies"
|
||||
ticket_observer.notify("preparing", subject=notification)
|
||||
did_they_ALL_save = save_ALL_blind_sigs(blind_signatures)
|
||||
|
||||
# verify the server's blind signatures against the public key,
|
||||
notification = "Evaluating the Server's Blind Replies"
|
||||
ticket_observer.notify("preparing", subject=notification)
|
||||
failed_validations = validate_blind_signatures(
|
||||
blind_signatures, ticket_observer, connection_observer
|
||||
)
|
||||
|
|
@ -68,6 +74,8 @@ def ticket_prep_orchestrator(
|
|||
# did verification of any of the blind sigs fail?
|
||||
how_many_failed = len(failed_validations)
|
||||
if how_many_failed >= 1:
|
||||
notification = f"Verification failed for {how_many_failed} blind signatures."
|
||||
ticket_observer.notify("preparing", subject=notification)
|
||||
logger.debug(
|
||||
f"Verification failed for {how_many_failed} blind signatures."
|
||||
)
|
||||
|
|
@ -79,6 +87,8 @@ def ticket_prep_orchestrator(
|
|||
}
|
||||
|
||||
# Unblind the signatures & combine with unblinded commitment:
|
||||
notification = f"Unblinding Signatures & Preparing Tickets..."
|
||||
ticket_observer.notify("preparing", subject=notification)
|
||||
did_prep_work = unblind_ALL_tickets(
|
||||
blind_signatures, ticket_observer, connection_observer
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "sp-hydra-veil-core"
|
||||
version = "2.3.0"
|
||||
version = "2.3.4"
|
||||
authors = [
|
||||
{ name = "Simplified Privacy" },
|
||||
]
|
||||
|
|
@ -15,7 +15,6 @@ dependencies = [
|
|||
"cryptography ~= 46.0.3",
|
||||
"dataclasses-json ~= 0.6.7",
|
||||
"marshmallow ~= 3.26.1",
|
||||
"psutil ~= 7.1.3",
|
||||
"pysocks ~= 1.7.1",
|
||||
"python-dateutil ~= 2.9.0.post0",
|
||||
"requests ~= 2.32.5",
|
||||
|
|
|
|||
Loading…
Reference in a new issue