#!/bin/bash
# kapaweb.gr Remote Support - Ubuntu/Debian installer  [customer]
#
# NOT TESTED ON A REAL UBUNTU YET (only against a mock, see tools/ubuntu-test.sh). It verifies
# every setting it applies and says so when something did not take effect. Support log (no
# passwords):  /var/lib/kapaweb/install-report.txt
#
# RustDesk 1.4.9 (source: core_main.rs, ipc.rs, platform/linux.rs): --option/--password/--get-id
# need the app INSTALLED (binary under /usr) and root, and as root they talk to the --server
# process of the ACTIVE DESKTOP USER (the rustdesk systemd service starts it while someone is
# logged in graphically), so the script needs a logged-in desktop session. Every setting is
# applied with "--option key value" and read back (same as the Windows and Mac installers).

MODE="customer"                       # customer | internal | managed
SHARED_PASSWORD=''   # internal only
HOST="rustdesk.kdns.gr"
API="https://rustdesk.kdns.gr"
KEY="8VYHuYHQJ3uHlBn97LpyItw41w2pOsc8jKvXg3vdl6w="
# used only when the GitHub API cannot be read (the API answer is preferred: newest release)
PIN_TAG="1.4.9"
PIN_SHA_AMD64="7244ba47c40e804172044bfbe659467c54ce46554c98e78c8c0406f1d612fda3"
PIN_SHA_ARM64="ce62c996f14d33f3bbe3a330e953644a44bace7f05885a7953f7395d69fb49c0"

ROOT="${KW_TEST_ROOT:-}"                 # test harness only: empty on real systems
TTY_IN="${KW_TEST_TTY:-/dev/tty}"        # test harness only
RD_BIN="$ROOT/usr/bin/rustdesk"
KW_DIR="$ROOT/var/lib/kapaweb"
LIB_DIR="$ROOT/usr/local/lib/kapaweb"
UPDATER="$LIB_DIR/update-rustdesk.sh"
REPORT="$KW_DIR/install-report.txt"
UNIT_DIR="$ROOT/etc/systemd/system"

# ---- menu: shown when the file is run without arguments in a terminal ----------------------
if [ $# -eq 0 ] && [ -t 0 ] && [ -t 1 ]; then
    echo ""
    echo "=========================================="
    echo " kapaweb.gr - Απομακρυσμένη Υποστήριξη (Ubuntu)"
    echo "=========================================="
    echo ""
    echo "   1) Εγκατάσταση"
    echo "   2) Αφαίρεση"
    echo ""
    printf "Επιλογή (1 ή 2): "; read -r CH <"$TTY_IN"
    case "$CH" in 2) set -- --uninstall ;; 1|"") set -- --install ;; *) echo "Ακυρώθηκε."; exit 0 ;; esac
fi

if [ "$(id -u)" -ne 0 ]; then
    if [ ! -f "$0" ]; then
        echo "Αποθηκεύστε το αρχείο και τρέξτε το με:  sudo bash <όνομα αρχείου>"
        exit 1
    fi
    echo "Χρειάζεται κωδικός διαχειριστή (sudo)."
    exec sudo bash "$0" "$@"
fi

have_tty() { [ -t 0 ] || [ -n "${KW_TEST_TTY:-}" ]; }
user_homes() { getent passwd | awk -F: '$3>=1000 && $3<60000 && $6!="" {print $6}'; }

# ---- removal: run this script with --uninstall ---------------------------------------------
if [ "${1:-}" = "--uninstall" ]; then
    systemctl disable --now kapaweb-rustdesk-update.timer >/dev/null 2>&1
    rm -f "$UNIT_DIR/kapaweb-rustdesk-update.timer" "$UNIT_DIR/kapaweb-rustdesk-update.service"
    systemctl daemon-reload >/dev/null 2>&1
    systemctl disable --now rustdesk >/dev/null 2>&1
    pkill -x rustdesk 2>/dev/null
    DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=300 purge -y rustdesk >/dev/null 2>&1
    rm -rf "$KW_DIR" "$LIB_DIR" "$ROOT/root/.config/rustdesk" "$ROOT/root/.local/share/logs/RustDesk"
    for H in $(user_homes); do
        rm -rf "$H/.config/rustdesk" "$H/.local/share/logs/RustDesk" "$H/.config/autostart/rustdesk.desktop"
    done
    echo "Η αφαίρεση ολοκληρώθηκε."
    if have_tty; then printf "Πατήστε Enter για κλείσιμο..."; read -r _ <"$TTY_IN"; fi
    exit 0
fi

