#!/bin/bash
set -e

# rsshfs: reverse sshfs
# v1.0 (2020-05-17), ed <irc.rizon.net>, MIT-licensed
# https://ocv.me/dev/?rsshfs.sh
#
# NOTE:
# while this appears to limit access to one particular folder,
# there is nothing stopping the remote machine from traversing
# the full filesystem on the local machine (under the privileges
# of the user running this script)
#
# trust is placed in the remote machine to do what it's told;
# sshfs does restrict access to the provided location, but
# sshfs (or the fifo) could be manipulated to do whatever
#
# the exception is `-o ro` (read-only) which is redundantly
# enforced on both sides


err() {
  printf '\n  \033[31merror:\033[0m %s\n\n' "$*"
}


help() {
  err $*
  cat <<'EOF'
need arg 1: local folder to share (path)
need arg 2: destination on remote (user@host:path)
  optional: sshfs options

example:
  rsshfs ./Movies ed@192.168.1.23:/mnt/movies -o ro

suggested options:
  -o ro,uid=1000,gid=1000,follow_symlinks,allow_other

depenedencies:
  on local machine: openssh (ssh, sftp-server)
  on remote machine: sshfs

EOF
  exit 1
}


[ ! -z "$1" ] &&
[ -e "$1" ] ||
  help arg 1 is not a local folder


printf '%s\n' "$2" |
grep -qE '.+:.+' ||
  help arg 2 is not a remote location


local="$1"
box="${2%%:*}"
remote="${2#*:}"
shift 2
sshfs_args="$@"
sftp_args=""
readonly=no


esc_local="$( printf '%q' "$local")"
esc_remote="$(printf '%q' "$remote")"


printf '%s\n' "$sshfs_args" |
grep -qE '(^| )-o ?([^ ]+,)?ro(,| |$)' &&
  sftp_args="$sftp_args -R" &&
  readonly=yes


sftp_bin="$(cat /dev/shm/rsshfs.bin 2>/dev/null || true)"
[ -e "$sftp_bin" ] || {
  sftp_bin="$(
    find /usr -name sftp-server 2>/dev/null |
    head -n 1 |
    grep -E ...
  )" || {
    err could not locate dependency: sftp-server
    exit 1
  }
  printf '%s\n' "$sftp_bin" > /dev/shm/rsshfs.bin
}


printf '(rsshfs.%d' $$

printf '\033[36m)  %s(\033[0m%s' \
         box "$box"        \
   read-only "$readonly"   \
       local "$local"      \
      remote "$remote"     \
   sftp-args "$sftp_args"  \
  sshfs-args "$sshfs_args"

printf '\033[36m)\033[0m\n'


fifo=/dev/shm/rsshfs.$$
rm -f $fifo
mkfifo -m600 $fifo


rv=1
function cleanup() {
  rm -f $fifo
  exit $rv
}
trap cleanup EXIT


set +e

"$sftp_bin" $sftp_args <$fifo | ssh "$box" \
  sshfs -o slave ":$esc_local" "$esc_remote" "$sshfs_args" >$fifo

arv="${PIPESTATUS[*]}"
rv=$(
  printf '%d\n' 0 $arv |
  sort -n |
  grep -vE '^130$' |
  tail -n 1
)
