summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek J. Clark <derkejohn.clark@gmail.com>2022-08-08 11:32:14 -0700
committerGitHub <noreply@github.com>2022-08-08 11:32:14 -0700
commit20094c5f752046a33287ef372fa973e919e83226 (patch)
treeed298251be183fc5f3151b19a10f7499c7d66e0d
parent198591dbd7b0b6dd311ab9265d4cda4a733ee280 (diff)
downloaddecky-loader-20094c5f752046a33287ef372fa973e919e83226.tar.gz
decky-loader-20094c5f752046a33287ef372fa973e919e83226.zip
Use Environment Variables (#123)
Uses environment variables instead of hard coding the "deck" user/group. This adds support for systems other than the steam deck that are using the DeckUI. * Use Environment Variables * Use method to get USER from a systemd root process * Fix imports. Add get_user and get_user_group methods in helpers.py. Removed duplicated code * Add separate setters/getters for user vars. Ensure sleep prevents race condition of user setter in while loop
-rw-r--r--backend/browser.py35
-rw-r--r--backend/helpers.py49
-rw-r--r--backend/main.py49
-rw-r--r--dist/install_nightly.sh16
-rw-r--r--[-rwxr-xr-x]dist/install_prerelease.sh7
-rw-r--r--dist/install_release.sh23
-rw-r--r--dist/uninstall.sh13
7 files changed, 126 insertions, 66 deletions
diff --git a/backend/browser.py b/backend/browser.py
index c58a97e5..190f8bd5 100644
--- a/backend/browser.py
+++ b/backend/browser.py
@@ -1,20 +1,22 @@
-from injector import get_tab
+# Full imports
+import json
+
+# Partial imports
+from aiohttp import ClientSession, web
+from asyncio import get_event_loop
+from concurrent.futures import ProcessPoolExecutor
+from hashlib import sha256
+from io import BytesIO
from logging import getLogger
from os import path, rename, listdir
from shutil import rmtree
-from aiohttp import ClientSession, web
-from io import BytesIO
-from zipfile import ZipFile
-from concurrent.futures import ProcessPoolExecutor
-from asyncio import get_event_loop
+from subprocess import call
from time import time
-from hashlib import sha256
-from subprocess import Popen
-from injector import inject_to_tab
-
-import json
+from zipfile import ZipFile
-import helpers
+# Local modules
+from helpers import get_ssl_context, get_user, get_user_group
+from injector import get_tab, inject_to_tab
class PluginInstallContext:
def __init__(self, artifact, name, version, hash) -> None:
@@ -41,8 +43,11 @@ class PluginBrowser:
return False
zip_file = ZipFile(zip)
zip_file.extractall(self.plugin_path)
- Popen(["chown", "-R", "deck:deck", self.plugin_path])
- Popen(["chmod", "-R", "555", self.plugin_path])
+ code_chown = call(["chown", "-R", get_user()+":"+get_user_group(), self.plugin_path])
+ code_chmod = call(["chmod", "-R", "555", self.plugin_path])
+ if code_chown != 0 or code_chmod != 0:
+ logger.error(f"chown/chmod exited with a non-zero exit code (chown: {code_chown}, chmod: {code_chmod})")
+ return False
return True
def find_plugin_folder(self, name):
@@ -83,7 +88,7 @@ class PluginBrowser:
self.log.info(f"Installing {name} (Version: {version})")
async with ClientSession() as client:
self.log.debug(f"Fetching {artifact}")
- res = await client.get(artifact, ssl=helpers.get_ssl_context())
+ res = await client.get(artifact, ssl=get_ssl_context())
if res.status == 200:
self.log.debug("Got 200. Reading...")
data = await res.read()
diff --git a/backend/helpers.py b/backend/helpers.py
index e8c2ce5b..68ac7cb3 100644
--- a/backend/helpers.py
+++ b/backend/helpers.py
@@ -1,11 +1,15 @@
-from aiohttp.web import middleware, Response
-import ssl
import certifi
+import ssl
import uuid
-ssl_ctx = ssl.create_default_context(cafile=certifi.where())
+from subprocess import check_output
+from time import sleep
+# global vars
csrf_token = str(uuid.uuid4())
+ssl_ctx = ssl.create_default_context(cafile=certifi.where())
+user = None
+group = None
def get_ssl_context():
return ssl_ctx
@@ -17,4 +21,41 @@ def get_csrf_token():
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/"):
return await handler(request)
- return Response(text='Forbidden', status='403') \ No newline at end of file
+ return Response(text='Forbidden', status='403')
+
+# Get the user by checking for the first logged in user. As this is run
+# by systemd at startup the process is likely to start before the user
+# logs in, so we will wait here until they are available. Note that
+# other methods such as getenv wont work as there was no $SUDO_USER to
+# start the systemd service.
+def set_user():
+ global user
+ cmd = "who | awk '{print $1}' | sort | head -1"
+ while user == None:
+ name = check_output(cmd, shell=True).decode().strip()
+ if name not in [None, '']:
+ user = name
+ sleep(0.1)
+
+# Get the global user. get_user must be called first.
+def get_user() -> str:
+ global user
+ if user == None:
+ raise ValueError("helpers.get_user method called before user variable was set. Run helpers.set_user first.")
+ return user
+
+# Set the global user group. get_user must be called first
+def set_user_group() -> str:
+ global group
+ global user
+ if user == None:
+ raise ValueError("helpers.set_user_dir method called before user variable was set. Run helpers.set_user first.")
+ if group == None:
+ group = check_output(["id", "-g", "-n", user]).decode().strip()
+
+# Get the group of the global user. set_user_group must be called first.
+def get_user_group() -> str:
+ global group
+ if group == None:
+ raise ValueError("helpers.get_user_group method called before group variable was set. Run helpers.set_user_group first.")
+ return group
diff --git a/backend/main.py b/backend/main.py
index 02cc0d56..4129f5db 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -1,10 +1,35 @@
-from logging import DEBUG, INFO, basicConfig, getLogger
-from os import getenv
+# Full imports
+import aiohttp_cors
+# Partial imports
from aiohttp import ClientSession
+from aiohttp.web import Application, run_app, static, get, Response
+from aiohttp_jinja2 import setup as jinja_setup
+from asyncio import get_event_loop, sleep
+from json import dumps, loads
+from logging import DEBUG, INFO, basicConfig, getLogger
+from os import getenv, path
+from subprocess import call
+
+# local modules
+from browser import PluginBrowser
+from helpers import csrf_middleware, get_csrf_token, get_user, get_user_group, set_user, set_user_group
+from injector import inject_to_tab, tab_has_global_var
+from loader import Loader
+from updater import Updater
+from utilities import Utilities
+# Ensure USER and GROUP vars are set first.
+# TODO: This isn't the best way to do this but supports the current
+# implementation. All the config load and environment setting eventually be
+# moved into init or a config/loader method.
+set_user()
+set_user_group()
+USER = get_user()
+GROUP = get_user_group()
+HOME_PATH = "/home/"+USER
CONFIG = {
- "plugin_path": getenv("PLUGIN_PATH", "/home/deck/homebrew/plugins"),
+ "plugin_path": getenv("PLUGIN_PATH", HOME_PATH+"/homebrew/plugins"),
"chown_plugin_path": getenv("CHOWN_PLUGIN_PATH", "1") == "1",
"server_host": getenv("SERVER_HOST", "127.0.0.1"),
"server_port": int(getenv("SERVER_PORT", "1337")),
@@ -14,26 +39,10 @@ CONFIG = {
basicConfig(level=CONFIG["log_level"], format="[%(module)s][%(levelname)s]: %(message)s")
-from asyncio import get_event_loop, sleep
-from json import dumps, loads
-from os import path
-from subprocess import call
-
-import aiohttp_cors
-from aiohttp.web import Application, run_app, static, get, Response
-from aiohttp_jinja2 import setup as jinja_setup
-
-from browser import PluginBrowser
-from injector import inject_to_tab, tab_has_global_var
-from loader import Loader
-from helpers import csrf_middleware, get_csrf_token
-from utilities import Utilities
-from updater import Updater
-
logger = getLogger("Main")
async def chown_plugin_dir(_):
- code_chown = call(["chown", "-R", "deck:deck", CONFIG["plugin_path"]])
+ code_chown = call(["chown", "-R", USER+":"+GROUP, CONFIG["plugin_path"]])
code_chmod = call(["chmod", "-R", "555", CONFIG["plugin_path"]])
if code_chown != 0 or code_chmod != 0:
logger.error(f"chown/chmod exited with a non-zero exit code (chown: {code_chown}, chmod: {code_chmod})")
diff --git a/dist/install_nightly.sh b/dist/install_nightly.sh
index 7fc34195..ca80cb27 100644
--- a/dist/install_nightly.sh
+++ b/dist/install_nightly.sh
@@ -4,12 +4,13 @@
echo "Installing Steam Deck Plugin Loader nightly..."
-HOMEBREW_FOLDER=/home/deck/homebrew
+USER_DIR="$(getent passwd $SUDO_USER | cut -d: -f6)"
+HOMEBREW_FOLDER="${USER_DIR}/homebrew"
# Create folder structure
rm -rf ${HOMEBREW_FOLDER}/services
-sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
-sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
+sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
+sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
# Download latest nightly build and install it
rm -rf /tmp/plugin_loader
@@ -22,7 +23,7 @@ chmod +x ${HOMEBREW_FOLDER}/services/PluginLoader
systemctl --user stop plugin_loader 2> /dev/null
systemctl --user disable plugin_loader 2> /dev/null
-rm -f /home/deck/.config/systemd/user/plugin_loader.service
+rm -f ${USER_DIR}/.config/systemd/user/plugin_loader.service
systemctl stop plugin_loader 2> /dev/null
systemctl disable plugin_loader 2> /dev/null
@@ -37,10 +38,9 @@ Type=simple
User=root
Restart=always
-ExecStart=/home/deck/homebrew/services/PluginLoader
-WorkingDirectory=/home/deck/homebrew/services
-
-Environment=PLUGIN_PATH=/home/deck/homebrew/plugins
+ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader
+WorkingDirectory=${HOMEBREW_FOLDER}/services
+Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins
[Install]
WantedBy=multi-user.target
diff --git a/dist/install_prerelease.sh b/dist/install_prerelease.sh
index 2bbd209e..f4916572 100755..100644
--- a/dist/install_prerelease.sh
+++ b/dist/install_prerelease.sh
@@ -4,12 +4,13 @@
echo "Installing Steam Deck Plugin Loader pre-release..."
-HOMEBREW_FOLDER=/home/deck/homebrew
+USER_DIR="$(getent passwd $SUDO_USER | cut -d: -f6)"
+HOMEBREW_FOLDER="${USER_DIR}/homebrew"
# # Create folder structure
rm -rf ${HOMEBREW_FOLDER}/services
-sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
-sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
+sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
+sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
# Download latest release and install it
RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "true"))")
diff --git a/dist/install_release.sh b/dist/install_release.sh
index cd690a8b..009997ad 100644
--- a/dist/install_release.sh
+++ b/dist/install_release.sh
@@ -4,33 +4,34 @@
echo "Installing Steam Deck Plugin Loader release..."
-HOMEBREW_FOLDER=/home/deck/homebrew
+USER_DIR="$(getent passwd $SUDO_USER | cut -d: -f6)"
+HOMEBREW_FOLDER="${USER_DIR}/homebrew"
# Create folder structure
-rm -rf ${HOMEBREW_FOLDER}/services
-sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
-sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
+rm -rf "${HOMEBREW_FOLDER}/services"
+sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
+sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
# Download latest release and install it
-curl -L https://github.com/SteamDeckHomebrew/PluginLoader/releases/latest/download/PluginLoader --output ${HOMEBREW_FOLDER}/services/PluginLoader
-chmod +x ${HOMEBREW_FOLDER}/services/PluginLoader
+curl -L https://github.com/SteamDeckHomebrew/PluginLoader/releases/latest/download/PluginLoader --output "${HOMEBREW_FOLDER}/services/PluginLoader"
+chmod +x "${HOMEBREW_FOLDER}/services/PluginLoader"
systemctl --user stop plugin_loader 2> /dev/null
systemctl --user disable plugin_loader 2> /dev/null
systemctl stop plugin_loader 2> /dev/null
systemctl disable plugin_loader 2> /dev/null
-rm -f /etc/systemd/system/plugin_loader.service
-cat > /etc/systemd/system/plugin_loader.service <<- EOM
+rm -f "/etc/systemd/system/plugin_loader.service"
+cat > "/etc/systemd/system/plugin_loader.service" <<- EOM
[Unit]
Description=SteamDeck Plugin Loader
[Service]
Type=simple
User=root
Restart=always
-ExecStart=/home/deck/homebrew/services/PluginLoader
-WorkingDirectory=/home/deck/homebrew/services
-Environment=PLUGIN_PATH=/home/deck/homebrew/plugins
+ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader
+WorkingDirectory=${HOMEBREW_FOLDER}/services
+Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins
[Install]
WantedBy=multi-user.target
EOM
diff --git a/dist/uninstall.sh b/dist/uninstall.sh
index a98ba0de..0680338d 100644
--- a/dist/uninstall.sh
+++ b/dist/uninstall.sh
@@ -1,17 +1,20 @@
#!/bin/sh
+[ "$UID" -eq 0 ] || exec sudo "$0" "$@"
+
echo "Uninstalling Steam Deck Plugin Loader..."
-HOMEBREW_FOLDER=/home/deck/homebrew
+USER_DIR="$(getent passwd $SUDO_USER | cut -d: -f6)"
+HOMEBREW_FOLDER="${USER_DIR}/homebrew"
# Disable and remove services
sudo systemctl disable --now plugin_loader.service > /dev/null
-sudo rm -f /home/deck/.config/systemd/user/plugin_loader.service
-sudo rm -f /etc/systemd/system/plugin_loader.service
+sudo rm -f "${USER_DIR}/.config/systemd/user/plugin_loader.service"
+sudo rm -f "/etc/systemd/system/plugin_loader.service"
# Remove temporary folder if it exists from the install process
-rm -rf /tmp/plugin_loader
+rm -rf "/tmp/plugin_loader"
# Cleanup services folder
-sudo rm ${HOMEBREW_FOLDER}/services/PluginLoader
+sudo rm "${HOMEBREW_FOLDER}/services/PluginLoader"