mkdir -p "$KW_DIR"; : > "$REPORT"
rep() { echo "$(date '+%Y-%m-%d %H:%M:%S')  $1" >> "$REPORT"; }
die() { echo ""; echo "  ΣΦΑΛΜΑ: $1"; rep "FAILED: $1"; exit 1; }
TMPD=""
trap '[ -n "$TMPD" ] && rm -rf "$TMPD"' EXIT
# shellcheck disable=SC1091
. "$ROOT/etc/os-release" 2>/dev/null
rep "kapaweb ubuntu installer [$MODE], ${PRETTY_NAME:-unknown}, $(uname -m)"

echo ""
echo "=========================================="
echo " kapaweb.gr - Απομακρυσμένη Υποστήριξη (Ubuntu)"
echo "=========================================="

# shellcheck disable=SC2016
inst_ver() { dpkg-query -W -f='${db:Status-Status} ${Version}\n' rustdesk 2>/dev/null | awk '$1=="installed"{print $2}'; }
yes_answer() { case "$1" in ν|Ν|ναι|Ναι|n|N|y|Y|yes) return 0 ;; *) return 1 ;; esac; }

# ---- 0. what is this machine ---------------------------------------------------------------
case " ${ID:-} ${ID_LIKE:-} " in
    *" ubuntu "*|*" debian "*) ;;
    *) die "Υποστηρίζονται Ubuntu, Debian και παράγωγα (Mint, Pop!_OS κ.λπ.). Βρέθηκε: ${PRETTY_NAME:-άγνωστο σύστημα}." ;;
esac
command -v apt-get >/dev/null 2>&1 || die "Δεν βρέθηκε το apt-get."
command -v systemctl >/dev/null 2>&1 || die "Το σύστημα δεν χρησιμοποιεί systemd."
case "$(dpkg --print-architecture)" in
    amd64) PAT_RE='x86_64\.deb'; PAT="x86_64.deb"; PIN_SHA="$PIN_SHA_AMD64" ;;
    arm64) PAT_RE='aarch64\.deb'; PAT="aarch64.deb"; PIN_SHA="$PIN_SHA_ARM64" ;;
    *) die "Η αρχιτεκτονική $(dpkg --print-architecture) δεν υποστηρίζεται (μόνο amd64 και arm64)." ;;
esac

# the desktop user that is logged in right now (the RustDesk server of that user is what the CLI talks to)
CU=""; SESSTYPE=""
if command -v loginctl >/dev/null 2>&1; then
    for S in $(loginctl list-sessions --no-legend 2>/dev/null | awk '{print $1}'); do
        T=$(loginctl show-session "$S" -p Type --value 2>/dev/null)
        A=$(loginctl show-session "$S" -p Active --value 2>/dev/null)
        if [ "$A" = "yes" ] && { [ "$T" = "x11" ] || [ "$T" = "wayland" ]; }; then
            CU=$(loginctl show-session "$S" -p Name --value 2>/dev/null); SESSTYPE="$T"; break
        fi
    done
fi
{ [ -n "$CU" ] && [ "$CU" != "root" ]; } || die "Δεν βρέθηκε χρήστης συνδεδεμένος στην επιφάνεια εργασίας. Συνδεθείτε γραφικά (όχι μέσω SSH) και τρέξτε ξανά."
CUID=$(id -u "$CU")
rep "desktop user: $CU (uid $CUID), session: $SESSTYPE"

if [ "$MODE" = "customer" ]; then
    cat <<'CONSENT'

Το πρόγραμμα εγκαθιστά το RustDesk (ανοιχτού κώδικα, AGPL-3.0) και το συνδέει με τον
server της kapaweb.gr, ώστε ο τεχνικός μας να βοηθήσει τον υπολογιστή σας εξ αποστάσεως.
- ΔΕΝ δημιουργείται μόνιμος κωδικός: κάθε φορά που χρειάζεστε βοήθεια ανοίγετε το RustDesk
  και λέτε στον τεχνικό το ID και τον κωδικό μιας χρήσης που εμφανίζεται. Αλλάζει κάθε φορά.
- Προστίθεται εβδομαδιαία αυτόματη ενημέρωση του RustDesk.
- Αφαίρεση οποιαδήποτε στιγμή: τρέξτε ξανά αυτό το αρχείο και επιλέξτε «2) Αφαίρεση».

CONSENT
    printf "Συνεχίζετε; (ν/ο): "; read -r ANS <"$TTY_IN"
    yes_answer "$ANS" || { echo "Ακυρώθηκε."; exit 0; }
    if [ -n "$(inst_ver)" ]; then
        printf "Υπάρχει ήδη RustDesk. Θα αλλάξει ο server του. Συνέχεια; (ν/ο): "; read -r ANS <"$TTY_IN"
        yes_answer "$ANS" || { echo "Ακυρώθηκε."; exit 0; }
    fi
