#!/usr/bin/env bash
# Formfiller that reads credentials from file and let vimb fill execute a
# JavaScript method to fill in the form data. Call this from vimb by ':sh!
# formfiller %'
#
# The form data are stored in $VIMB_KEY_DIR or as fallback
# $XDG_CONFIG_HOME/vimb/keys. The files must be names as
# [prefix]{domain}.gpg or [prefix]{domain}. The files must contain a valid
# JavaScript array that can be used for the _vbform.fill() method.
#
# A unencrypted sample file could look like this:
# ["input[name='user']:daniel", "input[name='password']:p45w0rD"]

# dmenu command use in case multiple files are found for current domain
DMENU="dmenu -l 7"

if [[ -z "$XDG_CONFIG_HOME" ]]; then
    XDG_CONFIG_HOME=$HOME/.config
fi

VIMB_KEY_DIR=${VIMB_KEY_DIR:-"$XDG_CONFIG_HOME/vimb/keys"}
uri=$1

die() {
    echo "$1" >&2
    exit 1
}

fillform() {
    local path=$1
    local data=""
    case "$path" in
        *.gpg )
            # this requires the gpg-agent to contains already the key
            data=$(gpg --batch -qd "$path")
            # abort here if the file could not be decrypted
            if [ $? -gt 0 ]; then
                exit 1
            fi
            ;;
        * )
            data=$(cat "$path")
            ;;
    esac
    # make sure we are in normal mode and fill in the form data
    # use :: to not save the secrets into vimb command history or into the
    # last ex command register ":
    echo "<Esc>::e! _vbform.fill($data);<CR>" | socat - UNIX-CONNECT:$VIMB_SOCKET
}

# check if uri is given
if [ -z "$uri" ]; then
    die 'No URI given'
fi
# check if the script is run from vimb with socket support enabled
if [ -z "$VIMB_SOCKET" ] || [ ! -S "$VIMB_SOCKET" ]; then
    die 'This script must be run from vimb with socket support'
fi

# extract the domain part without ports from given uri
domain=$(echo "$uri" | sed -r 's@https?://([^:/]+).*@\1@')

# find matching data files prefix${domain}{,.gpg}
files=($(find "$VIMB_KEY_DIR" -name "*$domain" -o -name "*${domain}.gpg"))
# strip of the key dir
files=("${files[@]#"$VIMB_KEY_DIR"/}")

# if only one matchin data file found - use this direct
if [ ${#files[@]} -eq 1 ]; then
    fillform "$VIMB_KEY_DIR/${files[0]}"
    exit 1
else
    # else allow to select the right one via dmenu
    match=$(printf '%s\n' "${files[@]}" | sort | $DMENU)
    if [ -n $match ]; then
        fillform "$VIMB_KEY_DIR/$match"
    fi
fi
