Files
lutris/utils/appimage/AppRun
Daniel Johnson dcb0f518e1 appimage: make WebKit login work on non-Ubuntu hosts
Three related bugs prevented the AppImage's WebKit-based service
login from working on Fedora / Arch / openSUSE — invisible on Ubuntu
because the host happens to satisfy the AppDir's missing pieces.

1. TLS backend not bundled. linuxdeploy-plugin-gtk copies libgio but
   not the GIO modules directory that holds glib-networking's
   libgiognutls.so. Without it GIO falls back to a compile-time libdir
   that doesn't exist off-Debian, and WebKit reports "TLS is not
   available" on the first HTTPS request. Copy the modules directory
   into $APPDIR/usr/lib/gio/modules with an $ORIGIN/../.. RPATH, add
   glib-networking to apt explicitly (it was pulled transitively but
   its modules weren't being copied), and export GIO_MODULE_DIR in
   AppRun.

2. WebKit shared libraries not bundled. libwebkit2gtk-4.1 and
   libjavascriptcoregtk-4.1 are loaded lazily via gi.repository when
   the user clicks a login button, so they never appear in any
   binary's NEEDED chain — linuxdeploy has no reason to bundle them.
   On non-Ubuntu hosts dlopen() falls through to the host copies with
   different symbols, e.g. `undefined symbol: webkit_web_context_new`.
   Pass both sonames to linuxdeploy explicitly.

3. WebKit helper processes not bundled and hardcoded path unreachable.
   WebKit2 4.1 forks WebKitNetworkProcess / WebKitWebProcess from a
   compile-time path baked into libwebkit2gtk-4.1.so.0
   (/usr/lib/x86_64-linux-gnu/webkit2gtk-4.1/). linuxdeploy bundles
   shared libraries, not auxiliary executables, and WEBKIT_EXEC_PATH
   was removed upstream — the path is only overridable by byte-patching
   the .so. Copy the webkit2gtk-4.1/ directory into the AppDir with
   $ORIGIN/.. RPATH on each helper, and byte-patch the hardcoded
   compile-time path inside libwebkit2gtk-4.1.so.0 to a writable
   /tmp/.lutris-appimage.dir/webkit2gtk-4.1 (same byte length). AppRun
   creates the symlink there before launch.

Also disable WebKit's bubblewrap sandbox
(WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1): bwrap opens a fresh
mount namespace that can't see the AppImage's FUSE mount at
/tmp/.mount_LutrisXXX, so any helper spawned inside it fails to reach
either the symlink target or the bundled libs. Lutris already runs
unsandboxed and spawns Wine, so an additional WebKit sandbox buys
negligible isolation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-01 19:32:36 -04:00

102 lines
4.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# AppRun entry point for the Lutris AppImage.
#
# Two responsibilities:
# 1. Source linuxdeploy-plugin-gtk's hook so GI_TYPELIB_PATH, GDK_PIXBUF_*,
# XDG_DATA_DIRS, etc. point inside the AppDir.
# 2. Launch bin/lutris with the bundled Python interpreter.
#
# Lutris is intentionally NOT sandboxed: it must call host binaries (xrandr,
# 7z, fuser, wine, the user's installed runners), read the user's $HOME,
# and access mounted drives. We deliberately leave PATH and PYTHONPATH
# alone so host tools and host Python (used by host subprocesses like
# umu-run) work as they do outside the AppImage. The build script
# installs Lutris's package files via --install-layout=deb so the
# bundled Python finds them via its standard dist-packages search,
# without us needing to advertise an AppDir path on PYTHONPATH.
set -e
HERE="$(dirname "$(readlink -f "${0}")")"
# linuxdeploy-plugin-gtk writes its environment setup into apprun-hooks/.
# Source every hook it dropped so we inherit the GTK/Pixbuf/typelib paths.
if [ -d "$HERE/apprun-hooks" ]; then
for hook in "$HERE"/apprun-hooks/*.sh; do
# shellcheck disable=SC1090
[ -r "$hook" ] && . "$hook"
done
fi
export APPDIR="$HERE"
# WebKit2 4.1 spawns helper processes (WebKitNetworkProcess,
# WebKitWebProcess) from a compile-time path baked into
# libwebkit2gtk-4.1.so.0. WEBKIT_EXEC_PATH does not exist in this
# build, so the build script byte-patched the hardcoded path inside
# the .so to /tmp/.lutris-appimage.dir/webkit2gtk-4.1 (same length as
# the original). Symlink that location to our bundled helpers before
# launching.
#
# Disable WebKit's bubblewrap sandbox: it creates a fresh mount
# namespace with only paths WebKit's own policy bind-mounts, and the
# AppImage's FUSE mount at /tmp/.mount_LutrisXXX is not one of them.
# The helpers execvp inside the sandbox and can't reach either the
# symlink target or the bundled libs. Lutris already runs with full
# user-home access and spawns Wine binaries — a WebKit sandbox layered
# on top adds negligible additional isolation, and disabling it is
# standard practice for AppImage-packaged WebKitGTK apps.
if [ -d "$HERE/usr/lib/webkit2gtk-4.1" ]; then
mkdir -p /tmp/.lutris-appimage.dir
ln -snf "$HERE/usr/lib/webkit2gtk-4.1" /tmp/.lutris-appimage.dir/webkit2gtk-4.1
export WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1
fi
# GLib's GIO looks for extension modules (TLS backends, proxy resolvers,
# etc.) at a compile-time libdir. Point it at our bundled copy explicitly;
# otherwise WebKit reports "TLS is not available" and any HTTPS login flow
# fails at the first request. This is silently masked on Debian/Ubuntu
# hosts because the compile-time fallback path exists there, but breaks
# on Fedora/Arch/openSUSE where it doesn't.
if [ -d "$HERE/usr/lib/gio/modules" ]; then
export GIO_MODULE_DIR="$HERE/usr/lib/gio/modules"
fi
# Intentionally do NOT export LD_LIBRARY_PATH. linuxdeploy already set
# RPATH=$ORIGIN/.. on every bundled binary, so they find their sibling libs
# without an env override. Exporting LD_LIBRARY_PATH here would leak into
# subprocesses — and Lutris launches host binaries constantly (xrandr, 7z,
# fuser, /usr/bin/flatpak, wine, etc.). Forcing them to load our older
# bundled libssl/libcrypto/libstdc++ breaks any host tool whose own deps
# were built against newer symbols. The cost of this discipline is that
# anything we copied into the AppDir manually (PyGObject's _gi.so,
# python3-dbus' bindings) must have its RPATH patched by the build script,
# since linuxdeploy only patches files it deploys itself.
unset LD_LIBRARY_PATH
# Python: find the bundled interpreter and site-packages. We accept any
# python3.X under usr/bin so this script doesn't need to be rev'd when the
# build image's Python minor version changes.
PYTHON_BIN=""
for cand in "$HERE"/usr/bin/python3.* "$HERE"/usr/bin/python3; do
if [ -x "$cand" ] && [ ! -L "$cand" ]; then
PYTHON_BIN="$cand"
break
fi
done
if [ -z "$PYTHON_BIN" ]; then
# Fallback: host python3. The AppImage is less portable this way, but
# at least it boots so the user sees a real error rather than nothing.
PYTHON_BIN="$(command -v python3 || true)"
fi
if [ -z "$PYTHON_BIN" ]; then
echo "Lutris AppImage: no python3 interpreter found in AppDir or host" >&2
exit 1
fi
# bin/lutris strips /home paths from sys.path unless this is set, which
# would also drop the AppDir paths Python auto-discovered when extracted
# AppImages live under /home (e.g. ~/Applications).
export LUTRIS_ALLOW_LOCAL_PYTHON_PACKAGES=1
exec "$PYTHON_BIN" "$HERE/usr/bin/lutris" "$@"