fi

# ---- 1. download the matching build, verify it, install ------------------------------------
command -v curl >/dev/null 2>&1 || {
    echo "  Εγκατάσταση curl..."
    DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=300 install -y curl >>"$REPORT" 2>&1 || die "Δεν βρέθηκε το curl και δεν εγκαταστάθηκε."
}
echo "  Έλεγχος τρέχουσας έκδοσης..."
JSON=$(curl -fsSL -m 20 -H "User-Agent: kapaweb-Installer" https://api.github.com/repos/rustdesk/rustdesk/releases/latest || true)
URL=$(echo "$JSON" | grep -oE '"browser_download_url" *: *"[^"]*'"$PAT_RE"'"' | head -1 | sed -E 's/.*: *"([^"]+)"/\1/')
TAG=$(echo "$JSON" | grep -oE '"tag_name" *: *"[^"]+"' | head -1 | sed -E 's/.*: *"([^"]+)"/\1/')
SHA=$(echo "$JSON" | tr -d '\n' | grep -oE '"digest" *: *"sha256:[0-9a-f]{64}"[^}]*"browser_download_url" *: *"[^"]*'"$PAT_RE"'"' | head -1 | grep -oE '[0-9a-f]{64}')
if [ -z "$URL" ] || [ -z "$SHA" ] || [ -z "$TAG" ]; then
    TAG="$PIN_TAG"; URL="https://github.com/rustdesk/rustdesk/releases/download/$PIN_TAG/rustdesk-$PIN_TAG-$PAT"; SHA="$PIN_SHA"
    rep "GitHub API not readable - using the pinned build $TAG"
fi
CURV=$(inst_ver)
if [ -n "$CURV" ] && dpkg --compare-versions "$CURV" ge "$TAG"; then
    echo "  Το RustDesk $CURV είναι ήδη εγκατεστημένο."
    rep "RustDesk $CURV already installed - download skipped"
else
    rep "installing RustDesk $TAG from $URL"
    echo "  Λήψη RustDesk $TAG..."
    mkdir -p "$ROOT/var/tmp"
    TMPD=$(mktemp -d "$ROOT/var/tmp/kwrd.XXXXXX"); chmod 755 "$TMPD"
    curl -fsSL -m 600 -o "$TMPD/rustdesk.deb" "$URL" || die "Η λήψη απέτυχε."
    if [ "$(sha256sum "$TMPD/rustdesk.deb" | cut -d' ' -f1)" != "$SHA" ]; then
        die "Το αρχείο δεν ταιριάζει με το επίσημο SHA-256 του RustDesk. Διακοπή."
    fi
    chmod 644 "$TMPD/rustdesk.deb"
    echo "  Εγκατάσταση (μπορεί να πάρει λίγο)..."
    export DEBIAN_FRONTEND=noninteractive
    apt-get -o DPkg::Lock::Timeout=300 update -qq >>"$REPORT" 2>&1 || rep "WARNING: apt-get update failed (continuing)"
    apt-get -o DPkg::Lock::Timeout=300 install -y "$TMPD/rustdesk.deb" >>"$REPORT" 2>&1 || die "Η εγκατάσταση του RustDesk απέτυχε. Στείλτε το αρχείο: $REPORT"
fi
[ -x "$RD_BIN" ] || die "Το RustDesk δεν εγκαταστάθηκε."
rep "app installed: $(inst_ver)"

# ---- 2. service + the user's server ---------------------------------------------------------
echo "  Εκκίνηση υπηρεσίας RustDesk..."
systemctl enable --now rustdesk >>"$REPORT" 2>&1 || rep "WARNING: systemctl enable --now rustdesk failed"
IPC="$ROOT/tmp/RustDesk-$CUID/ipc"
I=0
while [ $I -lt 30 ] && [ ! -e "$IPC" ]; do sleep 2; I=$((I+1)); done
if [ -e "$IPC" ]; then rep "user server is up ($IPC)"; else rep "WARNING: user server socket $IPC not found after 60 s"; fi

# ---- 3. apply every setting, read it back, retry until it is verified ------------------------
cli()        { "$RD_BIN" "$@" 2>/dev/null | tail -1 | tr -d '\r'; }
set_verify() { cli --option "$1" "$2" >/dev/null; [ "$(cli --option "$1")" = "$2" ]; }
S1=0; S2=0; S3=0; S4=0; S5=0; PW=0; IDOK=0; ID=""
echo "  Ρύθμιση και έλεγχος σύνδεσης (μέχρι 90 δευτερόλεπτα)..."
I=0
while [ $I -lt 45 ]; do
    [ $S1 = 1 ] || { set_verify custom-rendezvous-server "$HOST" && S1=1; }
    [ $S2 = 1 ] || { set_verify relay-server "$HOST" && S2=1; }
    [ $S3 = 1 ] || { set_verify api-server "$API" && S3=1; }
    [ $S4 = 1 ] || { set_verify key "$KEY" && S4=1; }
    # UDP must stay enabled: the open-source hbbs registers peers over UDP only (with Y the machine never shows online).
    [ $S5 = 1 ] || { set_verify disable-udp N && S5=1; }
    if [ $S1 = 1 ] && [ $S2 = 1 ] && [ $S3 = 1 ] && [ $S4 = 1 ] && [ $S5 = 1 ] && [ $PW = 0 ]; then
        if [ "$MODE" = "internal" ]; then
            [ "$(cli --password "$SHARED_PASSWORD")" = "Done!" ] && PW=1
        else
            set_verify verification-method use-temporary-password && PW=1
        fi
    fi
    if [ $PW = 1 ]; then
        ID=$(cli --get-id)
        case "$ID" in ""|*[!0-9]*) ;; *) IDOK=1; break ;; esac
    fi
    sleep 2; I=$((I+1))
