mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-13 04:05:04 +03:00
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
This commit is contained in:
+20
-15
@@ -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 logging import getLogger
|
||||||
from os import path, rename, listdir
|
from os import path, rename, listdir
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from aiohttp import ClientSession, web
|
from subprocess import call
|
||||||
from io import BytesIO
|
|
||||||
from zipfile import ZipFile
|
|
||||||
from concurrent.futures import ProcessPoolExecutor
|
|
||||||
from asyncio import get_event_loop
|
|
||||||
from time import time
|
from time import time
|
||||||
from hashlib import sha256
|
from zipfile import ZipFile
|
||||||
from subprocess import Popen
|
|
||||||
from injector import inject_to_tab
|
|
||||||
|
|
||||||
import json
|
# Local modules
|
||||||
|
from helpers import get_ssl_context, get_user, get_user_group
|
||||||
import helpers
|
from injector import get_tab, inject_to_tab
|
||||||
|
|
||||||
class PluginInstallContext:
|
class PluginInstallContext:
|
||||||
def __init__(self, artifact, name, version, hash) -> None:
|
def __init__(self, artifact, name, version, hash) -> None:
|
||||||
@@ -41,8 +43,11 @@ class PluginBrowser:
|
|||||||
return False
|
return False
|
||||||
zip_file = ZipFile(zip)
|
zip_file = ZipFile(zip)
|
||||||
zip_file.extractall(self.plugin_path)
|
zip_file.extractall(self.plugin_path)
|
||||||
Popen(["chown", "-R", "deck:deck", self.plugin_path])
|
code_chown = call(["chown", "-R", get_user()+":"+get_user_group(), self.plugin_path])
|
||||||
Popen(["chmod", "-R", "555", 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
|
return True
|
||||||
|
|
||||||
def find_plugin_folder(self, name):
|
def find_plugin_folder(self, name):
|
||||||
@@ -83,7 +88,7 @@ class PluginBrowser:
|
|||||||
self.log.info(f"Installing {name} (Version: {version})")
|
self.log.info(f"Installing {name} (Version: {version})")
|
||||||
async with ClientSession() as client:
|
async with ClientSession() as client:
|
||||||
self.log.debug(f"Fetching {artifact}")
|
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:
|
if res.status == 200:
|
||||||
self.log.debug("Got 200. Reading...")
|
self.log.debug("Got 200. Reading...")
|
||||||
data = await res.read()
|
data = await res.read()
|
||||||
|
|||||||
+45
-4
@@ -1,11 +1,15 @@
|
|||||||
from aiohttp.web import middleware, Response
|
|
||||||
import ssl
|
|
||||||
import certifi
|
import certifi
|
||||||
|
import ssl
|
||||||
import uuid
|
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())
|
csrf_token = str(uuid.uuid4())
|
||||||
|
ssl_ctx = ssl.create_default_context(cafile=certifi.where())
|
||||||
|
user = None
|
||||||
|
group = None
|
||||||
|
|
||||||
def get_ssl_context():
|
def get_ssl_context():
|
||||||
return ssl_ctx
|
return ssl_ctx
|
||||||
@@ -17,4 +21,41 @@ def get_csrf_token():
|
|||||||
async def csrf_middleware(request, handler):
|
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/"):
|
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 await handler(request)
|
||||||
return Response(text='Forbidden', status='403')
|
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
|
||||||
|
|||||||
+29
-20
@@ -1,10 +1,35 @@
|
|||||||
from logging import DEBUG, INFO, basicConfig, getLogger
|
# Full imports
|
||||||
from os import getenv
|
import aiohttp_cors
|
||||||
|
|
||||||
|
# Partial imports
|
||||||
from aiohttp import ClientSession
|
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 = {
|
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",
|
"chown_plugin_path": getenv("CHOWN_PLUGIN_PATH", "1") == "1",
|
||||||
"server_host": getenv("SERVER_HOST", "127.0.0.1"),
|
"server_host": getenv("SERVER_HOST", "127.0.0.1"),
|
||||||
"server_port": int(getenv("SERVER_PORT", "1337")),
|
"server_port": int(getenv("SERVER_PORT", "1337")),
|
||||||
@@ -14,26 +39,10 @@ CONFIG = {
|
|||||||
|
|
||||||
basicConfig(level=CONFIG["log_level"], format="[%(module)s][%(levelname)s]: %(message)s")
|
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")
|
logger = getLogger("Main")
|
||||||
|
|
||||||
async def chown_plugin_dir(_):
|
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"]])
|
code_chmod = call(["chmod", "-R", "555", CONFIG["plugin_path"]])
|
||||||
if code_chown != 0 or code_chmod != 0:
|
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})")
|
logger.error(f"chown/chmod exited with a non-zero exit code (chown: {code_chown}, chmod: {code_chmod})")
|
||||||
|
|||||||
Vendored
+8
-8
@@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
echo "Installing Steam Deck Plugin Loader nightly..."
|
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
|
# Create folder structure
|
||||||
rm -rf ${HOMEBREW_FOLDER}/services
|
rm -rf ${HOMEBREW_FOLDER}/services
|
||||||
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
|
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
|
||||||
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
|
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
|
||||||
|
|
||||||
# Download latest nightly build and install it
|
# Download latest nightly build and install it
|
||||||
rm -rf /tmp/plugin_loader
|
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 stop plugin_loader 2> /dev/null
|
||||||
systemctl --user disable 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 stop plugin_loader 2> /dev/null
|
||||||
systemctl disable plugin_loader 2> /dev/null
|
systemctl disable plugin_loader 2> /dev/null
|
||||||
@@ -37,10 +38,9 @@ Type=simple
|
|||||||
User=root
|
User=root
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
||||||
ExecStart=/home/deck/homebrew/services/PluginLoader
|
ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader
|
||||||
WorkingDirectory=/home/deck/homebrew/services
|
WorkingDirectory=${HOMEBREW_FOLDER}/services
|
||||||
|
Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins
|
||||||
Environment=PLUGIN_PATH=/home/deck/homebrew/plugins
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
+4
-3
@@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
echo "Installing Steam Deck Plugin Loader pre-release..."
|
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
|
# # Create folder structure
|
||||||
rm -rf ${HOMEBREW_FOLDER}/services
|
rm -rf ${HOMEBREW_FOLDER}/services
|
||||||
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
|
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
|
||||||
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
|
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
|
||||||
|
|
||||||
# Download latest release and install it
|
# Download latest release and install it
|
||||||
RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "true"))")
|
RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "true"))")
|
||||||
|
|||||||
Vendored
+12
-11
@@ -4,33 +4,34 @@
|
|||||||
|
|
||||||
echo "Installing Steam Deck Plugin Loader release..."
|
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
|
# Create folder structure
|
||||||
rm -rf ${HOMEBREW_FOLDER}/services
|
rm -rf "${HOMEBREW_FOLDER}/services"
|
||||||
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/services
|
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
|
||||||
sudo -u deck mkdir -p ${HOMEBREW_FOLDER}/plugins
|
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
|
||||||
|
|
||||||
# Download latest release and install it
|
# Download latest release and install it
|
||||||
curl -L https://github.com/SteamDeckHomebrew/PluginLoader/releases/latest/download/PluginLoader --output ${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
|
chmod +x "${HOMEBREW_FOLDER}/services/PluginLoader"
|
||||||
|
|
||||||
systemctl --user stop plugin_loader 2> /dev/null
|
systemctl --user stop plugin_loader 2> /dev/null
|
||||||
systemctl --user disable plugin_loader 2> /dev/null
|
systemctl --user disable plugin_loader 2> /dev/null
|
||||||
|
|
||||||
systemctl stop plugin_loader 2> /dev/null
|
systemctl stop plugin_loader 2> /dev/null
|
||||||
systemctl disable plugin_loader 2> /dev/null
|
systemctl disable plugin_loader 2> /dev/null
|
||||||
rm -f /etc/systemd/system/plugin_loader.service
|
rm -f "/etc/systemd/system/plugin_loader.service"
|
||||||
cat > /etc/systemd/system/plugin_loader.service <<- EOM
|
cat > "/etc/systemd/system/plugin_loader.service" <<- EOM
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=SteamDeck Plugin Loader
|
Description=SteamDeck Plugin Loader
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=root
|
User=root
|
||||||
Restart=always
|
Restart=always
|
||||||
ExecStart=/home/deck/homebrew/services/PluginLoader
|
ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader
|
||||||
WorkingDirectory=/home/deck/homebrew/services
|
WorkingDirectory=${HOMEBREW_FOLDER}/services
|
||||||
Environment=PLUGIN_PATH=/home/deck/homebrew/plugins
|
Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOM
|
EOM
|
||||||
|
|||||||
Vendored
+8
-5
@@ -1,17 +1,20 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
[ "$UID" -eq 0 ] || exec sudo "$0" "$@"
|
||||||
|
|
||||||
echo "Uninstalling Steam Deck Plugin Loader..."
|
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
|
# Disable and remove services
|
||||||
sudo systemctl disable --now plugin_loader.service > /dev/null
|
sudo systemctl disable --now plugin_loader.service > /dev/null
|
||||||
sudo rm -f /home/deck/.config/systemd/user/plugin_loader.service
|
sudo rm -f "${USER_DIR}/.config/systemd/user/plugin_loader.service"
|
||||||
sudo rm -f /etc/systemd/system/plugin_loader.service
|
sudo rm -f "/etc/systemd/system/plugin_loader.service"
|
||||||
|
|
||||||
# Remove temporary folder if it exists from the install process
|
# Remove temporary folder if it exists from the install process
|
||||||
rm -rf /tmp/plugin_loader
|
rm -rf "/tmp/plugin_loader"
|
||||||
|
|
||||||
# Cleanup services folder
|
# Cleanup services folder
|
||||||
sudo rm ${HOMEBREW_FOLDER}/services/PluginLoader
|
sudo rm "${HOMEBREW_FOLDER}/services/PluginLoader"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user