Initial commit

This commit is contained in:
2025-09-14 11:29:21 +02:00
commit d510d777ca
12 changed files with 1246 additions and 0 deletions

91
scripts/backtunnel-access Normal file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/env bash
# Copyright (c) 2025. LUXIM d.o.o., Slovenia - Matjaž Mozetič.
# backtunnel-access: Mount a folder shared over reverse SSH
# Usage: backtunnel-access /path/to/folder from remoteuser:remotehost [-p PORT] [-m MOUNTPOINT]
set -euo pipefail
PORT=2222
MOUNTPOINT="/mnt/remote-rssh"
usage() {
echo "Usage: $0 /path/to/folder from remoteuser:remotehost [-p PORT] [-m MOUNTPOINT]" >&2
exit 1
}
# --- parse positional args ---
[[ $# -lt 3 ]] && usage
FOLDER=$1
KEYWORD=$2
REMOTE=$3
shift 3 || true
[[ "$KEYWORD" != "from" ]] && usage
# Optional flags
while [[ $# -gt 0 ]]; do
case "$1" in
-p|--port)
[[ $# -lt 2 ]] && usage
PORT=$2
shift 2
;;
-m|--mount-point)
[[ $# -lt 2 ]] && usage
MOUNTPOINT=$2
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
# --- split remote user/host (supports user:host or user@host) ---
REMOTE_USER=""
REMOTE_HOST=""
if [[ "$REMOTE" == *:* ]]; then
REMOTE_USER=${REMOTE%%:*}
REMOTE_HOST=${REMOTE#*:}
elif [[ "$REMOTE" == *"@"* ]]; then
REMOTE_USER=${REMOTE%%@*}
REMOTE_HOST=${REMOTE#*@}
else
echo "Invalid remote format. Use remoteuser:remotehost or remoteuser@remotehost" >&2
exit 1
fi
# --- deps check ---
command -v sshfs >/dev/null 2>&1 || { echo "sshfs not found. Install sshfs first."; exit 1; }
command -v mountpoint >/dev/null 2>&1 || { echo "mountpoint utility not found."; exit 1; }
# --- prepare mountpoint ---
if [[ ! -d "$MOUNTPOINT" ]]; then
mkdir -p -- "$MOUNTPOINT"
fi
# Avoid double-mount
if mountpoint -q -- "$MOUNTPOINT"; then
echo "Mount point '$MOUNTPOINT' is already mounted. Unmount it first (e.g., 'fusermount -u \"$MOUNTPOINT\"')." >&2
exit 1
fi
echo "🔗 Mounting '$FOLDER' from '$REMOTE_USER@$REMOTE_HOST' via reverse-tunnel localhost:$PORT → '$MOUNTPOINT' ..."
sshfs \
-p "$PORT" \
-o reconnect \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=3 \
-o ssh_command="ssh -o ConnectTimeout=10" \
-- "$REMOTE_USER@localhost:$FOLDER" "$MOUNTPOINT"
echo "✅ Mounted at: $MOUNTPOINT"
echo "To unmount: fusermount -u \"$MOUNTPOINT\""

116
scripts/backtunnel-share Normal file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env bash
# Copyright (c) 2025. LUXIM d.o.o., Slovenia - Matjaž Mozetič.
# backtunnel-share: Share a folder using reverse SSH for a limited duration
# Syntax: backtunnel-share /path/to/folder with remoteuser:remotehost for 2h
# Options: -p|--tunnel-port <PORT> -l|--local-ssh-port <PORT> -h|--help
set -euo pipefail
TUNNEL_PORT=2222 # remote-side port exposed via -R
LOCAL_SSH_PORT=22 # local sshd port to forward to
DURATION="" # required: e.g. 30m, 2h, 1d
usage() {
cat >&2 <<EOF
Usage:
$(basename "$0") /path/to/folder with remoteuser:remotehost for <duration> [options]
Positional (required, in order):
/path/to/folder Informational only (the actual folder is mounted by backtunnel-access)
with Literal keyword
remoteuser:remotehost Or remoteuser@remotehost
for Literal keyword
<duration> e.g. 30m, 2h, 1d (passed to 'timeout')
Options:
-p, --tunnel-port N Remote tunnel port (default: ${TUNNEL_PORT})
-l, --local-ssh-port N Local sshd port to expose (default: ${LOCAL_SSH_PORT})
-h, --help Show this help
Examples:
$(basename "$0") ~/projects with alice:vps.example.com for 2h
$(basename "$0") ~/projects with alice@vps.example.com for 1d -p 4422 -l 2222
EOF
exit 1
}
# --- basic positional parsing ---
[[ $# -lt 5 ]] && usage
FOLDER=$1
KW1=$2
REMOTE=$3
KW2=$4
DURATION=$5
shift 5 || true
[[ "$KW1" != "with" ]] && usage
[[ "$KW2" != "for" ]] && usage
# --- optional flags ---
while [[ $# -gt 0 ]]; do
case "$1" in
-p|--tunnel-port)
[[ $# -lt 2 ]] && usage
TUNNEL_PORT=$2
shift 2
;;
-l|--local-ssh-port)
[[ $# -lt 2 ]] && usage
LOCAL_SSH_PORT=$2
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
# --- validate duration (timeout supports s,m,h,d) ---
if [[ ! "$DURATION" =~ ^[0-9]+[smhd]$ ]]; then
echo "Invalid duration '$DURATION' (use forms like 30m, 2h, 1d)." >&2
exit 1
fi
# --- split remote user/host ---
REMOTE_USER="" REMOTE_HOST=""
if [[ "$REMOTE" == *:* ]]; then
REMOTE_USER=${REMOTE%%:*}
REMOTE_HOST=${REMOTE#*:}
elif [[ "$REMOTE" == *"@"* ]]; then
REMOTE_USER=${REMOTE%%@*}
REMOTE_HOST=${REMOTE#*@}
else
echo "Invalid remote format. Use remoteuser:remotehost or remoteuser@remotehost" >&2
exit 1
fi
# --- deps check ---
command -v ssh >/dev/null 2>&1 || { echo "ssh not found."; exit 1; }
command -v timeout >/dev/null 2>&1 || { echo "timeout not found."; exit 1; }
echo "⏳ Sharing '${FOLDER}' via reverse SSH:"
echo " local sshd port : ${LOCAL_SSH_PORT}"
echo " remote bind port : ${TUNNEL_PORT} (on ${REMOTE_HOST})"
echo " remote user : ${REMOTE_USER}"
echo " duration : ${DURATION}"
echo
echo "Tip: On the remote side, mount with:"
echo " backtunnel-access '${FOLDER}' from ${REMOTE_USER}@${REMOTE_HOST} -p ${TUNNEL_PORT}"
timeout "$DURATION" ssh -N \
-R "${TUNNEL_PORT}:localhost:${LOCAL_SSH_PORT}" \
-- "${REMOTE_USER}@${REMOTE_HOST}"
rc=$?
if [[ $rc -eq 124 ]]; then
echo "⏹️ Sharing ended: reached duration (${DURATION})."
exit 0
fi
exit "$rc"

47
scripts/install.sh Normal file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Copyright (c) 2025. LUXIM d.o.o., Slovenia - Matjaž Mozetič.
set -euo pipefail
# Install binaries
echo "📦 Installing BackTunnel binaries to /usr/local/bin..."
sudo install -m 0755 scripts/backtunnel-share /usr/local/bin/backtunnel-share
sudo install -m 0755 scripts/backtunnel-access /usr/local/bin/backtunnel-access
# Man page
echo "📚 Installing man page..."
sudo install -m 0644 man/backtunnel.1 /usr/local/share/man/man1/backtunnel.1 || true
sudo mandb || true
# Bash completions
if [[ -d /usr/share/bash-completion/completions ]]; then
echo "🧠 Installing bash completion ..."
sudo install -m 0644 completions/backtunnel.bash /usr/share/bash-completion/completions/backtunnel-share || true
sudo install -m 0644 completions/backtunnel.bash /usr/share/bash-completion/completions/backtunnel-access || true
elif [[ -d /etc/bash_completion.d ]]; then
echo "🧠 Installing bash completion ..."
sudo install -m 0644 completions/backtunnel.bash /etc/bash_completion.d/backtunnel || true
fi
# Dolphin service menus (Plasma 6)
if [[ -d /usr/share/kio/servicemenus ]]; then
echo "🖱️ Installing Dolphin service menus (Plasma 6)..."
sudo install -m 0644 servicemenus/backtunnel_share.desktop /usr/share/kio/servicemenus/backtunnel_share.desktop || true
sudo install -m 0644 servicemenus/backtunnel_access.desktop /usr/share/kio/servicemenus/backtunnel_access.desktop || true
fi
# Dolphin service menus (Plasma 5)
if [[ -d /usr/share/kservices5/ServiceMenus ]]; then
echo "🖱️ Installing Dolphin service menus (Plasma 5)..."
sudo install -m 0644 servicemenus/backtunnel_share.desktop /usr/share/kservices5/ServiceMenus/backtunnel_share.desktop || true
sudo install -m 0644 servicemenus/backtunnel_access.desktop /usr/share/kservices5/ServiceMenus/backtunnel_access.desktop || true
fi
# Desktop launcher (optional)
if [[ -d /usr/share/applications ]]; then
echo "🖥️ Installing desktop launcher ..."
sudo install -m 0644 desktop/backtunnel.desktop /usr/share/applications/backtunnel.desktop || true
fi
echo "✅ BackTunnel installed. You may need to restart your shell and Dolphin."

42
scripts/uninstall.sh Normal file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
# Copyright (c) 2025. LUXIM d.o.o., Slovenia - Matjaž Mozetič.
set -euo pipefail
CONFIRM=1
while [[ $# -gt 0 ]]; do
case "$1" in
-y|--yes) CONFIRM=0; shift;;
-h|--help) echo "Usage: $(basename "$0") [--yes]"; exit 0;;
*) echo "Unknown option: $1" >&2; exit 1;;
esac
done
if [[ $CONFIRM -ne 0 ]]; then
read -r -p "Remove BackTunnel binaries, manpage, completions, service menus, and desktop file? [y/N] " ans
case "${ans:-N}" in y|Y|yes|YES) ;; *) echo "Aborted."; exit 1;; esac
fi
echo "🧹 Removing binaries ..."
sudo rm -f /usr/local/bin/backtunnel-share /usr/local/bin/backtunnel-access || true
echo "🧹 Removing man page ..."
sudo rm -f /usr/local/share/man/man1/backtunnel.1 || true
sudo mandb || true
echo "🧹 Removing bash completion ..."
sudo rm -f /usr/share/bash-completion/completions/backtunnel-share || true
sudo rm -f /usr/share/bash-completion/completions/backtunnel-access || true
sudo rm -f /etc/bash_completion.d/backtunnel || true
echo "🧹 Removing Dolphin service menus ..."
sudo rm -f /usr/share/kio/servicemenus/backtunnel_share.desktop || true
sudo rm -f /usr/share/kio/servicemenus/backtunnel_access.desktop || true
sudo rm -f /usr/share/kservices5/ServiceMenus/backtunnel_share.desktop || true
sudo rm -f /usr/share/kservices5/ServiceMenus/backtunnel_access.desktop || true
echo "🧹 Removing desktop launcher ..."
sudo rm -f /usr/share/applications/backtunnel.desktop || true
echo "✅ Uninstall complete."