Download Remote Binaries during Store Install (#177)

* Download Remote Binaries during store install.
Fix Manual Install Modal Type

* Use Unix Line endings. (Thanks WSL)

* Fix Merge Commit with main branch.
This commit is contained in:
Trent Callan
2022-09-18 17:20:19 -07:00
committed by GitHub
parent 3700dd7437
commit 3136ad72ed
2 changed files with 85 additions and 10 deletions
+57 -10
View File
@@ -8,14 +8,14 @@ from concurrent.futures import ProcessPoolExecutor
from hashlib import sha256 from hashlib import sha256
from io import BytesIO from io import BytesIO
from logging import getLogger 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 shutil import rmtree
from subprocess import call from subprocess import call
from time import time from time import time
from zipfile import ZipFile from zipfile import ZipFile
# Local modules # 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 from injector import get_tab, inject_to_tab
logger = getLogger("Browser") 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})") logger.error(f"chown/chmod exited with a non-zero exit code (chown: {code_chown}, chmod: {code_chmod})")
return False return False
return True 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): def find_plugin_folder(self, name):
for folder in listdir(self.plugin_path): for folder in listdir(self.plugin_path):
@@ -100,14 +143,18 @@ class PluginBrowser:
logger.debug("Unzipping...") logger.debug("Unzipping...")
ret = self._unzip_to_plugin_dir(res_zip, name, hash) ret = self._unzip_to_plugin_dir(res_zip, name, hash)
if ret: if ret:
logger.info(f"Installed {name} (Version: {version})") ret = await self._download_remote_binaries_for_plugin_with_name(name)
plugin_dir = self.find_plugin_folder(name) if ret:
if name in self.loader.plugins: logger.info(f"Installed {name} (Version: {version})")
self.loader.plugins[name].stop() plugin_dir = self.find_plugin_folder(name)
self.loader.plugins.pop(name, None) if name in self.loader.plugins:
await sleep(1) self.loader.plugins[name].stop()
self.loader.import_plugin(path.join(plugin_dir, "main.py"), plugin_dir) self.loader.plugins.pop(name, None)
# await inject_to_tab("SP", "window.syncDeckyPlugins()") 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: else:
self.log.fatal(f"SHA-256 Mismatch!!!! {name} (Version: {version})") self.log.fatal(f"SHA-256 Mismatch!!!! {name} (Version: {version})")
if self.loader.watcher: if self.loader.watcher:
+28
View File
@@ -2,11 +2,15 @@ import re
import ssl import ssl
import subprocess import subprocess
import uuid import uuid
import os
from subprocess import check_output from subprocess import check_output
from time import sleep from time import sleep
from hashlib import sha256
from io import BytesIO
import certifi import certifi
from aiohttp.web import Response, middleware from aiohttp.web import Response, middleware
from aiohttp import ClientSession
REMOTE_DEBUGGER_UNIT = "steam-web-debug-portforward.service" 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")
# 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: async def is_systemd_unit_active(unit_name: str) -> bool:
res = subprocess.run(["systemctl", "is-active", unit_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) res = subprocess.run(["systemctl", "is-active", unit_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return res.returncode == 0 return res.returncode == 0