mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-13 00:53:46 +03:00
* First iteration for internationalization of the loader * First iteration for internationalization of the loader * Cleanup node mess * Cleanup node mess pt2 * Additional touches * Latest decky changed merged into i18n and updated translation. * Styling fixes * Initial backend hosting implementation * Added correct url path of the loopback server. * Added correct url path of the loopback server. * Some better namespaced text. * Added whitelist for locales path. * Refactor languages and fix hooks logic bugs. * Small typo in language translation structure. * Working backend, automatically swtich languages with steam and language fixes. * Fix to languages * Key fixes * Additional language fixes. * Additional json changes * Final text revision and added a vscode tasks to automatically extract text from code. * Typo in the middleware * Remove unused imports * Cleanup whitespaces. * Import changes * Revert "Import changes" This reverts commit8e8231950f. * Update index.d.ts * Clean up unused imports * Delete pnpm-lock.yaml * Update rollup.config.js * Update PluginInstallModal.tsx * Update index.tsx * Update plugin-loader.tsx * Update plugin-loader.tsx * Revert "Delete pnpm-lock.yaml" This reverts commit3a39f36f21. * Additional strings reworks. * Fixes for issues coming from github merge. * Fixes for master * Styling fixes * Styling pt2 * Missed a few strings in master, * Styling fixes * Additional master merge fixes. * Final cleanup and adaptation to master. * Final empty language cleanup and few string added * Small changes to italian translation * Disabled translation on a few components inside plugin-loader for missing react hooks. * Fixed passing tag to translation. * Disable debug output for reducing console spam. * Return correct content type * Small italian language change * Added support for country code * Fixed missing translation for uninstall popup. * Fix class name shenanigans for toast notification * Update dependencies * Fixed github workflow to include the new locales folder * Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up * Missed a file name change * Updated dev dependencies to latest version * Missed a few dev dependencies * Revert "Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up" Messed up merge with a different main branch * Messed up deletion of rollup config. * Fix broken pnpm lock file * Missed a localized string during the merge * Fixed a parameter mistake in the uninstall text parameter * Fix pnpm random issues * Small italian language tweaks * Fix wrong parameter passed to the uninstall function call * Another fix on a wrong function parameter * Additional translation text on the store and branch selection channels * Changed the default type passed to map to being able to index the two arrays. * Reverted and reworked the last changes * Distinguish events in UI for installing vs reinstalling plugins * Additional fixes for reinstall prompt * Revert the use of intevalPlural since the parser doesn't seem to support that. * Missed a routing path in the backend * Small bugfixes * Small fixes * Correctly adding the parameter to the request headers. * Refactoring of the UI popup modal * Fix pnpm shenanigans * Final fixes for the install UI localization * Clean up unnedeed backend code * Small rework on text selection. * Cleaned up parser configuration * Removed extracttext dependency to pnpmsetup * Merged translation and cleaned up parser * Fixed JSON structure after manual merge. * Added translation to the file picker * First iteration for merging the new filepicker. * Revert changes to PluginInstallModal * Reworked the text modal for the final time * Missed the proper linted text * Missed the backend change * Final branch cleanup * First iteration for porting the new file picker * Hotfix for i18n where the detector was overriding localStorage * Please, pnpm, cooperate * Small fix regarding the backend getting hammered when switching to not supported languages plus a small english typo * Initial working upstream iteration for file picker * Typo on translation variable * File picker final improvements * Stylistic fixes and fix on wrong bool passed to fp * Fixup merge from main * Other merge errors fixed * Minor cleanups * Fixed missing padding under text label extension * Implement pagination backend side * First draft for filtering backend side * Implemented matching on file names. * Fix for unable to order per size on folders. * Hard checking a return value * Added a missing import. * Implemented show more as a frontend button * Whoops, python typo * Fixed python backend * Rendering bug fix and small qol improvement * Added missing parameter to openFilePicker call * Fixed path on windows and unknown error on wrong path * Small backend fixes * Extension fix * Simplified extension logic * Less string conversions. * Optimize backend code and removed additional components. * Take correctly into account the max value The button will now respect the actual maximum desired number of entries. * Bugfix for ordering logic and ignore cases during sorting * Regex call was missing an argument * Fixed issues with filtering extensions * Rollback testing changes * Minor cleanup and attempt at fixing the not updating multimodal. * Cleanup variable types. * Mantains the same api format from the original source code. * Removing hardcoded paths in the code * Additional fixes for resolving the user path * Cleanup useless modifications * Final fixes for avoid path hardcoding * Update lockfile and i18next version
163 lines
5.7 KiB
Python
163 lines
5.7 KiB
Python
import re
|
|
import ssl
|
|
import uuid
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
from hashlib import sha256
|
|
from io import BytesIO
|
|
|
|
import certifi
|
|
from aiohttp.web import Response, middleware
|
|
from aiohttp import ClientSession
|
|
import localplatform
|
|
from customtypes import UserType
|
|
from logging import getLogger
|
|
|
|
REMOTE_DEBUGGER_UNIT = "steam-web-debug-portforward.service"
|
|
|
|
# global vars
|
|
csrf_token = str(uuid.uuid4())
|
|
ssl_ctx = ssl.create_default_context(cafile=certifi.where())
|
|
|
|
assets_regex = re.compile("^/plugins/.*/assets/.*")
|
|
frontend_regex = re.compile("^/frontend/.*")
|
|
logger = getLogger("Main")
|
|
|
|
def get_ssl_context():
|
|
return ssl_ctx
|
|
|
|
def get_csrf_token():
|
|
return csrf_token
|
|
|
|
@middleware
|
|
async def csrf_middleware(request, handler):
|
|
if str(request.method) == "OPTIONS" or request.headers.get('Authentication') == csrf_token or str(request.rel_url) == "/auth/token" or str(request.rel_url).startswith("/plugins/load_main/") or str(request.rel_url).startswith("/static/") or str(request.rel_url).startswith("/legacy/") or str(request.rel_url).startswith("/steam_resource/") or str(request.rel_url).startswith("/frontend/") or assets_regex.match(str(request.rel_url)) or frontend_regex.match(str(request.rel_url)):
|
|
return await handler(request)
|
|
return Response(text='Forbidden', status='403')
|
|
|
|
# Get the default homebrew path unless a home_path is specified. home_path argument is deprecated
|
|
def get_homebrew_path(home_path = None) -> str:
|
|
return localplatform.get_unprivileged_path()
|
|
|
|
# Recursively create path and chown as user
|
|
def mkdir_as_user(path):
|
|
path = os.path.realpath(path)
|
|
os.makedirs(path, exist_ok=True)
|
|
localplatform.chown(path)
|
|
|
|
# Fetches the version of loader
|
|
def get_loader_version() -> str:
|
|
try:
|
|
with open(os.path.join(os.getcwd(), ".loader.version"), "r", encoding="utf-8") as version_file:
|
|
return version_file.readline().strip()
|
|
except Exception as e:
|
|
logger.warn(f"Failed to execute get_loader_version(): {str(e)}")
|
|
return "unknown"
|
|
|
|
# returns the appropriate system python paths
|
|
def get_system_pythonpaths() -> list[str]:
|
|
extra_args = {}
|
|
|
|
if localplatform.ON_LINUX:
|
|
# run as normal normal user to also include user python paths
|
|
extra_args["user"] = localplatform.localplatform._get_user_id()
|
|
extra_args["env"] = {}
|
|
|
|
try:
|
|
proc = subprocess.run(["python3" if localplatform.ON_LINUX else "python", "-c", "import sys; print('\\n'.join(x for x in sys.path if x))"],
|
|
capture_output=True, **extra_args)
|
|
return [x.strip() for x in proc.stdout.decode().strip().split("\n")]
|
|
except Exception as e:
|
|
logger.warn(f"Failed to execute get_system_pythonpaths(): {str(e)}")
|
|
return []
|
|
|
|
# Download Remote Binaries to local Plugin
|
|
async def download_remote_binary_to_path(url, binHash, path) -> bool:
|
|
rv = False
|
|
try:
|
|
if os.access(os.path.dirname(path), os.W_OK):
|
|
async with ClientSession() as client:
|
|
res = await client.get(url, ssl=get_ssl_context())
|
|
if res.status == 200:
|
|
data = BytesIO(await res.read())
|
|
remoteHash = sha256(data.getbuffer()).hexdigest()
|
|
if binHash == remoteHash:
|
|
data.seek(0)
|
|
with open(path, 'wb') as f:
|
|
f.write(data.getbuffer())
|
|
rv = True
|
|
else:
|
|
raise Exception(f"Fatal Error: Hash Mismatch for remote binary {path}@{url}")
|
|
else:
|
|
rv = False
|
|
except:
|
|
rv = False
|
|
|
|
return rv
|
|
|
|
# Deprecated
|
|
def set_user():
|
|
pass
|
|
|
|
# Deprecated
|
|
def set_user_group() -> str:
|
|
return get_user_group()
|
|
|
|
#########
|
|
# Below is legacy code, provided for backwards compatibility. This will break on windows
|
|
#########
|
|
|
|
# Get the user id hosting the plugin loader
|
|
def get_user_id() -> int:
|
|
return localplatform.localplatform._get_user_id()
|
|
|
|
# Get the user hosting the plugin loader
|
|
def get_user() -> str:
|
|
return localplatform.localplatform._get_user()
|
|
|
|
# Get the effective user id of the running process
|
|
def get_effective_user_id() -> int:
|
|
return localplatform.localplatform._get_effective_user_id()
|
|
|
|
# Get the effective user of the running process
|
|
def get_effective_user() -> str:
|
|
return localplatform.localplatform._get_effective_user()
|
|
|
|
# Get the effective user group id of the running process
|
|
def get_effective_user_group_id() -> int:
|
|
return localplatform.localplatform._get_effective_user_group_id()
|
|
|
|
# Get the effective user group of the running process
|
|
def get_effective_user_group() -> str:
|
|
return localplatform.localplatform._get_effective_user_group()
|
|
|
|
# Get the user owner of the given file path.
|
|
def get_user_owner(file_path) -> str:
|
|
return localplatform.localplatform._get_user_owner(file_path)
|
|
|
|
# Get the user group of the given file path.
|
|
def get_user_group(file_path) -> str:
|
|
return localplatform.localplatform._get_user_group(file_path)
|
|
|
|
# Get the group id of the user hosting the plugin loader
|
|
def get_user_group_id() -> int:
|
|
return localplatform.localplatform._get_user_group_id()
|
|
|
|
# Get the group of the user hosting the plugin loader
|
|
def get_user_group() -> str:
|
|
return localplatform.localplatform._get_user_group()
|
|
|
|
# Get the default home path unless a user is specified
|
|
def get_home_path(username = None) -> str:
|
|
return localplatform.get_home_path(UserType.ROOT if username == "root" else UserType.HOST_USER)
|
|
|
|
async def is_systemd_unit_active(unit_name: str) -> bool:
|
|
return await localplatform.service_active(unit_name)
|
|
|
|
async def stop_systemd_unit(unit_name: str) -> bool:
|
|
return await localplatform.service_stop(unit_name)
|
|
|
|
async def start_systemd_unit(unit_name: str) -> bool:
|
|
return await localplatform.service_start(unit_name)
|