From b1dd9bfc837acc1d6e2d7428aa8a29d31dd6a768 Mon Sep 17 00:00:00 2001 From: sysadminmatmoz Date: Sun, 14 Sep 2025 14:11:36 +0200 Subject: [PATCH] Enhance backtunnel-share with improved desktop integration, port collision checks, and pre-flight validations --- completions/backtunnel.bash | 14 ++++++++++++++ desktop/backtunnel.desktop | 13 ++++++++++++- man/backtunnel.1 | 5 +++-- scripts/backtunnel-share | 16 ++++++++++++++++ scripts/install.sh | 8 ++++++++ scripts/uninstall.sh | 8 ++++++++ 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/completions/backtunnel.bash b/completions/backtunnel.bash index 2fa736b..d183905 100644 --- a/completions/backtunnel.bash +++ b/completions/backtunnel.bash @@ -32,6 +32,20 @@ _backtunnel_complete() { return 0 fi + # backtunnel-share: after positionals, propose flags incl. invite + if [[ ${COMP_WORDS[0]} == backtunnel-share && ${COMP_CWORD} -ge 5 ]]; then + local opts="-p --tunnel-port -l --local-ssh-port -i --invite --invite-mount --invite-file --qr -h --help" + mapfile -t COMPREPLY < <(compgen -W "${opts}" -- "${cur}") + return 0 + fi + + # backtunnel-access: after positionals, propose its flags + if [[ ${COMP_WORDS[0]} == backtunnel-access && ${COMP_CWORD} -ge 3 ]]; then + local opts="-p --port -m --mount-point -h --help" + mapfile -t COMPREPLY < <(compgen -W "${opts}" -- "${cur}") + return 0 + fi + COMPREPLY=() } diff --git a/desktop/backtunnel.desktop b/desktop/backtunnel.desktop index e2bbb48..d290eda 100644 --- a/desktop/backtunnel.desktop +++ b/desktop/backtunnel.desktop @@ -2,7 +2,18 @@ Type=Application Name=BackTunnel Comment=Reverse SSH folder sharing and access -Exec=backtunnel-share %f +Exec=bash -lc ' + FOLDER="%f"; + REMOTE="$(kdialog --inputbox "Remote (user@host or user:host):" "user@vps.example.com")" || exit 1; + DUR="$(kdialog --combobox "Share duration" 30m 2h 6h 1d 2d --editable "2h")" || exit 1; + TPORT="$(kdialog --inputbox "Tunnel port on remote:" "2222")" || exit 1; + LPORT="$(kdialog --inputbox "Local SSH port to expose:" "22")" || exit 1; + if kdialog --yesno "Print invite line for chat?"; then INV="-i"; else INV=""; fi; + if kdialog --yesno "Show QR code for the invite?"; then QR="--qr"; else QR=""; fi; + MP="$(kdialog --inputbox "Suggested mount point in invite:" "/mnt/remote-rssh")" || exit 1; + konsole --noclose -e backtunnel-share "$FOLDER" with "$REMOTE" for "$DUR" \ + -p "$TPORT" -l "$LPORT" $INV $QR --invite-mount "$MP" +' Icon=network-vpn Terminal=true Categories=Network;Utility; diff --git a/man/backtunnel.1 b/man/backtunnel.1 index 989119d..8fcc213 100644 --- a/man/backtunnel.1 +++ b/man/backtunnel.1 @@ -18,7 +18,8 @@ The sharing ends automatically after the given \fIduration\fR via \fBtimeout\fR. With the \fB--invite\fR option, \fBbacktunnel-share\fR prints a ready-to-copy access command for the remote user, which can be pasted directly into a chat or terminal. The invite can also be rendered as a QR code or written to a file. -\fBbacktunnel-access\fR mounts the shared folder from the remote side using \fBsshfs\fR by connecting to \fBlocalhost:\fR on the remote host (the port exposed by \fBbacktunnel-share\fR). +\fBbacktunnel-access\fR mounts the shared folder from the remote side using \fBsshfs\fR by connecting to \fBlocalhost:\fR on the remote host +(the port exposed by \fBbacktunnel-share\fR). .SH OPTIONS .SS backtunnel-share options @@ -80,7 +81,7 @@ Share for 1 day, using custom ports: /home/user/docs with alice:vps.example.com for 1d -p 4422 -l 2222 .TP -Share with invite printed: +Share for 2 hours and print an invite: .B backtunnel-share /home/user/docs with alice@vps.example.com for 2h -i diff --git a/scripts/backtunnel-share b/scripts/backtunnel-share index 6aada9a..263ebe6 100644 --- a/scripts/backtunnel-share +++ b/scripts/backtunnel-share @@ -1,6 +1,7 @@ #!/usr/bin/env bash # Copyright (c) 2025. LUXIM d.o.o., Slovenia - Matjaž Mozetič. +# Licensed under the GNU GPL v3.0 # backtunnel-share: Share a folder using reverse SSH for a limited duration # Syntax: backtunnel-share /path/to/folder with remoteuser:remotehost for 2h @@ -163,8 +164,23 @@ fi echo "Tip: On the remote side, mount with:" echo " backtunnel-access '${FOLDER}' from ${REMOTE_USER}@${REMOTE_HOST} -p ${TUNNEL_PORT}" +echo "To stop sharing early: press Ctrl+C here." +# --- optional pre-flight: warn if remote loopback port is already in use (best-effort) --- +if ssh -o BatchMode=yes -o ConnectTimeout=5 "${REMOTE_USER}@${REMOTE_HOST}" \ + "command -v nc >/dev/null 2>&1 && nc -z 127.0.0.1 ${TUNNEL_PORT}"; then + echo "⚠️ Port ${TUNNEL_PORT} on remote 127.0.0.1 appears in use; choose another with -p." >&2 + # Uncomment the next line to make it a hard failure: + # exit 1 +fi + +# Bind reverse to 127.0.0.1 on the REMOTE host (private-by-default). +# Keepalive so the tunnel drops on dead links. +# Exit fast if the reverse bind fails (e.g., port in use). timeout "$DURATION" ssh -N \ + -o ExitOnForwardFailure=yes \ + -o ServerAliveInterval=15 \ + -o ServerAliveCountMax=3 \ -R "${TUNNEL_PORT}:localhost:${LOCAL_SSH_PORT}" \ -- "${REMOTE_USER}@${REMOTE_HOST}" diff --git a/scripts/install.sh b/scripts/install.sh index a84bf8f..4c3b70d 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -44,4 +44,12 @@ if [[ -d /usr/share/applications ]]; then sudo install -m 0644 desktop/backtunnel.desktop /usr/share/applications/backtunnel.desktop || true fi +# Refresh desktop DB and KDE service cache (best-effort) +command -v update-desktop-database >/dev/null 2>&1 && sudo update-desktop-database -q || true +if command -v kbuildsycoca6 >/dev/null 2>&1; then + kbuildsycoca6 --noincremental >/dev/null 2>&1 || true +elif command -v kbuildsycoca5 >/dev/null 2>&1; then + kbuildsycoca5 --noincremental >/dev/null 2>&1 || true +fi + echo "✅ BackTunnel installed. You may need to restart your shell and Dolphin." diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index cea11ec..458cb40 100644 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -39,4 +39,12 @@ sudo rm -f /usr/share/kservices5/ServiceMenus/backtunnel_access.desktop || true echo "🧹 Removing desktop launcher ..." sudo rm -f /usr/share/applications/backtunnel.desktop || true +# Refresh desktop DB and KDE service cache (best-effort) +command -v update-desktop-database >/dev/null 2>&1 && sudo update-desktop-database -q || true +if command -v kbuildsycoca6 >/dev/null 2>&1; then + kbuildsycoca6 --noincremental >/dev/null 2>&1 || true +elif command -v kbuildsycoca5 >/dev/null 2>&1; then + kbuildsycoca5 --noincremental >/dev/null 2>&1 || true +fi + echo "✅ Uninstall complete."