#!/usr/bin/env bash set -euo pipefail ACTION=install case "${1:-}" in uninstall|--uninstall|remove|--remove) ACTION=uninstall; shift ;; purge|--purge) ACTION=purge; shift ;; install|--install) ACTION=install; shift ;; esac TARGET_USER="${1:-}" if [[ -z "$TARGET_USER" ]]; then if [[ -n "${SUDO_USER:-}" && "$SUDO_USER" != "root" ]]; then TARGET_USER="$SUDO_USER"; else TARGET_USER="$(logname 2>/dev/null || true)"; fi fi if [[ -z "$TARGET_USER" || ! "$TARGET_USER" =~ ^[A-Za-z_][A-Za-z0-9_-]*[$]?$ ]] || ! id "$TARGET_USER" >/dev/null 2>&1; then echo "Specify the desktop user: sudo bash scripts/install-webui-helpers.sh \"$USER\"" >&2 exit 2 fi SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" uninstall_webui_helpers() { local user="$1" home="" user_unit="" echo "Uninstalling BastionGuard WebUI helpers for user: $user" systemctl disable --now bastionguard-webui-inotify.service 2>/dev/null || true rm -f /etc/systemd/system/bastionguard-webui-inotify.service systemctl daemon-reload 2>/dev/null || true systemctl reset-failed bastionguard-webui-inotify.service 2>/dev/null || true home="$(getent passwd "$user" | cut -d: -f6)" if [[ -n "$home" && -d "$home" ]]; then user_unit="$home/.config/systemd/user/bastionguard-webui-inotify.service" runuser -u "$user" -- systemctl --user disable --now bastionguard-webui-inotify.service 2>/dev/null || true rm -f "$user_unit" "$user_unit.disabled-by-root-service" 2>/dev/null || true fi rm -f /usr/local/sbin/bastionguard-webui-systemctl rm -f /usr/local/sbin/bastionguard-webui-admin rm -f /usr/local/sbin/bastionguard-webui-wizard rm -f /usr/local/libexec/bastionguard-webui-inotify-runner rm -f /etc/sudoers.d/bastionguard-webui rm -f "/run/bastionguard-webui-inotify-$user.sh" "/run/bastionguard-webui-inotify-$user.paths" "/run/bastionguard-webui-inotify-$user.pid" 2>/dev/null || true rm -rf /run/bastionguard-webui 2>/dev/null || true if [[ "$ACTION" == "purge" ]]; then rm -rf /var/lib/bastionguard-webui echo "Persistent data removed: /var/lib/bastionguard-webui" else echo "Persistent data kept: /var/lib/bastionguard-webui" fi echo "BastionGuard WebUI helpers uninstalled." } if [[ "$ACTION" == "uninstall" || "$ACTION" == "purge" ]]; then uninstall_webui_helpers "$TARGET_USER" exit 0 fi # Font policy: the WebUI template uses a vendored Cantarell asset only. # Expected path: webui/assets/fonts/Cantarell-VF.otf if [[ ! -f "$SCRIPT_DIR/../assets/fonts/Cantarell-VF.otf" ]]; then if [[ -x "$SCRIPT_DIR/vendor-cantarell-font.sh" ]]; then bash "$SCRIPT_DIR/vendor-cantarell-font.sh" || echo "Warning: vendored Cantarell font missing: webui/assets/fonts/Cantarell-VF.otf" >&2 else echo "Warning: vendored Cantarell font missing: webui/assets/fonts/Cantarell-VF.otf" >&2 fi fi install -o root -g root -m 0755 "$SCRIPT_DIR/bastionguard-webui-systemctl" /usr/local/sbin/bastionguard-webui-systemctl install -o root -g root -m 0755 "$SCRIPT_DIR/bastionguard-webui-admin" /usr/local/sbin/bastionguard-webui-admin install -o root -g root -m 0755 "$SCRIPT_DIR/bastionguard-webui-wizard" /usr/local/sbin/bastionguard-webui-wizard install -d -o root -g root -m 0755 /usr/local/libexec install -o root -g root -m 0755 "$SCRIPT_DIR/bastionguard-webui-inotify-runner" /usr/local/libexec/bastionguard-webui-inotify-runner WEB_USERS=() for u in www-data http apache nginx caddy; do if id "$u" >/dev/null 2>&1; then WEB_USERS+=("$u"); fi done if [[ ${#WEB_USERS[@]} -eq 0 ]]; then echo "No known web-server user found. Add sudoers manually for your PHP-FPM user." >&2 exit 3 fi # Data dir persistente usata dalla WebUI per opzioni, cache e stato locale. DATA_DIR=/var/lib/bastionguard-webui mkdir -p "$DATA_DIR" chown "${WEB_USERS[0]}:${WEB_USERS[0]}" "$DATA_DIR" 2>/dev/null || chown "${WEB_USERS[0]}" "$DATA_DIR" 2>/dev/null || true chmod 0750 "$DATA_DIR" || true # WebUI language/theme are session-only. Remove older persisted values if present. if command -v python3 >/dev/null 2>&1 && [[ -f "$DATA_DIR/web_options.json" ]]; then python3 - "$DATA_DIR/web_options.json" <<'PYWEBOPTS' || true import json, os, sys path = sys.argv[1] try: with open(path, 'r', encoding='utf-8') as fh: data = json.load(fh) if isinstance(data, dict): changed = False for key in ('language', 'theme'): if key in data: data.pop(key, None) changed = True if changed: tmp = path + '.tmp' with open(tmp, 'w', encoding='utf-8') as fh: json.dump(data, fh, ensure_ascii=False, indent=2) fh.write('\n') os.replace(tmp, path) except Exception: pass PYWEBOPTS fi # Persistent root/system service for the realtime WebPanel monitor. # This replaces the old --user unit so the monitor can inspect root-owned paths # allowed by the WebUI policy (/var/www, /srv, /tmp, /home, mounted media, ...). TARGET_HOME="$(getent passwd "$TARGET_USER" | cut -d: -f6)" SYSTEM_UNIT=/etc/systemd/system/bastionguard-webui-inotify.service cat > "$SYSTEM_UNIT" </dev/null || true # Disable the legacy per-user unit if an older WebUI package installed it. if [[ -n "${TARGET_HOME:-}" && -d "$TARGET_HOME" ]]; then USER_UNIT="$TARGET_HOME/.config/systemd/user/bastionguard-webui-inotify.service" if [[ -f "$USER_UNIT" ]]; then runuser -u "$TARGET_USER" -- systemctl --user disable --now bastionguard-webui-inotify.service 2>/dev/null || true mv -f "$USER_UNIT" "$USER_UNIT.disabled-by-root-service" 2>/dev/null || true fi fi # Remove legacy dynamic runtime scripts generated by older WebUI builds. # The realtime worker is now a static root-owned helper under /usr/local/libexec. rm -f "/run/bastionguard-webui-inotify-$TARGET_USER.sh" "/run/bastionguard-webui-inotify-$TARGET_USER.paths" 2>/dev/null || true install -d -o root -g root -m 0755 /run/bastionguard-webui 2>/dev/null || true SUDOERS="/etc/sudoers.d/bastionguard-webui" TMP="$(mktemp)" { echo "# BastionGuard WebUI: controlled helpers for $TARGET_USER" echo "Cmnd_Alias BASTIONGUARD_WEBUI_SYSTEMCTL = /usr/local/sbin/bastionguard-webui-systemctl user $TARGET_USER *" echo "Cmnd_Alias BASTIONGUARD_WEBUI_ADMIN = /usr/local/sbin/bastionguard-webui-admin *" echo "Cmnd_Alias BASTIONGUARD_WEBUI_INOTIFY = /usr/local/sbin/bastionguard-webui-admin inotify-start-saved $TARGET_USER, /usr/local/sbin/bastionguard-webui-admin inotify-stop $TARGET_USER, /usr/local/sbin/bastionguard-webui-admin inotify-status $TARGET_USER, /usr/local/sbin/bastionguard-webui-admin inotify-service-stop $TARGET_USER, /usr/local/sbin/bastionguard-webui-admin inotify-service-status $TARGET_USER, /usr/local/sbin/bastionguard-webui-admin ransomware-realtime-start $TARGET_USER" echo "Cmnd_Alias BASTIONGUARD_WEBUI_WIZARD = /usr/local/sbin/bastionguard-webui-wizard *" for u in "${WEB_USERS[@]}"; do echo "$u ALL=(root) NOPASSWD: BASTIONGUARD_WEBUI_SYSTEMCTL, BASTIONGUARD_WEBUI_ADMIN, BASTIONGUARD_WEBUI_WIZARD" done echo "$TARGET_USER ALL=(root) NOPASSWD: BASTIONGUARD_WEBUI_INOTIFY" } > "$TMP" chmod 0440 "$TMP" if command -v visudo >/dev/null 2>&1; then visudo -cf "$TMP" >/dev/null; fi install -o root -g root -m 0440 "$TMP" "$SUDOERS" rm -f "$TMP" cat <