diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 299e379..1009a67 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,9 @@ on: - master pull_request: +env: + APPIMAGE_EXTRACT_AND_RUN: "1" + jobs: build-qtwebengine: runs-on: ubuntu-24.04 @@ -109,3 +112,114 @@ jobs: ldd artifacts/webkitgtk/safe-exam-browser | grep -q 'libwebkit2gtk-4.1' ! ldd artifacts/webkitgtk/safe-exam-browser | grep -q 'libQt6WebEngine' artifacts/webkitgtk/safe-exam-browser --version + + # Portable AppImages are built on Ubuntu 22.04 (glibc 2.35) for Ubuntu 22.04+ / Fedora 39+. + # Full AppImage packaging is heavy; run on main/master pushes (not every PR). + build-appimage: + if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') + runs-on: ubuntu-latest + container: + image: ubuntu:22.04 + steps: + - name: Bootstrap container packages + run: | + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + ca-certificates \ + git \ + wget \ + sudo \ + binutils + + - uses: actions/checkout@v7 + + - name: Build AppImage artifacts + run: | + chmod +x scripts/build-release.sh + scripts/build-release.sh "0.0.0-ci" + + - name: Upload AppImage artifacts + uses: actions/upload-artifact@v7 + with: + name: safe-exam-browser-appimage + path: | + dist/*.AppImage + if-no-files-found: error + + appimage-smoke-ubuntu: + needs: + - build-appimage + runs-on: ubuntu-24.04 + steps: + - name: Install AppImage host runtime libs + run: | + # GL/EGL/OpenGL stay on the host (not bundled). Fonts/GTK bits help the WebKit AppImage. + # AppImages only ship the xcb Qt plugin, so smoke under Xvfb. + sudo apt-get update + sudo apt-get install -y \ + libegl1 \ + libgl1 \ + libgles2 \ + libopengl0 \ + libfreetype6 \ + fontconfig \ + libxkbcommon0 \ + libgtk-3-0t64 \ + libwebkit2gtk-4.1-0 \ + xvfb + + - name: Download AppImage artifacts + uses: actions/download-artifact@v8 + with: + name: safe-exam-browser-appimage + path: dist + + - name: Smoke-test AppImages on Ubuntu + env: + QT_QPA_PLATFORM: xcb + APPIMAGE_EXTRACT_AND_RUN: "1" + run: | + chmod +x dist/*.AppImage + for appimage in dist/*.AppImage; do + echo "Running ${appimage} --version" + xvfb-run -a "${appimage}" --version + done + + appimage-smoke-fedora: + needs: + - build-appimage + runs-on: ubuntu-latest + container: + image: fedora:latest + steps: + - name: Install AppImage host runtime libs + run: | + dnf install -y \ + libglvnd-egl \ + libglvnd-glx \ + libglvnd-opengl \ + mesa-libEGL \ + mesa-libGL \ + freetype \ + fontconfig \ + libxkbcommon \ + gtk3 \ + webkit2gtk4.1 \ + xorg-x11-server-Xvfb + + - name: Download AppImage artifacts + uses: actions/download-artifact@v8 + with: + name: safe-exam-browser-appimage + path: dist + + - name: Smoke-test AppImages on Fedora + env: + QT_QPA_PLATFORM: xcb + APPIMAGE_EXTRACT_AND_RUN: "1" + run: | + chmod +x dist/*.AppImage + for appimage in dist/*.AppImage; do + echo "Running ${appimage} --version" + xvfb-run -a "${appimage}" --version + done diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7f986c4..a7fb786 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,10 +14,24 @@ on: permissions: contents: write +env: + APPIMAGE_EXTRACT_AND_RUN: "1" + jobs: build-linux: - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest + container: + image: ubuntu:22.04 steps: + - name: Bootstrap container packages + run: | + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + ca-certificates \ + git \ + wget \ + sudo + - uses: actions/checkout@v7 - name: Resolve release version @@ -53,6 +67,8 @@ jobs: body: | Thanks to everyone who contributed to this release. + Supported targets: Ubuntu 22.04+, Fedora 39+ (x86_64), glibc >= 2.35. + GitHub generated release notes below include the commit summary and new contributors automatically. files: | dist/*.AppImage diff --git a/README.md b/README.md index aa67a1c..6409f9c 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,11 @@ so you can just focus on your exam. ### Running Everywhere Safe Exam Browser has options for QtWebEngine and WebKitGTK. -We've also packaged all of the dependencies inside AppImage files so -Safe Exam Browser for Linux really can run anywhere. +We've also packaged dependencies inside AppImage files for portable installs. + +**Supported AppImage targets (x86_64):** Ubuntu 22.04+, Fedora 39+, and other +distributions with **glibc ≥ 2.35**. Release AppImages are built on Ubuntu 22.04 +so they stay compatible across those systems. ## Getting Started @@ -35,10 +38,10 @@ and `libgtk-3-dev` installed so we can use the fallback engine. ### How to Build -Note: This is for binary builds, for AppImage builds you can use -prebuilt images or utilize `./scripts/build-release.sh`, the dependencies should -be installed automatically on debian systems. It is recommended to build inside -of a debian system or a debian container. +Note: This is for binary builds. For AppImage builds use prebuilt releases or +`./scripts/build-release.sh` (dependencies install automatically on Debian/Ubuntu). +Build AppImages on **Ubuntu 22.04** (or an Ubuntu 22.04 container) so the glibc +floor stays at 2.35 and the result runs on Ubuntu 22.04+ and Fedora 39+. For binary builds, it's pretty simple: diff --git a/scripts/build-release.sh b/scripts/build-release.sh index 3f20970..9d4883a 100755 --- a/scripts/build-release.sh +++ b/scripts/build-release.sh @@ -9,32 +9,41 @@ PROJECT_FILE="${PROJECT_DIR}/seb-linux-qt.pro" ARTIFACT_DIR="${PROJECT_DIR}/dist" TOOLS_DIR="${PROJECT_DIR}/build-tools" PACKAGE_NAME="safe-exam-browser" +# AppImages inherit the build host glibc. Ubuntu 22.04 sets the floor at 2.35. +MAX_GLIBC_VERSION="${MAX_GLIBC_VERSION:-2.35}" LINUXDEPLOY_VERSION="1-alpha-20250213-2" LINUXDEPLOY_PLUGIN_QT_VERSION="1-alpha-20250213-1" LINUXDEPLOY_SHA256="4648f278ab3ef31f819e67c30d50f462640e5365a77637d7e6f2ad9fd0b4522a" LINUXDEPLOY_PLUGIN_QT_SHA256="15106be885c1c48a021198e7e1e9a48ce9d02a86dd0a1848f00bdbf3c1c92724" LINUXDEPLOY_URL="https://github.com/linuxdeploy/linuxdeploy/releases/download/${LINUXDEPLOY_VERSION}/linuxdeploy-x86_64.AppImage" LINUXDEPLOY_PLUGIN_QT_URL="https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/${LINUXDEPLOY_PLUGIN_QT_VERSION}/linuxdeploy-plugin-qt-x86_64.AppImage" -LINUXBUILD_EXTRA_ARGS=( - -l /usr/lib/x86_64-linux-gnu/libssl.so.3 - -l /usr/lib/x86_64-linux-gnu/libsoftokn3.so - -l /usr/lib/x86_64-linux-gnu/libatomic.so.1 - -l /usr/lib/x86_64-linux-gnu/libdeflate.so.0 - -l /usr/lib/x86_64-linux-gnu/libjbig.so.0 - -l /usr/lib/x86_64-linux-gnu/libjpeg.so.62 - -l /usr/lib/x86_64-linux-gnu/libLerc.so.4 - -l /usr/lib/x86_64-linux-gnu/libQt6Pdf.so.6 - -l /usr/lib/x86_64-linux-gnu/libQt6QmlWorkerScript.so.6 - -l /usr/lib/x86_64-linux-gnu/libsmime3.so - -l /usr/lib/x86_64-linux-gnu/libssh2.so.1 - -l /usr/lib/x86_64-linux-gnu/libtiff.so.6 - -l /usr/lib/x86_64-linux-gnu/libxcb-cursor.so.0 - -l /usr/lib/x86_64-linux-gnu/libxcb-xinput.so.0 + +# Prefer extract-and-run so nested AppImages work without FUSE (CI containers). +export APPIMAGE_EXTRACT_AND_RUN="${APPIMAGE_EXTRACT_AND_RUN:-1}" + +# Library basenames to bundle via linuxdeploy -l (resolved at runtime). +REQUIRED_EXTRA_LIBS=( + libssl.so.3 + libsoftokn3.so + libatomic.so.1 + libdeflate.so.0 + libfreetype.so.6 + libjbig.so.0 + libjpeg.so.62 + libQt6Pdf.so.6 + libQt6QmlWorkerScript.so.6 + libsmime3.so + libssh2.so.1 + libxcb-cursor.so.0 + libxcb-xinput.so.0 ) -# -l /usr/lib/x86_64-linux-gnu/libnghttp3.so.9 -# -l /usr/lib/x86_64-linux-gnu/libngtcp2.so.16 -l /usr/lib/x86_64-linux-gnu/libngtcp2_crypto_gnutls.so.8 -# -l /usr/lib/x86_64-linux-gnu/libQt6QmlMeta.so.6 -# -l /usr/lib/x86_64-linux-gnu/libxml2.so.16 + +# Prefer newer sonames first. Jammy: libtiff.so.5 / libLerc.so.3; Noble+: .6 / .4. +ALTERNATE_EXTRA_LIBS=( + "libtiff.so.6|libtiff.so.5" + "libLerc.so.4|libLerc.so.3" +) + echo "Variables set" verify_sha256() { @@ -86,6 +95,119 @@ run_logged() { fi } +resolve_library_path() { + local lib_name="$1" + local resolved="" + local candidate + + if command -v ldconfig >/dev/null; then + resolved="$(ldconfig -p 2>/dev/null | awk -v name="${lib_name}" ' + $1 == name { + for (i = 1; i <= NF; i++) { + if ($i ~ /^\//) { + print $i + exit + } + } + } + ')" + fi + + # NSS modules (e.g. libsoftokn3.so) live under .../nss/ and are often absent + # from ldconfig -p / the top-level multiarch lib dir. + if [[ -z "${resolved}" || ! -e "${resolved}" ]]; then + for candidate in \ + "/usr/lib/x86_64-linux-gnu/nss/${lib_name}" \ + "/usr/lib/x86_64-linux-gnu/${lib_name}" \ + "/usr/lib64/nss/${lib_name}" \ + "/usr/lib64/${lib_name}" \ + "/usr/lib/nss/${lib_name}" \ + "/usr/lib/${lib_name}"; do + if [[ -e "${candidate}" ]]; then + resolved="${candidate}" + break + fi + done + fi + + if [[ -n "${resolved}" && -e "${resolved}" ]]; then + readlink -f "${resolved}" 2>/dev/null || printf '%s\n' "${resolved}" + return 0 + fi + + return 1 +} + +build_linuxdeploy_extra_args() { + local lib_name + local lib_path + local alt_group + local found + + LINUXBUILD_EXTRA_ARGS=() + + for lib_name in "${REQUIRED_EXTRA_LIBS[@]}"; do + if ! lib_path="$(resolve_library_path "${lib_name}")"; then + echo "Required library not found: ${lib_name}" >&2 + exit 1 + fi + LINUXBUILD_EXTRA_ARGS+=(-l "${lib_path}") + done + + for alt_group in "${ALTERNATE_EXTRA_LIBS[@]}"; do + found=0 + IFS='|' read -r -a alt_libs <<< "${alt_group}" + for lib_name in "${alt_libs[@]}"; do + if lib_path="$(resolve_library_path "${lib_name}")"; then + LINUXBUILD_EXTRA_ARGS+=(-l "${lib_path}") + found=1 + break + fi + done + if [[ "${found}" -eq 0 ]]; then + echo "Warning: none of these libraries found (optional): ${alt_group}" >&2 + fi + done +} + +version_gt() { + # Return 0 if $1 > $2 (dotted numeric versions). + local left="$1" + local right="$2" + [[ "$(printf '%s\n' "${left}" "${right}" | sort -V | tail -n1)" == "${left}" && "${left}" != "${right}" ]] +} + +check_glibc_symbols() { + local app_dir="$1" + local max_version="$2" + local elf_file + local symbol + local version + local too_new=0 + + if ! command -v objdump >/dev/null; then + echo "objdump not found; cannot verify glibc symbol versions" >&2 + exit 1 + fi + + echo "Checking glibc symbol versions in ${app_dir} (max ${max_version})" + + while IFS= read -r -d '' elf_file; do + while IFS= read -r symbol; do + version="${symbol#GLIBC_}" + if version_gt "${version}" "${max_version}"; then + echo "glibc symbol ${symbol} in ${elf_file} exceeds ${max_version}" >&2 + too_new=1 + fi + done < <(objdump -T "${elf_file}" 2>/dev/null | grep -oE 'GLIBC_[0-9]+(\.[0-9]+)+' | sort -u || true) + done < <(find "${app_dir}" -type f \( -perm -111 -o -name '*.so*' \) -print0) + + if [[ "${too_new}" -ne 0 ]]; then + echo "AppDir requires glibc newer than ${max_version}; rebuild on an older base" >&2 + exit 1 + fi +} + build_appimage() { local config="$1" local build_dir="$2" @@ -117,6 +239,8 @@ build_appimage() { "${LINUXBUILD_EXTRA_ARGS[@]}" popd >/dev/null + check_glibc_symbols "${app_dir}" "${MAX_GLIBC_VERSION}" + appimage_path="$(find "${appimage_output_dir}" -maxdepth 1 -type f -name '*.AppImage' -print -quit)" if [[ -z "${appimage_path}" ]]; then echo "linuxdeploy did not produce an AppImage" >&2 @@ -127,14 +251,17 @@ build_appimage() { } echo "Installing dependencies" -${ROOT_DIR}/scripts/dependencies.sh +"${ROOT_DIR}/scripts/dependencies.sh" unset QML_SOURCES_PATHS unset QMAKE unset EXTRA_QT_MODULES +unset EXTRA_PLATFORM_PLUGINS export QML_SOURCES_PATHS="$PROJECT_DIR"/src export QMAKE=$(which qmake6) export EXTRA_QT_MODULES="libssl;libcrypto" +# Menu/anti-cheat lockdown uses QT_QPA_PLATFORM=linuxfb on a bare VT. +export EXTRA_PLATFORM_PLUGINS="libqlinuxfb.so" echo "Environment variables set" mkdir -p "${BUILD_DIR}" "${ARTIFACT_DIR}" "${TOOLS_DIR}" @@ -150,6 +277,9 @@ download_verified_tool \ "${TOOLS_DIR}/linuxdeploy-plugin-qt-x86_64.AppImage" \ "${LINUXDEPLOY_PLUGIN_QT_SHA256}" +build_linuxdeploy_extra_args +echo "Resolved ${#LINUXBUILD_EXTRA_ARGS[@]} linuxdeploy extra library args" + echo "Building for QtWebEngine" build_appimage \ "force_qtwebengine" \ diff --git a/scripts/dependencies.sh b/scripts/dependencies.sh index 8edf098..3b07a33 100755 --- a/scripts/dependencies.sh +++ b/scripts/dependencies.sh @@ -1,37 +1,73 @@ #!/bin/bash +set -euo pipefail -if command -v apt >/dev/null; then - echo "installing dependencies" - sudo apt-get update - sudo apt-get install -y \ - build-essential \ - desktop-file-utils \ - dpkg-dev \ - libqt6svg6-dev \ - qt6-base-dev \ - qt6-tools-dev-tools \ - qt6-webengine-dev \ - libwebkit2gtk-4.1-dev \ - libgtk-3-dev \ - shared-mime-info \ - zlib1g-dev \ - libssl-dev \ - file \ - libatomic1 \ - libdeflate0 \ - libjbig0 \ - liblerc4 \ - libngtcp2-dev \ - libngtcp2-crypto-gnutls-dev \ - libqt6pdf6 \ - libqt6qmlworkerscript6 \ - libnss3 \ - libssh2-1 \ - libssl3 \ - libtiff-dev \ - libxcb-cursor0 \ - libxcb-xinput0 \ +# Release AppImage builds are expected on Debian/Ubuntu (preferably Ubuntu 22.04). +# Non-Debian systems skip install; use a Debian/Ubuntu container for packaging. + +if ! command -v apt-get >/dev/null; then + echo "detected non-debian system, skipping dependency install" + exit 0 +fi + +run_as_root() { + if [[ "${EUID}" -eq 0 ]]; then + "$@" + else + sudo "$@" + fi +} + +echo "installing dependencies" + +run_as_root apt-get update + +PACKAGES=( + binutils + build-essential + desktop-file-utils + dpkg-dev + libqt6svg6-dev + qt6-base-dev + qt6-tools-dev-tools + qt6-webengine-dev + libwebkit2gtk-4.1-dev + libgtk-3-dev + shared-mime-info + zlib1g-dev + libssl-dev + file + libatomic1 + libdeflate0 + libjbig0 + libfreetype6 + libngtcp2-dev + libngtcp2-crypto-gnutls-dev + libqt6pdf6 + libqt6qmlworkerscript6 + libnss3 + libssh2-1 + libssl3 + libxcb-cursor0 + libxcb-xinput0 libjpeg62 + qt6-qpa-plugins + wget +) + +# Jammy: libtiff5 / liblerc3; Noble+: libtiff6 / liblerc4. +if apt-cache show libtiff6 >/dev/null 2>&1; then + PACKAGES+=(libtiff6) +elif apt-cache show libtiff5 >/dev/null 2>&1; then + PACKAGES+=(libtiff5) +fi +PACKAGES+=(libtiff-dev) + +if apt-cache show liblerc4 >/dev/null 2>&1; then + PACKAGES+=(liblerc4) +elif apt-cache show liblerc3 >/dev/null 2>&1; then + PACKAGES+=(liblerc3) else - echo "detected non-debian system, skipping dependency install" + echo "optional package not available, skipping: liblerc*" fi + +run_as_root apt-get install -y "${PACKAGES[@]}" diff --git a/src/main.cpp b/src/main.cpp index a645f8b..c8bd9b7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +141,29 @@ bool hasArgument(int argc, char *argv[], const QString &value) return false; } +// QApplication is not created yet, so probe known plugin locations (AppImage APPDIR + distro paths). +static bool qtPlatformPluginAvailable(const QString &platformName) +{ + const QString fileName = QStringLiteral("libq") + platformName + QStringLiteral(".so"); + QStringList dirs; + + const QByteArray appDir = qgetenv("APPDIR"); + if (!appDir.isEmpty()) { + dirs << (QString::fromLocal8Bit(appDir) + QStringLiteral("/usr/plugins/platforms")); + } + + dirs << QStringLiteral("/usr/lib/x86_64-linux-gnu/qt6/plugins/platforms") + << QStringLiteral("/usr/lib/qt6/plugins/platforms") + << QStringLiteral("/usr/lib64/qt6/plugins/platforms"); + + for (const QString &dir : dirs) { + if (QFileInfo::exists(dir + QLatin1Char('/') + fileName)) { + return true; + } + } + return false; +} + static void appendPkexecEnvironmentVariable(QStringList &args, const char *name) { const QByteArray value = qgetenv(name); @@ -148,6 +172,53 @@ static void appendPkexecEnvironmentVariable(QStringList &args, const char *name) } } +// When running from an AppImage, applicationFilePath() is under the FUSE mount +// (/tmp/.mount_*/usr/bin/...). Root cannot execute that path after pkexec. +// Prefer $APPIMAGE so elevation re-runs the outer AppImage file instead. +static QString elevatedExecutablePath() +{ + const QByteArray appImage = qgetenv("APPIMAGE"); + if (!appImage.isEmpty()) { + const QString path = QString::fromLocal8Bit(appImage); + if (QFileInfo::exists(path)) { + return path; + } + } + return QCoreApplication::applicationFilePath(); +} + +// Build pkexec argv without --keep-cwd (unsupported on Ubuntu 22.04 / pkexec 0.105). +// Preserve the caller's cwd via /bin/sh so AppImage and relative paths keep working. +static QStringList buildPkexecArguments(const QStringList &appArgs, + const QStringList &extraEnvAssignments = {}) +{ + QStringList pkexecArgs; + pkexecArgs << QStringLiteral("env"); + appendPkexecEnvironmentVariable(pkexecArgs, "DISPLAY"); + appendPkexecEnvironmentVariable(pkexecArgs, "WAYLAND_DISPLAY"); + appendPkexecEnvironmentVariable(pkexecArgs, "XAUTHORITY"); + appendPkexecEnvironmentVariable(pkexecArgs, "XDG_RUNTIME_DIR"); + appendPkexecEnvironmentVariable(pkexecArgs, "XDG_SESSION_TYPE"); + appendPkexecEnvironmentVariable(pkexecArgs, "DBUS_SESSION_BUS_ADDRESS"); + // Do not forward QT_QPA_PLATFORM from the parent: lockdown mode chooses linuxfb/xcb itself. + // Keep AppImage runtime hints for the elevated re-exec. + appendPkexecEnvironmentVariable(pkexecArgs, "APPIMAGE"); + appendPkexecEnvironmentVariable(pkexecArgs, "APPDIR"); + appendPkexecEnvironmentVariable(pkexecArgs, "OWD"); + appendPkexecEnvironmentVariable(pkexecArgs, "ARGV0"); + appendPkexecEnvironmentVariable(pkexecArgs, "APPIMAGE_EXTRACT_AND_RUN"); + pkexecArgs << extraEnvAssignments; + + pkexecArgs << QStringLiteral("/bin/sh"); + pkexecArgs << QStringLiteral("-c"); + pkexecArgs << QStringLiteral("cd -- \"$1\" && shift && exec \"$@\""); + pkexecArgs << QStringLiteral("sh"); + pkexecArgs << QDir::currentPath(); + pkexecArgs << elevatedExecutablePath(); + pkexecArgs << appArgs; + return pkexecArgs; +} + static int runNonDetachedPkexecChild(QProcess &child) { // Do not detach. Forward outputs to parent. @@ -244,12 +315,16 @@ void applyEarlyEnvironment(int argc, char *argv[]) if (isExamAntiCheat || isMenuLockdown) { if (isMenuLockdown || (isExamAntiCheat && hasResource)) { - if (!setup_barebones_vt()) { - qCritical() << "Anti-cheat VT setup failed; aborting."; - _exit(1); + // Lockdown prefers a bare VT + linuxfb. AppImages often only ship xcb unless + // EXTRA_PLATFORM_PLUGINS includes libqlinuxfb.so — fall back instead of aborting. + if (qtPlatformPluginAvailable(QStringLiteral("linuxfb")) && setup_barebones_vt()) { + qputenv("QT_QPA_PLATFORM", "linuxfb"); + qputenv("QT_QUICK_BACKEND", "software"); + } else { + qWarning() << "VT/linuxfb lockdown unavailable; continuing with the default Qt platform " + "(xcb). Rebuild the AppImage with EXTRA_PLATFORM_PLUGINS=libqlinuxfb.so " + "for full bare-VT lockdown."; } - qputenv("QT_QPA_PLATFORM", "linuxfb"); - qputenv("QT_QUICK_BACKEND", "software"); } #if SEB_HAS_QTWEBENGINE qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--no-sandbox"); @@ -460,21 +535,7 @@ int main(int argc, char *argv[]) QProcess child; child.setProgram(QStringLiteral("pkexec")); - - QStringList pkexecArgs; - pkexecArgs << QStringLiteral("--keep-cwd"); - pkexecArgs << QStringLiteral("env"); - appendPkexecEnvironmentVariable(pkexecArgs, "DISPLAY"); - appendPkexecEnvironmentVariable(pkexecArgs, "WAYLAND_DISPLAY"); - appendPkexecEnvironmentVariable(pkexecArgs, "XAUTHORITY"); - appendPkexecEnvironmentVariable(pkexecArgs, "XDG_RUNTIME_DIR"); - appendPkexecEnvironmentVariable(pkexecArgs, "XDG_SESSION_TYPE"); - appendPkexecEnvironmentVariable(pkexecArgs, "DBUS_SESSION_BUS_ADDRESS"); - appendPkexecEnvironmentVariable(pkexecArgs, "QT_QPA_PLATFORM"); - pkexecArgs << QCoreApplication::applicationFilePath(); - pkexecArgs << args; - - child.setArguments(pkexecArgs); + child.setArguments(buildPkexecArguments(args)); return runNonDetachedPkexecChild(child); } @@ -498,27 +559,15 @@ int main(int argc, char *argv[]) if (!args.contains(QStringLiteral("--anti-cheat"))) { args.prepend(QStringLiteral("--anti-cheat")); } - - QProcess child; - child.setProgram(QStringLiteral("pkexec")); - - QStringList pkexecArgs; - pkexecArgs << QStringLiteral("--keep-cwd"); - pkexecArgs << QStringLiteral("env"); - appendPkexecEnvironmentVariable(pkexecArgs, "DISPLAY"); - appendPkexecEnvironmentVariable(pkexecArgs, "WAYLAND_DISPLAY"); - appendPkexecEnvironmentVariable(pkexecArgs, "XAUTHORITY"); - appendPkexecEnvironmentVariable(pkexecArgs, "XDG_RUNTIME_DIR"); - appendPkexecEnvironmentVariable(pkexecArgs, "XDG_SESSION_TYPE"); - appendPkexecEnvironmentVariable(pkexecArgs, "DBUS_SESSION_BUS_ADDRESS"); - appendPkexecEnvironmentVariable(pkexecArgs, "QT_QPA_PLATFORM"); + + QStringList extraEnv; if (usedPassword) { - pkexecArgs << (QStringLiteral("SEB_PASSWORD=") + userPassword); + extraEnv << (QStringLiteral("SEB_PASSWORD=") + userPassword); } - pkexecArgs << QCoreApplication::applicationFilePath(); - pkexecArgs << args; - - child.setArguments(pkexecArgs); + + QProcess child; + child.setProgram(QStringLiteral("pkexec")); + child.setArguments(buildPkexecArguments(args, extraEnv)); return runNonDetachedPkexecChild(child); } }