sp-hydra-veil-core/core/controllers/ApplicationController.py

103 lines
4.2 KiB
Python

from core.Constants import Constants
from core.controllers.SessionStateController import SessionStateController
from core.models.session.Application import Application
from core.models.session.ApplicationVersion import ApplicationVersion
from core.models.session.SessionProfile import SessionProfile
from core.models.session.SessionState import SessionState
from core.observers.ProfileObserver import ProfileObserver
from core.services.WebServiceApiService import WebServiceApiService
from pathlib import Path
from typing import Optional
import os
import re
import shutil
import stat
import subprocess
class ApplicationController:
@staticmethod
def get(code: str):
return Application.find(code)
@staticmethod
def get_all():
return Application.all()
@staticmethod
def launch(version: ApplicationVersion, profile: SessionProfile, port_number: int = None, profile_observer: Optional[ProfileObserver] = None):
persistent_state_path = f'{profile.get_data_path()}/persistent-state'
if not os.path.isdir(persistent_state_path) or len(os.listdir(persistent_state_path)) == 0:
shutil.copytree(f'{version.installation_path}/resources/initial-state', persistent_state_path)
display = ApplicationController._find_unused_display()
base_initialization_file_template = open(f'/{Constants.SP_DATA_HOME}/.init.ptpl', 'r').read()
base_initialization_file_contents = base_initialization_file_template.format(display=display, time_zone=profile.location.time_zone, sp_data_home=Constants.SP_DATA_HOME)
application_initialization_file_template = open(f'/{version.installation_path}/.init.ptpl', 'r').read()
application_initialization_file_contents = application_initialization_file_template.format(application_version_home=version.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)
session_state = SessionStateController.get_or_new(profile.id)
SessionStateController.update_or_create(session_state)
initialization_file_contents = base_initialization_file_contents + application_initialization_file_contents
initialization_file_path = f'{session_state.get_state_path()}/.init'
Path(initialization_file_path).touch(exist_ok=True, mode=0o600 | stat.S_IEXEC)
open(initialization_file_path, 'w').write(initialization_file_contents)
fork_process_id = os.fork()
if not fork_process_id:
process = subprocess.Popen(('xinit', initialization_file_path, '--', '/usr/bin/Xephyr', '-ac', '-title', f'Simplified Privacy - {profile.name or "Unnamed Profile"}', '-screen', profile.resolution, '-no-host-grab', display), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
session_state = SessionState(session_state.id, session_state.network_port_numbers, [process.pid])
SessionStateController.update_or_create(session_state)
os.waitpid(process.pid, 0)
from core.controllers.ProfileController import ProfileController
ProfileController.disable(profile, False, profile_observer=profile_observer)
@staticmethod
def fetch(proxies: Optional[dict] = None):
applications = WebServiceApiService.get_applications(proxies)
supported_applications = []
for application in applications:
if application.code in ('firefox', 'brave', 'chromium'):
supported_applications.append(application)
Application.truncate()
Application.save_many(applications)
@staticmethod
def _find_unused_display():
file_names = os.listdir('/tmp/.X11-unix')
active_displays = []
for file_name in file_names:
match_object = re.search(r'X(\d+)', file_name)
if match_object:
detected_display = int(match_object.group(1))
if 170 <= detected_display <= 198:
active_displays.append(detected_display)
if len(active_displays) > 0:
unused_display = sorted(active_displays)[-1] + 1
return ':' + str(unused_display)
else:
return ':170'