done
rep "verified: server=$S1 relay=$S2 api=$S3 key=$S4 udp=$S5 password-policy=$PW id=$ID"
[ $IDOK = 1 ] || die "Οι ρυθμίσεις ΔΕΝ επιβεβαιώθηκαν (server=$S1 relay=$S2 api=$S3 key=$S4 udp=$S5 κωδικός=$PW). Μην δώσετε ID/κωδικό σε κανέναν. Στείλτε το αρχείο: $REPORT"


# ---- 3b. unattended editions: unattended access needs an Xorg login screen (Wayland asks the user every time) ----
if [ "$MODE" != "customer" ] && [ "$SESSTYPE" = "wayland" ]; then
    GDMCONF="$ROOT/etc/gdm3/custom.conf"; [ -f "$GDMCONF" ] || GDMCONF="$ROOT/etc/gdm/custom.conf"
    if [ -f "$GDMCONF" ] && have_tty; then
        echo ""
        echo "  Ο υπολογιστής χρησιμοποιεί Wayland. Για σύνδεση χωρίς να χρειάζεται κάποιος να πατήσει «Αποδοχή»"
        echo "  στην οθόνη, το RustDesk θέλει Xorg. Να το αλλάξω τώρα (ισχύει μετά από επανεκκίνηση);"
        printf "  (ν/ο): "; read -r ANS <"$TTY_IN"
        if yes_answer "$ANS"; then
            if grep -qE '^[#[:space:]]*WaylandEnable[[:space:]]*=' "$GDMCONF"; then
                sed -i -E 's/^[#[:space:]]*WaylandEnable[[:space:]]*=.*/WaylandEnable=false/' "$GDMCONF"
            elif grep -q '^\[daemon\]' "$GDMCONF"; then
                sed -i '/^\[daemon\]/a WaylandEnable=false' "$GDMCONF"
            else
                printf '\n[daemon]\nWaylandEnable=false\n' >> "$GDMCONF"
            fi
            rep "GDM set to Xorg (WaylandEnable=false in $GDMCONF), takes effect after a restart"
            echo "  Έγινε. Κάντε επανεκκίνηση όποτε σας βολεύει."
        fi
    fi
fi

# ---- 4. weekly update via a systemd timer ----------------------------------------------------
mkdir -p "$LIB_DIR" "$UNIT_DIR"
cat > "$UPDATER" <<'UPDATEREOF'
#!/bin/bash
KW_DIR="/var/lib/kapaweb"; LOG="$KW_DIR/update-log.txt"; UNIT_DIR="/etc/systemd/system"
mkdir -p "$KW_DIR"
log() { echo "$(date '+%Y-%m-%d %H:%M:%S')  $1" >> "$LOG"; }
# removed by the customer: never bring it back
if ! dpkg-query -W -f='${db:Status-Status}\n' rustdesk 2>/dev/null | grep -qx installed; then
    log "RustDesk removed - deleting the update job"
    systemctl disable --now kapaweb-rustdesk-update.timer >/dev/null 2>&1
    rm -f "$UNIT_DIR/kapaweb-rustdesk-update.timer" "$UNIT_DIR/kapaweb-rustdesk-update.service"
    systemctl daemon-reload >/dev/null 2>&1
    exit 0
