Add backtunnel-umount script, host key policy support, and extend TUI/CLI integration
Introduce `backtunnel-umount` as a portable unmount helper, preferring `fusermount3`, `fusermount`, or `umount`. Add `BACKTUNNEL_HOSTKEY_POLICY` for configurable host key handling in `backtunnel-share` and `backtunnel-access`. Update TUIs for remote folder prompts and mount point handling. Enhance bash completion for TUI commands with directory suggestions. Revamp terminal selection logic in `backtunnel-open-term` to prioritize modern emulators like wezterm. Extend tests with scaffolds for host key policy and unmount behavior. Update README with new scripts, workflows, features, and troubleshooting tips.
This commit is contained in:
242
README.md
242
README.md
@@ -8,24 +8,31 @@ No third-party relay, no cloud dependency – just peer-to-peer, temporary, SSH-
|
|||||||
## ⚡ Quick Start
|
## ⚡ Quick Start
|
||||||
|
|
||||||
### 1. Accessor: Prepare your key (one-time)
|
### 1. Accessor: Prepare your key (one-time)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
backtunnel-keys print
|
backtunnel-keys print
|
||||||
```
|
```
|
||||||
|
|
||||||
Send the printed public key to the sharer.
|
Send the printed public key to the sharer.
|
||||||
|
|
||||||
### 2. Sharer: Start sharing and authorize the accessor
|
### 2. Sharer: Start sharing and authorize the accessor
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
backtunnel-share ~/Documents with alice@remotehost for 2h -i --allow-key ./alice.pub
|
backtunnel-share ~/Documents with alice@remotehost for 2h -i --allow-key ./alice.pub
|
||||||
```
|
```
|
||||||
|
|
||||||
This injects a **temporary, restricted SFTP-only key** and prints an invite.
|
This injects a **temporary, restricted SFTP-only key** and prints an invite.
|
||||||
|
|
||||||
### 3. Accessor: Mount the shared folder
|
### 3. Accessor: Mount the shared folder
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
backtunnel-access '/home/sharer/Documents' from alice@remotehost -p 2222 -m ~/remote-rssh
|
backtunnel-access '/home/sharer/Documents' from alice@remotehost -p 2222 -m ~/remote-rssh
|
||||||
```
|
```
|
||||||
|
|
||||||
Unmount with:
|
Unmount with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
fusermount -u ~/remote-rssh
|
backtunnel-umount ~/remote-rssh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -35,81 +42,230 @@ fusermount -u ~/remote-rssh
|
|||||||
- **NAT/firewall friendly**: works without port forwarding.
|
- **NAT/firewall friendly**: works without port forwarding.
|
||||||
- **Temporary by design**: shares auto-expire after a set duration.
|
- **Temporary by design**: shares auto-expire after a set duration.
|
||||||
- **Invite workflow**: sharer sends a one-liner or QR code to accessor.
|
- **Invite workflow**: sharer sends a one-liner or QR code to accessor.
|
||||||
- **Restricted keys**: accessor keys are usable *only* for SFTP via the tunnel and are auto-removed when the share ends.
|
- **Restricted keys**: accessor keys are usable only for SFTP via the reverse tunnel and can be auto-added for the session.
|
||||||
- **Profiles**: save defaults and common remotes in `profiles.ini`.
|
- **Profiles**: save defaults and common remotes in profiles.ini.
|
||||||
- **Desktop integration**: Dolphin (KDE) service menus for GUI sharing and access.
|
- **Host key policy**: configurable StrictHostKeyChecking via BACKTUNNEL_HOSTKEY_POLICY.
|
||||||
|
- **Desktop integration**: Dolphin (KDE) service menus for GUI/TUI sharing and access.
|
||||||
|
- **Convenient TUIs/GUI**: guided prompts for sharer/accessor; terminal opener detects installed terminals.
|
||||||
|
- **Bash completion**: contextual completion for both CLI commands and TUIs.
|
||||||
|
- **Logs with rotation**: servicemenu invocations write logs and keep the last 10 entries.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Roles and Flow
|
||||||
|
|
||||||
|
- Sharer: exposes a local SSH service back to a remote host for a limited time. Runs backtunnel-share.
|
||||||
|
- Accessor: connects to the sharer via the remote host’s `127.0.0.1:PORT` and mounts a folder with sshfs. Runs backtunnel-access.
|
||||||
|
- Reverse tunnel: the sharer’s ssh -R binds `127.0.0.1:PORT` on the remote host and forwards back to the sharer’s sshd.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Requirements
|
||||||
|
|
||||||
|
- Linux with Bash
|
||||||
|
- OpenSSH client (ssh, sftp)
|
||||||
|
- sshfs (FUSE) on the accessor machine
|
||||||
|
- Optional:
|
||||||
|
- qrencode (for QR code invites)
|
||||||
|
- A terminal emulator for service menu helpers (e.g., konsole, gnome-terminal, wezterm, kitty, etc.)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔑 Commands
|
## 🔑 Commands
|
||||||
|
|
||||||
### Sharing
|
### Sharer side
|
||||||
|
|
||||||
|
- backtunnel-share
|
||||||
|
- Start a time-bounded reverse SSH tunnel and optionally print an invite.
|
||||||
|
- Syntax:
|
||||||
```bash
|
```bash
|
||||||
backtunnel-share /path/to/folder with user@host for <duration> [options]
|
backtunnel-share /path/to/folder with user@host for <duration> [options]
|
||||||
```
|
```
|
||||||
- `-p, --tunnel-port` Remote bind port (default: 2222)
|
- Duration: 10m, 30m, 1h, 2h, 6h, 12h, 1d, 2d (single unit e.g., 30m, 2h, 1d)
|
||||||
- `-l, --local-ssh-port` Local sshd port to expose (default: 22)
|
- Options:
|
||||||
- `-i, --invite` Print invite line
|
- -p, --tunnel-port N: Remote bind port (default: 2222)
|
||||||
- `--qr` Show QR code (requires qrencode)
|
- -l, --local-ssh-port N: Local sshd port to forward to (default: 22)
|
||||||
- `--allow-key FILE` Authorize a provided public key
|
- -i, --invite: Print a one-liner invite for the accessor
|
||||||
- `--allow-known NAME` Authorize a stored key (~/.config/backtunnel/authorized/NAME.pub)
|
- --invite-mount PATH: Suggested mount point in the invite (default: $HOME/remote-rssh)
|
||||||
|
- --invite-file FILE: Save the invite text (with unmount hint) to a file
|
||||||
|
- --qr: Also show a QR code for the invite (requires qrencode)
|
||||||
|
- --allow-key FILE: Temporarily authorize an accessor public key for this session
|
||||||
|
- --allow-known NAME: Authorize a stored key (~/.config/backtunnel/authorized/NAME.pub)
|
||||||
|
- -h, --help: Show usage
|
||||||
|
|
||||||
### Accessing
|
- backtunnel-share-tui
|
||||||
|
- Minimal TUI wrapper prompting for remote, duration, ports, and invite options, then runs backtunnel-share.
|
||||||
|
- Syntax:
|
||||||
```bash
|
```bash
|
||||||
backtunnel-access /path/to/folder from user@host [options]
|
backtunnel-share-tui <folder>
|
||||||
```
|
```
|
||||||
- `-p, --port` Tunnel port (default: 2222)
|
|
||||||
- `-m, --mount-point` Local mount point (default: ~/remote-rssh)
|
- backtunnel-authorize
|
||||||
|
- Store a named accessor public key for --allow-known usage.
|
||||||
|
- Syntax:
|
||||||
|
```bash
|
||||||
|
backtunnel-authorize <name> <pubkey-file>
|
||||||
|
```
|
||||||
|
- Stores at: `${XDG_CONFIG_HOME:-$HOME/.config}/backtunnel/authorized/<name>.pub`
|
||||||
|
|
||||||
|
### Accessor side
|
||||||
|
|
||||||
|
- backtunnel-access
|
||||||
|
- Mount a folder over SFTP via the reverse tunnel’s `127.0.0.1:PORT`.
|
||||||
|
- Syntax:
|
||||||
|
```bash
|
||||||
|
backtunnel-access /remote/folder from user@host [-p PORT] [-m MOUNTPOINT]
|
||||||
|
```
|
||||||
|
- Options:
|
||||||
|
- -p, --port N: Tunnel port on the remote host (default: 2222)
|
||||||
|
- -m, --mount-point PATH: Local mount point (default: $HOME/remote-rssh)
|
||||||
|
- -h, --help: Show usage
|
||||||
|
- Behavior:
|
||||||
|
- Checks mount point readiness and warns if not empty.
|
||||||
|
- Tries passwordless auth via a dedicated identity if present (~/.ssh/id_ed25519_backtunnel).
|
||||||
|
- Performs a quick SFTP visibility check of the target folder.
|
||||||
|
- Mounts with reconnect/keepalives.
|
||||||
|
|
||||||
|
- backtunnel-access-tui
|
||||||
|
- Minimal TUI wrapper prompting for remote, tunnel port, remote folder, and mount point.
|
||||||
|
- Syntax:
|
||||||
|
```bash
|
||||||
|
backtunnel-access-tui <selected-dir>
|
||||||
|
```
|
||||||
|
|
||||||
|
- backtunnel-keys
|
||||||
|
- Manage the accessor-side dedicated key pair (~/.ssh/id_ed25519_backtunnel).
|
||||||
|
- Syntax:
|
||||||
|
```bash
|
||||||
|
backtunnel-keys print # emit public key (generate if missing)
|
||||||
|
backtunnel-keys path # show key paths
|
||||||
|
```
|
||||||
|
|
||||||
|
- backtunnel-auth-setup
|
||||||
|
- Initialize a tunnel-only, SFTP-only authorized_keys entry on the remote (via the tunnel).
|
||||||
|
- Syntax:
|
||||||
|
```bash
|
||||||
|
backtunnel-auth-setup [-p PORT] user@localhost
|
||||||
|
```
|
||||||
|
- Installs a restricted entry:
|
||||||
|
from="127.0.0.1",command="internal-sftp",restrict <pubkey>
|
||||||
|
|
||||||
|
- backtunnel-umount
|
||||||
|
- Portable unmount helper (prefers fusermount3, then fusermount, then umount).
|
||||||
|
- Syntax:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
backtunnel-umount <mountpoint>
|
||||||
|
```
|
||||||
|
|
||||||
|
- backtunnel-open-term
|
||||||
|
- Launch a command in an available terminal emulator; logs output with simple rotation.
|
||||||
|
- Automatically detects terminals (prefers konsole on KDE; supports wezterm, kitty, alacritty, gnome-terminal, kgx, tilix, xfce4-terminal, xterm).
|
||||||
|
- Used by service menus/GUI wrappers.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📁 Profiles
|
## 🔒 Security Model
|
||||||
|
|
||||||
|
- Reverse tunnel bind: remote side binds on `127.0.0.1:PORT` (loopback only).
|
||||||
|
- Access is SFTP-based:
|
||||||
|
- Invite flow can be paired with a restricted authorized_keys entry:
|
||||||
|
- from="127.0.0.1",command="internal-sftp",restrict
|
||||||
|
- This limits usage to SFTP over the reverse tunnel only; no shell or port forwarding.
|
||||||
|
- Temporary authorization:
|
||||||
|
- Sharer can temporarily add an accessor public key for the session; it’s removed on exit.
|
||||||
|
- Host key policy:
|
||||||
|
- Controlled via the environment variable BACKTUNNEL_HOSTKEY_POLICY with values:
|
||||||
|
- accept-new (default), yes, no, ask
|
||||||
|
- Applied to ssh, sftp, and the ssh command used by sshfs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 Profiles
|
||||||
|
|
||||||
|
- Config locations (higher precedence first):
|
||||||
|
- `${XDG_CONFIG_HOME:-$HOME/.config}/backtunnel/profiles.ini`
|
||||||
|
- /etc/backtunnel/profiles.ini
|
||||||
|
- /usr/share/backtunnel/profiles.ini
|
||||||
|
- Example:
|
||||||
|
|
||||||
`~/.config/backtunnel/profiles.ini`:
|
|
||||||
```ini
|
```ini
|
||||||
[default]
|
[default]
|
||||||
tunnel_port=2222
|
tunnel_port=2222
|
||||||
invite=true
|
local_ssh_port=22
|
||||||
invite_mount=$HOME/remote-rssh
|
invite_mount=$HOME/remote-rssh
|
||||||
|
invite=true
|
||||||
|
qr=false
|
||||||
|
|
||||||
[work]
|
[work]
|
||||||
user=alice
|
user=alice
|
||||||
host=vps.example.com
|
host=vps.example.com
|
||||||
tunnel_port=4422
|
tunnel_port=4422
|
||||||
```
|
```
|
||||||
Usage:
|
|
||||||
|
- Usage with @profile:
|
||||||
```bash
|
```bash
|
||||||
backtunnel-share ~/reports with @work for 6h -i --allow-known alice
|
backtunnel-share ~/reports with @work for 6h -i --allow-known alice
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🖥️ Dolphin Integration
|
## 🧭 Bash Completion
|
||||||
|
|
||||||
- **Share via BackTunnel…** – GUI dialog for sharer options.
|
- Source completions/backtunnel.bash or install it via your system’s completion.d directory.
|
||||||
- **Access via BackTunnel…** – GUI dialog for accessor options.
|
- Provides:
|
||||||
|
- Keyword scaffolding (with/from/for)
|
||||||
|
- @profile expansion
|
||||||
|
- Suggestions for durations and ports
|
||||||
|
- Key name/file completion for --allow-known/--allow-key
|
||||||
|
- Path completion for the first positional and mount path options
|
||||||
|
- Includes minimal completion for TUIs (first positional directory).
|
||||||
|
|
||||||
Logs are written to:
|
---
|
||||||
|
|
||||||
|
## 🖥️ Desktop Integration (KDE Dolphin)
|
||||||
|
|
||||||
|
- Right-click in a folder:
|
||||||
|
- “Share via BackTunnel…” → opens a GUI/TUI flow for the sharer.
|
||||||
|
- “Access via BackTunnel (mount here)…” → opens a GUI/TUI flow for the accessor.
|
||||||
|
- Logs:
|
||||||
```
|
```
|
||||||
~/.local/state/backtunnel/servicemenu.*.log
|
~/.local/state/backtunnel/servicemenu.*.log
|
||||||
```
|
```
|
||||||
|
The launcher keeps the last 10 logs (simple rotation).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🌐 Environment Variables
|
||||||
|
|
||||||
|
- BACKTUNNEL_HOSTKEY_POLICY
|
||||||
|
- Controls StrictHostKeyChecking for ssh/sftp/sshfs:
|
||||||
|
- Values: accept-new (default), yes, no, ask
|
||||||
|
- Example:
|
||||||
|
```bash
|
||||||
|
BACKTUNNEL_HOSTKEY_POLICY=strict # alias for 'yes' in many contexts
|
||||||
|
BACKTUNNEL_HOSTKEY_POLICY=accept-new
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📦 Install
|
## 🛠️ Installation
|
||||||
|
|
||||||
### From source
|
### From source
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo bash scripts/install.sh
|
sudo bash scripts/install.sh
|
||||||
make init # copy example profiles.ini
|
make init # copy example profiles.ini
|
||||||
```
|
```
|
||||||
|
|
||||||
### Arch Linux
|
### Arch Linux
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
makepkg -si
|
makepkg -si
|
||||||
```
|
```
|
||||||
|
|
||||||
Uninstall:
|
Uninstall:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo bash scripts/uninstall.sh
|
sudo bash scripts/uninstall.sh
|
||||||
# or with purge of defaults
|
# or with purge of defaults
|
||||||
@@ -118,7 +274,43 @@ sudo PURGE=1 bash scripts/uninstall.sh
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📖 Documentation
|
## 🔍 Troubleshooting
|
||||||
|
|
||||||
|
- Port already in use on remote:
|
||||||
|
- backtunnel-share warns if `127.0.0.1:PORT` is busy; choose another with -p.
|
||||||
|
- Missing sshfs:
|
||||||
|
- Install sshfs on the accessor machine; ensure FUSE is available.
|
||||||
|
- SFTP path is not listable:
|
||||||
|
- backtunnel-access warns if SFTP cannot list the path. Verify folder existence and permissions.
|
||||||
|
- Passwordless auth isn't set:
|
||||||
|
- Try:
|
||||||
|
```bash
|
||||||
|
backtunnel-auth-setup -p <PORT> <user>@localhost
|
||||||
|
```
|
||||||
|
- Unmount fails:
|
||||||
|
- Use the portable helper:
|
||||||
|
```bash
|
||||||
|
backtunnel-umount <mountpoint>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing
|
||||||
|
|
||||||
|
- Bats scaffolds are provided to extend:
|
||||||
|
- tests/test-umount.bats
|
||||||
|
- tests/test-hostkey-policy.bats
|
||||||
|
|
||||||
|
Run tests (example):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bats tests
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 Man Page
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
man backtunnel
|
man backtunnel
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -242,3 +242,29 @@ _backtunnel_complete() {
|
|||||||
# Register for both commands
|
# Register for both commands
|
||||||
complete -F _backtunnel_complete backtunnel-share
|
complete -F _backtunnel_complete backtunnel-share
|
||||||
complete -F _backtunnel_complete backtunnel-access
|
complete -F _backtunnel_complete backtunnel-access
|
||||||
|
|
||||||
|
# Minimal TUI completers: complete only the first positional as a directory
|
||||||
|
_backtunnel_access_tui_complete() {
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
if [[ ${COMP_CWORD} -eq 1 ]]; then
|
||||||
|
compopt -o filenames 2>/dev/null
|
||||||
|
mapfile -t COMPREPLY < <(compgen -d -- "$cur")
|
||||||
|
else
|
||||||
|
COMPREPLY=()
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
_backtunnel_share_tui_complete() {
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
if [[ ${COMP_CWORD} -eq 1 ]]; then
|
||||||
|
compopt -o filenames 2>/dev/null
|
||||||
|
mapfile -t COMPREPLY < <(compgen -d -- "$cur")
|
||||||
|
else
|
||||||
|
COMPREPLY=()
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Register TUI completion
|
||||||
|
complete -F _backtunnel_access_tui_complete backtunnel-access-tui
|
||||||
|
complete -F _backtunnel_share_tui_complete backtunnel-share-tui
|
||||||
@@ -41,6 +41,13 @@ set -euo pipefail
|
|||||||
PORT=2222
|
PORT=2222
|
||||||
MOUNTPOINT="$HOME/remote-rssh"
|
MOUNTPOINT="$HOME/remote-rssh"
|
||||||
|
|
||||||
|
# Host key checking policy: env BACKTUNNEL_HOSTKEY_POLICY = yes|no|ask|accept-new (default: accept-new)
|
||||||
|
HKP="${BACKTUNNEL_HOSTKEY_POLICY:-accept-new}"
|
||||||
|
case "$HKP" in
|
||||||
|
yes|no|ask|accept-new) ;;
|
||||||
|
*) HKP="accept-new" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo "Usage: $0 /path/to/folder from remoteuser:remotehost [-p PORT] [-m MOUNTPOINT]" >&2
|
echo "Usage: $0 /path/to/folder from remoteuser:remotehost [-p PORT] [-m MOUNTPOINT]" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -151,7 +158,7 @@ if [[ -f "$HOME/.ssh/id_ed25519_backtunnel" ]]; then
|
|||||||
SFTP_ID_OPTS+=( -o IdentityFile="$HOME/.ssh/id_ed25519_backtunnel" -o IdentitiesOnly=yes )
|
SFTP_ID_OPTS+=( -o IdentityFile="$HOME/.ssh/id_ed25519_backtunnel" -o IdentitiesOnly=yes )
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new \
|
if ! ssh -o BatchMode=yes -o StrictHostKeyChecking="$HKP" \
|
||||||
-p "$PORT" "${SSH_IDENTITY_OPTS[@]}" "$REMOTE_USER@localhost" true 2>/dev/null; then cat >&2 <<EOF
|
-p "$PORT" "${SSH_IDENTITY_OPTS[@]}" "$REMOTE_USER@localhost" true 2>/dev/null; then cat >&2 <<EOF
|
||||||
⚠️ Passwordless auth not set for $REMOTE_USER@localhost:$PORT.
|
⚠️ Passwordless auth not set for $REMOTE_USER@localhost:$PORT.
|
||||||
You can initialize a tunnel-only, SFTP-only key with:
|
You can initialize a tunnel-only, SFTP-only key with:
|
||||||
@@ -164,14 +171,14 @@ fi
|
|||||||
echo "Checking remote path visibility via SFTP ..."
|
echo "Checking remote path visibility via SFTP ..."
|
||||||
|
|
||||||
# Purpose: quick sanity check that the target path is visible over SFTP before mounting.
|
# Purpose: quick sanity check that the target path is visible over SFTP before mounting.
|
||||||
if ! sftp -q -P "$PORT" -o StrictHostKeyChecking=accept-new "${SFTP_ID_OPTS[@]}" \
|
if ! sftp -q -P "$PORT" -o StrictHostKeyChecking="$HKP" "${SFTP_ID_OPTS[@]}" \
|
||||||
"$REMOTE_USER@localhost" <<< "ls -1 \"$FOLDER\"" >/dev/null 2>&1; then
|
"$REMOTE_USER@localhost" <<< "ls -1 \"$FOLDER\"" >/dev/null 2>&1; then
|
||||||
echo "⚠️ Remote path '$FOLDER' not listable via SFTP. It may not exist or permissions deny access." >&2
|
echo "⚠️ Remote path '$FOLDER' not listable via SFTP. It may not exist or permissions deny access." >&2
|
||||||
echo " Proceeding to mount; sshfs may fail if the path is invalid." >&2
|
echo " Proceeding to mount; sshfs may fail if the path is invalid." >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build ssh command used by sshfs (adds keepalive/connect-timeout, identity if present).
|
# Build ssh command used by sshfs (adds keepalive/connect-timeout, identity if present).
|
||||||
SSH_CMD="ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new"
|
SSH_CMD="ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=$HKP"
|
||||||
# If identity options are present, append them to SSH_CMD
|
# If identity options are present, append them to SSH_CMD
|
||||||
if [[ ${#SSH_IDENTITY_OPTS[@]} -gt 0 ]]; then
|
if [[ ${#SSH_IDENTITY_OPTS[@]} -gt 0 ]]; then
|
||||||
# Join array safely
|
# Join array safely
|
||||||
@@ -190,4 +197,4 @@ sshfs \
|
|||||||
-- "$REMOTE_USER@localhost:$FOLDER" "$MOUNTPOINT"
|
-- "$REMOTE_USER@localhost:$FOLDER" "$MOUNTPOINT"
|
||||||
|
|
||||||
echo "✅ Mounted at: $MOUNTPOINT"
|
echo "✅ Mounted at: $MOUNTPOINT"
|
||||||
echo "To unmount: fusermount -u \"$MOUNTPOINT\" || fusermount3 -u \"$MOUNTPOINT\""
|
echo "To unmount: backtunnel-umount \"$MOUNTPOINT\""
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ REMOTE="${REMOTE:-user@vps.example.com}"
|
|||||||
read -r -p "Tunnel port on remote [2222]: " PORT
|
read -r -p "Tunnel port on remote [2222]: " PORT
|
||||||
PORT="${PORT:-2222}"
|
PORT="${PORT:-2222}"
|
||||||
|
|
||||||
|
# Ask for the remote folder that should be mounted (first positional of backtunnel-access)
|
||||||
|
read -r -p "Remote folder path to mount [~/]: " FOLDER
|
||||||
|
FOLDER="${FOLDER:-~/}"
|
||||||
|
if [[ "$FOLDER" == "~" ]]; then
|
||||||
|
FOLDER="~/"
|
||||||
|
fi
|
||||||
|
|
||||||
read -r -p "Mount point [${DEFAULT_MP}]: " MP
|
read -r -p "Mount point [${DEFAULT_MP}]: " MP
|
||||||
MP="${MP:-$DEFAULT_MP}"
|
MP="${MP:-$DEFAULT_MP}"
|
||||||
|
|
||||||
@@ -62,7 +69,7 @@ if [[ ! -w "$MP" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Running: backtunnel-access '<remote-folder>' from '$REMOTE' -p '$PORT' -m '$MP'"
|
echo "Running: backtunnel-access '${FOLDER}' from '${REMOTE}' -p '${PORT}' -m '${MP}'"
|
||||||
echo "Note: you'll be prompted on the remote for the exact folder (as per your workflow)."
|
echo "Note: the folder is accessed via SFTP on the remote through the reverse tunnel."
|
||||||
# Replace this process with backtunnel-access (no return to this script after exec)
|
# Replace this process with backtunnel-access (no return to this script after exec)
|
||||||
exec backtunnel-access "$MP" from "$REMOTE" -p "$PORT" -m "$MP"
|
exec backtunnel-access "$FOLDER" from "$REMOTE" -p "$PORT" -m "$MP"
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ cmd=( "$@" )
|
|||||||
if [[ -n "${KDE_FULL_SESSION:-}" ]] && command -v konsole >/dev/null 2>&1; then
|
if [[ -n "${KDE_FULL_SESSION:-}" ]] && command -v konsole >/dev/null 2>&1; then
|
||||||
echo "konsole"; return
|
echo "konsole"; return
|
||||||
fi
|
fi
|
||||||
for t in kitty alacritty kgx gnome-terminal tilix xfce4-terminal konsole xterm; do
|
# Prefer widely used modern terminals first when not on KDE
|
||||||
|
for t in wezterm kitty alacritty kgx gnome-terminal tilix xfce4-terminal konsole xterm; do
|
||||||
if command -v "$t" >/dev/null 2>&1; then echo "$t"; return; fi
|
if command -v "$t" >/dev/null 2>&1; then echo "$t"; return; fi
|
||||||
done
|
done
|
||||||
echo "" # none
|
echo "" # none
|
||||||
@@ -101,6 +102,7 @@ cmd=( "$@" )
|
|||||||
# Run command in terminal (use hold/noclose if supported)
|
# Run command in terminal (use hold/noclose if supported)
|
||||||
case "$term" in
|
case "$term" in
|
||||||
konsole) exec konsole --noclose -e "${cmd[@]}" ;;
|
konsole) exec konsole --noclose -e "${cmd[@]}" ;;
|
||||||
|
wezterm) exec wezterm start -- "${cmd[@]}" ;;
|
||||||
kitty) exec kitty -e "${cmd[@]}" ;;
|
kitty) exec kitty -e "${cmd[@]}" ;;
|
||||||
alacritty) exec alacritty -e "${cmd[@]}" ;;
|
alacritty) exec alacritty -e "${cmd[@]}" ;;
|
||||||
gnome-terminal) exec gnome-terminal -- bash -lc "exec $shell_cmd" ;;
|
gnome-terminal) exec gnome-terminal -- bash -lc "exec $shell_cmd" ;;
|
||||||
|
|||||||
@@ -75,6 +75,13 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Host key checking policy: env BACKTUNNEL_HOSTKEY_POLICY = yes|no|ask|accept-new (default: accept-new)
|
||||||
|
HKP="${BACKTUNNEL_HOSTKEY_POLICY:-accept-new}"
|
||||||
|
case "$HKP" in
|
||||||
|
yes|no|ask|accept-new) ;;
|
||||||
|
*) HKP="accept-new" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
# Config discovery
|
# Config discovery
|
||||||
# Purpose: choose the highest-precedence profiles.ini available.
|
# Purpose: choose the highest-precedence profiles.ini available.
|
||||||
@@ -464,7 +471,7 @@ ${AUTH_CMD}
|
|||||||
${INVITE_CMD}
|
${INVITE_CMD}
|
||||||
|
|
||||||
# Unmount when done:
|
# Unmount when done:
|
||||||
fusermount -u '${INVITE_MOUNT}' || fusermount3 -u '${INVITE_MOUNT}'
|
backtunnel-umount '${INVITE_MOUNT}'
|
||||||
EOT
|
EOT
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@@ -476,7 +483,7 @@ EOT
|
|||||||
${INVITE_CMD}
|
${INVITE_CMD}
|
||||||
|
|
||||||
# Unmount when done:
|
# Unmount when done:
|
||||||
fusermount -u '${INVITE_MOUNT}' || fusermount3 -u '${INVITE_MOUNT}'
|
backtunnel-umount '${INVITE_MOUNT}'
|
||||||
EOT
|
EOT
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
@@ -512,7 +519,7 @@ echo "To stop sharing early: press Ctrl+C in this window."
|
|||||||
# Pre-flight: warn if remote loopback port already in use (best-effort)
|
# Pre-flight: warn if remote loopback port already in use (best-effort)
|
||||||
# Purpose: give an actionable warning before attempting the -R bind.
|
# Purpose: give an actionable warning before attempting the -R bind.
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
if ssh -o BatchMode=yes -o ConnectTimeout=5 "${REMOTE_USER}@${REMOTE_HOST}" \
|
if ssh -o BatchMode=yes -o StrictHostKeyChecking="$HKP" -o ConnectTimeout=5 "${REMOTE_USER}@${REMOTE_HOST}" \
|
||||||
"command -v nc >/dev/null 2>&1 && nc -z 127.0.0.1 ${TUNNEL_PORT}"; then
|
"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
|
echo "⚠️ Port ${TUNNEL_PORT} on remote 127.0.0.1 appears in use; choose another with -p." >&2
|
||||||
# You may 'exit 1' here if you prefer a hard failure
|
# You may 'exit 1' here if you prefer a hard failure
|
||||||
@@ -545,6 +552,7 @@ ssh -N \
|
|||||||
-o ExitOnForwardFailure=yes \
|
-o ExitOnForwardFailure=yes \
|
||||||
-o ServerAliveInterval=15 \
|
-o ServerAliveInterval=15 \
|
||||||
-o ServerAliveCountMax=3 \
|
-o ServerAliveCountMax=3 \
|
||||||
|
-o StrictHostKeyChecking="$HKP" \
|
||||||
-R "${TUNNEL_PORT}:localhost:${LOCAL_SSH_PORT}" \
|
-R "${TUNNEL_PORT}:localhost:${LOCAL_SSH_PORT}" \
|
||||||
-- "${REMOTE_USER}@${REMOTE_HOST}" &
|
-- "${REMOTE_USER}@${REMOTE_HOST}" &
|
||||||
SSH_PID=$!
|
SSH_PID=$!
|
||||||
|
|||||||
35
scripts/backtunnel-umount
Normal file
35
scripts/backtunnel-umount
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# Name: backtunnel-umount
|
||||||
|
# Summary: Unmount a BackTunnel FUSE mount point using the best available helper.
|
||||||
|
# Usage:
|
||||||
|
# backtunnel-umount <mountpoint>
|
||||||
|
# Notes:
|
||||||
|
# - Prefers fusermount3, then fusermount; falls back to umount.
|
||||||
|
# - Expands a leading "~" in the mountpoint.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: $(basename "$0") <mountpoint>" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
-h|--help) usage ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
MP="${1:-}"
|
||||||
|
[[ -n "$MP" ]] || usage
|
||||||
|
|
||||||
|
# Expand leading ~
|
||||||
|
if [[ "$MP" == "~"* ]]; then
|
||||||
|
MP="${MP/#\~/$HOME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v fusermount3 >/dev/null 2>&1; then
|
||||||
|
exec fusermount3 -u -- "$MP"
|
||||||
|
elif command -v fusermount >/dev/null 2>&1; then
|
||||||
|
exec fusermount -u -- "$MP"
|
||||||
|
else
|
||||||
|
exec umount -- "$MP"
|
||||||
|
fi
|
||||||
7
tests/test-hostkey-policy.bats
Normal file
7
tests/test-hostkey-policy.bats
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
# Scaffold for host key policy; to be implemented with a controlled SSH target or dry-run hooks.
|
||||||
|
|
||||||
|
@test "BACKTUNNEL_HOSTKEY_POLICY scaffold" {
|
||||||
|
skip "TODO: verify policy propagation into ssh/sftp/sshfs invocations"
|
||||||
|
}
|
||||||
11
tests/test-umount.bats
Normal file
11
tests/test-umount.bats
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "backtunnel-umount shows usage with no args" {
|
||||||
|
run scripts/backtunnel-umount
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Usage:"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "backtunnel-umount integration (scaffold)" {
|
||||||
|
skip "TODO: create a temporary FUSE mount and verify unmount behavior"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user