#!/usr/bin/env bash
#
# crypt — montera gocryptfs-valvet på USB-stickan till ~/crypt
#
# Hittar själv den krypterade katalogen (den som innehåller gocryptfs.conf)
# på inkopplade USB-diskar. gocryptfs frågar efter lösenordet själv, så
# ingen hemlighet passerar det här scriptet.
#
# Användning:  crypt            montera (default)
#              crypt umount     avmontera
#              crypt status     visa läge
#              crypt toggle     montera om avmonterat, annars avmontera
#
# Miljövariabler:
#   CRYPT_MOUNT      monteringspunkt          (default: ~/crypt)
#   CRYPT_CIPHERDIR  krypterad katalog        (default: autodetekteras)

set -euo pipefail

MOUNT="${CRYPT_MOUNT:-$HOME/crypt}"

die()  { printf '✗ %s\n' "$*" >&2; exit 1; }
info() { printf '%s\n' "$*"; }

command -v gocryptfs >/dev/null 2>&1 || die "gocryptfs saknas (sudo apt install gocryptfs fuse3)"

FUSERMOUNT=$(command -v fusermount3 || command -v fusermount || true)
[ -n "$FUSERMOUNT" ] || die "fusermount saknas (sudo apt install fuse3)"

is_mounted() { mountpoint -q "$MOUNT" 2>/dev/null; }

# Skriver ut alla kataloger under monterade USB-diskar som ser ut som ett
# gocryptfs-valv (innehåller gocryptfs.conf).
find_cipherdirs() {
    local base conf
    for base in "/media/$USER" "/run/media/$USER"; do
        [ -d "$base" ] || continue
        while IFS= read -r conf; do
            dirname "$conf"
        done < <(find "$base" -maxdepth 3 -name gocryptfs.conf 2>/dev/null)
    done
}

# Monterar omonterade USB-partitioner via udisks om inget valv hittades.
automount_removable() {
    command -v udisksctl >/dev/null 2>&1 || return 1
    local name
    while read -r name; do
        [ -n "$name" ] && udisksctl mount -b "/dev/$name" >/dev/null 2>&1 || true
    done < <(lsblk -rno NAME,TYPE,RM,FSTYPE,MOUNTPOINT \
                 | awk '$2=="part" && $3=="1" && $4!="" && $5=="" {print $1}')
}

pick_cipherdir() {
    if [ -n "${CRYPT_CIPHERDIR:-}" ]; then
        [ -f "$CRYPT_CIPHERDIR/gocryptfs.conf" ] || die "ingen gocryptfs.conf i $CRYPT_CIPHERDIR"
        printf '%s\n' "$CRYPT_CIPHERDIR"
        return
    fi

    local dirs=()
    mapfile -t dirs < <(find_cipherdirs)
    if [ "${#dirs[@]}" -eq 0 ] && automount_removable; then
        sleep 1
        mapfile -t dirs < <(find_cipherdirs)
    fi

    case "${#dirs[@]}" in
        0) die "hittade inget gocryptfs-valv — sitter USB-stickan i? (eller sätt CRYPT_CIPHERDIR)" ;;
        1) printf '%s\n' "${dirs[0]}" ;;
        *) local d
           PS3="Välj valv: "
           select d in "${dirs[@]}"; do
               [ -n "${d:-}" ] && { printf '%s\n' "$d"; break; }
           done >&2 < /dev/tty ;;
    esac
}

do_mount() {
    if is_mounted; then
        info "● redan monterat på $MOUNT"
        return 0
    fi
    local cipher
    cipher=$(pick_cipherdir)
    mkdir -p "$MOUNT"
    # Monteringspunkten måste vara tom, annars nekar gocryptfs.
    if [ -n "$(ls -A "$MOUNT" 2>/dev/null)" ]; then
        die "$MOUNT är inte tom och inget är monterat där"
    fi
    info "Monterar $cipher → $MOUNT"
    gocryptfs "$cipher" "$MOUNT"
    info "● monterat på $MOUNT"
}

do_umount() {
    if ! is_mounted; then
        info "○ inget monterat på $MOUNT"
        return 0
    fi
    "$FUSERMOUNT" -u "$MOUNT" || die "kunde inte avmontera $MOUNT (används den? prova: fuser -vm $MOUNT)"
    info "○ avmonterat $MOUNT"
}

do_status() {
    if is_mounted; then
        info "● monterat på $MOUNT"
    else
        info "○ inte monterat ($MOUNT)"
    fi
    local d
    while IFS= read -r d; do info "  valv: $d"; done < <(find_cipherdirs)
}

case "${1:-mount}" in
    mount|m)         do_mount ;;
    umount|unmount|u) do_umount ;;
    status|s)        do_status ;;
    toggle|t)        if is_mounted; then do_umount; else do_mount; fi ;;
    -h|--help|help)  sed -n '3,17p' "$0" | sed 's/^# \{0,1\}//' ;;
    *)               die "okänt kommando: $1 (mount|umount|status|toggle)" ;;
esac
