if [ "x$DEBUG" = "x*" ]; then
    set -x
fi

if [ -z "$HOME" ]; then
    echo "Cannot find your user's home directory..."
    exit 1
fi

SECRETS="$HOME/.unlocker/.secrets"
LOCKED_SECRETS="$SECRETS.lock"

if [ "x$1" = "xhelp" ]; then
    echo "              _            _             "
    echo "  _   _ _ __ | | ___   ___| | _____ _ __ "
    echo " | | | | '_ \| |/ _ \ / __| |/ / _ \ '__|"
    echo " | |_| | | | | | (_) | (__|   <  __/ |   "
    echo "  \__,_|_| |_|_|\___/ \___|_|\_\___|_|   "
    echo ""
    echo "Unlocker v$VERSION $(uname -op)"
    echo ""
    echo "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR"
    echo "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,"
    echo "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE"
    echo "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER"
    echo "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,"
    echo "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE"
    echo "SOFTWARE."
    echo ""
    echo "  Please report bugs at $HOMEPAGE"
    echo ""
    echo "Usage:"
    echo "  service [user@]host[:port]  - Unlock server if credentials are known"
    echo ""
    echo "Examples:"
    echo "  redis 127.0.0.1:6379        - Connect to local Redis with an available user"
    echo "  mysql 127.0.0.1             - Connect to MySQL with any available user"
    echo "  mysql guest@database:3306   - Connect to MySQL on port 3306 with user guest"
    echo "  ssh root@yourserver.tld     - Connect to yourserver.tld with root user"
    echo "  ssh yourserver.tld          - Connect to yourserver.tld with available user"
    echo ""
    exit 0
fi

IS_LOCKED=$(ls -l "$LOCKED_SECRETS" 2> /dev/null | wc -l)
if [ "$IS_LOCKED" = "1" ]; then
    if ! [ -x "$(command -v gpg)" ]; then
        echo "Cannot decrypt secrets..."
        echo "Please install gpg and try again"
        echo "Closing..."
        exit 1
    fi
    gpg -o "$SECRETS" --decrypt "$LOCKED_SECRETS"
    if [ $? != "0" ]; then
        echo "Failed to decrypt secrets..."
        echo "Closing..."
        exit 1
    fi
    rm -f "$LOCKED_SECRETS"
    if [ -z "$1" ]; then
        echo "Secrets are now unlocked"
        exit 0
    fi
fi

IS_UNLOCKED=$(ls -l "$SECRETS" 2> /dev/null | wc -l)
if [ "$IS_UNLOCKED" = "0" ]; then
    echo "Either unlocker has not been initialized, either secrets are missing"
    echo "Try unlock help and unlocker -h"
    echo "Closing..."
    exit 1
fi

is_installed ()
{
    if [ "x$1" = "x?" ]; then
        shift
    fi
    if [ -z "$1" ]; then
        echo "Missing service to check if is installed..."
        exit 2
    elif ! [ -x "$(command -v $1)" ]; then
        echo "Cannot find $1..."
        echo "Please install $1 and try again"
        exit 1
    elif [ "x$DEBUG" = "x*" ]; then
        echo "$1 is installed..."
    fi
}

get_passkey()
{
    if [ "x$DEBUG" = "x*" ]; then
        echo $@ | unlocker | tr '\n' ' '
    else
        echo $@ | unlocker 2> /dev/null | tr '\n' ' '
    fi
}

get_password ()
{
    echo $1 | sed -En 's/^password (.*)/\1/pg' | python -m base64 -d
}

get_private_key ()
{
    echo $1 | sed -En 's/^privatekey (.*)/\1/pg' | python -m base64 -d
}

init ()
{
    mkdir -p /tmp/.unlocker
}

clean ()
{
    rm -rf /tmp/.unlocker
}

get_credentials ()
{
    export NOPAGER=true
    for line in "$(unlocker list | grep -E "$1 .* $2")"; do
        args=""
        user=$(echo $line | cut -d "|" -f 7 | tr -d " ")
        if [ ! -z "$user" ]; then
            args="${args}$user@$2"
        else
            args="${args}$2"
        fi
        port=$(echo $line | cut -d "|" -f 5 | tr -d " ")
        if [ ! -z "$port" ]; then
            args="${args}:$port"
        fi
        echo $args
    done
    unset NOPAGER
}

