summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrent Callan <trentcalllan@yahoo.com>2022-09-18 17:20:19 -0700
committerGitHub <noreply@github.com>2022-09-18 17:20:19 -0700
commit3136ad72edd0949626f48ab55103e79b540c7a94 (patch)
treee2a20425209e3f512ac58fbb41351f6fdc367666
parent3700dd7437c0c5ed28de3688ffc049bb9b92a41a (diff)
downloaddecky-loader-2.1.0-pre3.tar.gz
decky-loader-2.1.0-pre3.zip
Download Remote Binaries during Store Install (#177)v2.1.0-pre3
* Download Remote Binaries during store install. Fix Manual Install Modal Type * Use Unix Line endings. (Thanks WSL) * Fix Merge Commit with main branch.
-rw-r--r--backend/browser.py67
-rw-r--r--backend/helpers.py28
2 files changed, 85 insertions, 10 deletions
diff --git a/backend/browser.py b/backend/browser.py
index c0e70c82..6a4747f1 100644
--- a/backend/browser.py
+++ b/backend/browser.py
@@ -8,14 +8,14 @@ from concurrent.futures import ProcessPoolExecutor
from hashlib import sha256
from io import BytesIO
from logging import getLogger
-from os import path, rename, listdir
+from os import R_OK, W_OK, path, rename, listdir, access, mkdir
from shutil import rmtree
from subprocess import call
from time import time
from zipfile import ZipFile
# Local modules
-from helpers import get_ssl_context, get_user, get_user_group
+from helpers import get_ssl_context, get_user, get_user_group, download_remote_binary_to_path
from injector import get_tab, inject_to_tab
logger = getLogger("Browser")
@@ -47,6 +47,49 @@ class PluginBrowser:
logger.error(f"chown/chmod exited with a non-zero exit code (chown: {code_chown}, chmod: {code_chmod})")
return False
return True
+
+ async def _download_remote_binaries_for_plugin_with_name(self, plugin_name):
+ rv = False
+ try:
+ pluginBasePath = path.join(self.plugin_path, plugin_name)
+ packageJsonPath = path.join(pluginBasePath, 'package.json')
+ pluginBinPath = path.join(pluginBasePath, 'bin')
+
+ if access(packageJsonPath, R_OK):
+ with open(packageJsonPath, 'r') as f:
+ packageJson = json.load(f)
+ if len(packageJson["remote_binary"]) > 0:
+ # create bin directory if needed.
+ rc=call(["chmod", "-R", "777", pluginBasePath])
+ if access(pluginBasePath, W_OK):
+
+ if not path.exists(pluginBinPath):
+ mkdir(pluginBinPath)
+
+ if not access(pluginBinPath, W_OK):
+ rc=call(["chmod", "-R", "777", pluginBinPath])
+
+ rv = True
+ for remoteBinary in packageJson["remote_binary"]:
+ # Required Fields. If any Remote Binary is missing these fail the install.
+ binName = remoteBinary["name"]
+ binURL = remoteBinary["url"]
+ binHash = remoteBinary["sha256hash"]
+ if not await download_remote_binary_to_path(binURL, binHash, path.join(pluginBinPath, binName)):
+ rv = False
+ raise Exception(f"Error Downloading Remote Binary {binName}@{binURL} with hash {binHash} to {path.join(pluginBinPath, binName)}")
+
+ code_chown = call(["chown", "-R", get_user()+":"+get_user_group(), self.plugin_path])
+ rc=call(["chmod", "-R", "555", pluginBasePath])
+ else:
+ rv = True
+ logger.debug(f"No Remote Binaries to Download")
+
+ except Exception as e:
+ rv = False
+ logger.debug(str(e))
+
+ return rv
def find_plugin_folder(self, name):
for folder in listdir(self.plugin_path):
@@ -100,14 +143,18 @@ class PluginBrowser:
logger.debug("Unzipping...")
ret = self._unzip_to_plugin_dir(res_zip, name, hash)
if ret:
- logger.info(f"Installed {name} (Version: {version})")
- plugin_dir = self.find_plugin_folder(name)
- if name in self.loader.plugins:
- self.loader.plugins[name].stop()
- self.loader.plugins.pop(name, None)
- await sleep(1)
- self.loader.import_plugin(path.join(plugin_dir, "main.py"), plugin_dir)
- # await inject_to_tab("SP", "window.syncDeckyPlugins()")
+ ret = await self._download_remote_binaries_for_plugin_with_name(name)
+ if ret:
+ logger.info(f"Installed {name} (Version: {version})")
+ plugin_dir = self.find_plugin_folder(name)
+ if name in self.loader.plugins:
+ self.loader.plugins[name].stop()
+ self.loader.plugins.pop(name, None)
+ await sleep(1)
+ self.loader.import_plugin(path.join(plugin_dir, "main.py"), plugin_dir)
+ # await inject_to_tab("SP", "window.syncDeckyPlugins()")
+ else:
+ logger.fatal(f"Failed Downloading Remote Binaries")
else:
self.log.fatal(f"SHA-256 Mismatch!!!! {name} (Version: {version})")
if self.loader.watcher:
diff --git a/backend/helpers.py b/backend/helpers.py
index 3a109dca..0b6e7746 100644
--- a/backend/helpers.py
+++ b/backend/helpers.py
@@ -2,11 +2,15 @@ import re
import ssl
import subprocess
import uuid
+import os
from subprocess import check_output
from time import sleep
+from hashlib import sha256
+from io import BytesIO
import certifi
from aiohttp.web import Response, middleware
+from aiohttp import ClientSession
REMOTE_DEBUGGER_UNIT = "steam-web-debug-portforward.service"
@@ -83,6 +87,30 @@ def get_homebrew_path(home_path = None) -> str:
return str(home_path+"/homebrew")
# return str(home_path+"/homebrew")
+# 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
+
async def is_systemd_unit_active(unit_name: str) -> bool:
res = subprocess.run(["systemctl", "is-active", unit_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return res.returncode == 0