fi
case "$(dpkg --print-architecture)" in
    amd64) PAT_RE='x86_64\.deb' ;;
    arm64) PAT_RE='aarch64\.deb' ;;
    *) log "FAILED - unsupported architecture"; exit 1 ;;
esac
JSON=$(curl -fsSL -m 20 -H "User-Agent: kapaweb-Updater" https://api.github.com/repos/rustdesk/rustdesk/releases/latest) || { log "FAILED - GitHub query"; exit 1; }
URL=$(echo "$JSON" | grep -oE '"browser_download_url" *: *"[^"]*'"$PAT_RE"'"' | head -1 | sed -E 's/.*: *"([^"]+)"/\1/')
TAG=$(echo "$JSON" | grep -oE '"tag_name" *: *"[^"]+"' | head -1 | sed -E 's/.*: *"([^"]+)"/\1/')
SHA=$(echo "$JSON" | tr -d '\n' | grep -oE '"digest" *: *"sha256:[0-9a-f]{64}"[^}]*"browser_download_url" *: *"[^"]*'"$PAT_RE"'"' | head -1 | grep -oE '[0-9a-f]{64}')
{ [ -n "$URL" ] && [ -n "$SHA" ] && [ -n "$TAG" ]; } || { log "FAILED - no asset/digest"; exit 1; }
CUR=$(dpkg-query -W -f='${Version}\n' rustdesk 2>/dev/null)
if dpkg --compare-versions "$CUR" ge "$TAG"; then log "up to date ($CUR)"; exit 0; fi
TMPD=$(mktemp -d /var/tmp/kwup.XXXXXX); chmod 755 "$TMPD"
trap 'rm -rf "$TMPD"' EXIT
curl -fsSL -m 600 -o "$TMPD/rustdesk.deb" "$URL" || { log "FAILED - download"; exit 1; }
[ "$(sha256sum "$TMPD/rustdesk.deb" | cut -d' ' -f1)" = "$SHA" ] || { log "FAILED - SHA-256 mismatch"; exit 1; }
chmod 644 "$TMPD/rustdesk.deb"
if DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=600 install -y "$TMPD/rustdesk.deb" >>"$LOG" 2>&1; then
    log "OK - installed $TAG"
else
    log "FAILED - apt install"; exit 1
fi
[ -f "$LOG" ] && tail -n 200 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG"
UPDATEREOF
chmod 755 "$UPDATER"
cat > "$UNIT_DIR/kapaweb-rustdesk-update.service" <<UNITEOF
[Unit]
Description=kapaweb.gr - RustDesk update check
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/bin/bash /usr/local/lib/kapaweb/update-rustdesk.sh
UNITEOF
cat > "$UNIT_DIR/kapaweb-rustdesk-update.timer" <<UNITEOF
[Unit]
Description=kapaweb.gr - weekly RustDesk update (Sunday 04:00)

[Timer]
OnCalendar=Sun *-*-* 04:00:00
RandomizedDelaySec=2h
Persistent=true
OnBootSec=15min

[Install]
WantedBy=timers.target
UNITEOF
systemctl daemon-reload >/dev/null 2>&1
if systemctl enable --now kapaweb-rustdesk-update.timer >/dev/null 2>&1; then
    rep "weekly update timer enabled"
else
    rep "WARNING: update timer not enabled (will be after a restart)"
fi

# ---- 5. result ---------------------------------------------------------------------------------
echo ""
echo "=========================================="
echo " ΕΤΟΙΜΟ"
echo "=========================================="
echo ""
echo "  ID : $ID"
echo ""
if [ "$MODE" = "internal" ]; then
    echo "  Επόμενο βήμα (μία φορά): πρόσθεσε το ID στο tools/fleet-machines.txt και τρέξε: python tools/fleet-enroll.py"
else
    echo "  Όταν χρειαστείτε βοήθεια, ανοίξτε το RustDesk από το μενού εφαρμογών και πείτε στον τεχνικό"
    echo "  το ID και τον κωδικό που εμφανίζεται (αλλάζει κάθε φορά)."
fi
if [ "$SESSTYPE" = "wayland" ]; then
    echo ""
    echo "  Σημείωση: ο υπολογιστής χρησιμοποιεί Wayland. Σε κάθε σύνδεση θα εμφανίζεται και ένα παράθυρο του"
    echo "  συστήματος που ζητά την άδειά σας για κοινή χρήση οθόνης· πατήστε «Κοινή χρήση»."
fi
echo ""
if have_tty; then printf "Πατήστε Enter για κλείσιμο..."; read -r _ <"$TTY_IN"; fi