unlock_service ()
{
    init
    PROTOCOL=$1
    ADDRESS=$2
    case $PROTOCOL in
        ssh) {
            passkey=$(get_passkey ssh://$ADDRESS)
            if [ -z "$passkey" ]; then
                echo "Testing all possible credentials..."
                credentials=$(get_credentials "$PROTOCOL" "$ADDRESS")
                for addr in "$credentials"; do
                    passkey=$(get_passkey ssh://$addr)
                    if [ ! -z "$passkey" ]; then
                        ADDRESS=$addr
                        break
                    fi
                done
            fi
            params=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+):(.+)/\1@\2 -p\3/gp')
            if [ -z "$params" ]; then
                params=$ADDRESS
            fi
            if [ "x$DEBUG" = "xssh" -o "x$DEBUG" = "x*" ]; then
                params="-v $params"
            fi
            if [ -z "$passkey" ]; then
                echo "Cannot unlock server because passkey is missing..."
                echo "Recovering..."
                echo "Press any key to continue adding a password or a private key and store"
                echo "it for later use, otherwise exit with ^C or add it to unlocker manually"
                read -p "" anykey
                echo "Choose how to connect:"
                echo "  1) I have a password"
                echo "  2) I have a privatekey"
                echo ""
                read -p "Type number: " auth
                args=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+):(.+)/-u \1 -h \2 -p \3/pg')
                if [ -z "$args" ]; then
                    args=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+)/-u \1 -h \2 -p 22/pg')
                    if [ -z "$args" ]; then
                        args="-h $ADDRESS -p 22 -u _"
                    fi
                fi
                case $auth in
                    1) {
                        args="-a password $args"
                    }
                    ;;
                    2) {
                        args="-a privatekey $args"
                    }
                    ;;
                    *) {
                        echo "Unsuported authentification method..."
                        exit 1
                    }
                    ;;
                esac
                unlocker append $args
                passkey=$(get_passkey ssh://$ADDRESS)
            fi
            password=$(get_password "$passkey")
            if [ -z "$password" ]; then
                privatekey=$(get_private_key "$passkey")
                if [ -z "$privatekey" ]; then
                    echo "Cannot understand authentification method for $ADDRESS"
                    echo "It may not be supported by unlocker or it may corrupted"
                    exit 1
                fi
                secret_file=/tmp/.unlocker/$(date +%s).pk
                echo "$privatekey" > $secret_file
                chmod 0400 $secret_file
                params="-i $secret_file $params"
                is_installed ? ssh
                ssh $params
            else
                is_installed ? sshpass
                export SSHPASS="$password"
                sshpass -e ssh $params
                unset SSHPASS
            fi
        }
        ;;
        mysql) {
            params=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+):(.+)/-h\2 -P\3 -u\1/gp')
            if [ -z "$params" ]; then
                params=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+)/-h\2 -u\1/gp')
            fi
            if [ "x$DEBUG" = "xmysql" -o "x$DEBUG" = "x*" ]; then
                params="-v $params"
            fi
            passkey=$(get_passkey mysql://$ADDRESS)
            if [ -z "$passkey" ]; then
                echo "Cannot unlock server because passkey is missing..."
                echo "Recovering..."
                echo "Press any key to continue adding a password and store it for later"
                echo "use, otherwise exit with ^C or add it to unlocker manually"
                read -p "" anykey
                args=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+):(.+)/-u \1 -h \2 -p \3/pg')
                if [ -z "$args" ]; then
                    args=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+)/-u \1 -h \2 -p 3306/pg')
                fi
                unlocker append $args -a password
                passkey=$(get_passkey mysql://$ADDRESS)
            fi
            password=$(get_password "$passkey")
            if [ -z "$password" ]; then
                echo "Cannot understand authentification method for $ADDRESS"
                echo "It may not be supported by unlocker or it may corrupted"
                exit 1
            else
                params="-p$password $params"
            fi
            is_installed ? mysql
            mysql $params
        }
        ;;
        redis) {
            params=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+):(.+)/-h \2 -p \3/gp')
            if [ -z "$params" ]; then
                params=$(echo "$ADDRESS" | sed -En 's/(.+):(.+)/-h \1 -p \2/gp')
                if [ -z "$params" ]; then
                    params="-h $ADDRESS"
                fi
            fi
            if [ "x$DEBUG" = "xredis" -o "x$DEBUG" = "x*" ]; then
                echo "Unlocker doesn't support verbose mode for Redis"
            fi
            passkey=$(get_passkey redis://_@$ADDRESS)
            if [ -z "$passkey" ]; then
                echo "Cannot unlock server because passkey is missing..."
                echo "Recovering..."
                echo "Press any key to continue adding a password and store it for later"
                echo "use, otherwise exit with ^C or add it to unlocker manually"
                read -p "" anykey
                args=$(echo "$ADDRESS" | sed -En 's/(.+)@(.+):(.+)/-h \2 -p \3/pg')
                if [ -z "$args" ]; then
                    args=$(echo "$ADDRESS" | sed -En 's/(.+):(.+)/-h \1 -p \2/pg')
                    if [ -z "$args" ]; then
                        args="-h $ADDRESS -p 6379"
                    fi
                fi
                unlocker append $args -a password -u _
                passkey=$(get_passkey redis://_@$ADDRESS)
            fi
            password=$(get_password "$passkey")
            if [ -z "$password" ]; then
                echo "Cannot understand authentification method for $ADDRESS"
                echo "It may not be supported by unlocker or it may corrupted"
                exit 1
            else
                params="$params -a $password"
            fi
            is_installed ? redis-cli
            redis-cli $params
        }
        ;;
        *) {
            is_installed ? $PROTOCOL
            if [ $? != 0 ]; then
                echo "$PROTOCOL is installed on your system, but is not supported by Unlocker"
                echo "Help by submitting an implementation or a request at $HOMEPAGE"
                echo "Closing..."
                exit 1
            fi
        }
        ;;
    esac
    clean
}

if [ -z "$1" ]; then
    echo "Nothing to unlock (try help)"
    echo "Closing..."
    exit 1
fi

if [ -z "$2" ]; then
    echo "Server address required (try help)"
    echo "Closing..."
    exit 1
fi

cleanup ()
{
    clean
    echo "Closing..."
    exit 0
}

for app in cat wc grep sed tr cut tee python pip unlocker; do
    is_installed ? $app
done

trap cleanup 2 3

echo "Trying to unlock $2..."
unlock_service $@
echo "Successfully closed connection to $2..."
