#!/bin/bash

PATH=/lib/rc/bin:$PATH

TEXTDOMAIN=cl_access_add
CL_ACCESS_VERSION=0.1.0_beta3
DESCRIPTION=$"Access preparing tools"
DEBUG_LOG=/var/log/calculate/cl-access-add.log

USERNAME=access
ACCESSDIR=/var/calculate/access
STORAGE=$ACCESSDIR/storage


# прервать скрипт в случае ошибки любой из команд
# break the script execution in case of a command error
set -e

: >$DEBUG_LOG

# вывод короткой справки
# show the short help message
usage() {
    echo "Usage: $0 --id ID [--ssh-key PKEY] [--header HEADER] --key KEYFILE --device DEVICE --mount DIR

Version: $CL_ACCESS_VERSION

${DESCRIPTION}

    -h, --help  display all options and exit"
}

# вывод полной справки
# show the long help message
long_usage() {
    echo "Usage: $0 --id ID [--ssh-key PKEY] [--header HEADER] --key KEYFILE --device DEVICE --mount DIR

Version: $CL_ACCESS_VERSION

${DESCRIPTION}

  --id ID                       set access id
  -s PKEY, --ssh-key PKEY       public authorized key
  -H HEADER, --header HEADER    separated LUKS header
  -k KEYFILE, --key KEYFILE     LUKS key file
  -d DEVICE, --device DEVICE    LUKS device (/dev or PARTUUID)
  -m DIR, --mount DIR           mount point
"
}

# подготовить параметры командной строки
# prepare the commmand line parameters
rearrange_params() {
    set +e
    TEMP=$(unset POSIXLY_CORRECT; getopt \
        -o "hs:H:k:d:m:" \
        --long help \
        --long id: \
        --long ssh-key: \
        --long header: \
        --long key: \
        --long device: \
        --long mount: \
        -- "$@" 2>&1)
    if (( $? != 0 )); then
        echo "$TEMP" | sed 's/getopt: /cl-access-add: /;$d'
        exit 1
    fi
    set -e
}

# выполнить параметры командной строки
# apply the command line parameters
do_args() {
    while :; do
        case $1 in
        -h|--help)
            long_usage
            exit 0
            ;;
        --id)
            ID="$2"
            shift
            ;;
        -s|--ssh-key)
            SSHKEY="$2"
            shift
            ;;
        -H|--header)
            HEADER="$2"
            shift
            ;;
        -k|--key)
            KEY="$2"
            shift
            ;;
        -d|--device)
            DEVICE="$2"
            shift
            ;;
        -m|--mount)
            MP="$2"
            shift
            ;;
        --) shift; break;;
        *) usage;
           eerror $"Unknown option: $1"
           ;;
       esac
       shift
    done
    if [[ -n $1 ]]
    then
        usage;
        eerror $"Unknown argument: $1"
    fi
}

######################
# Обработать параметры
# Process the options
######################
rearrange_params "$@"
eval set -- "$TEMP"
do_args "$@"

check_setup() {
    [[ -d $ACCESSDIR ]]
}

id_not_exists() {
    local id=$1
    [[ ! -d $STORAGE/$id ]]
}

create_id() {
    local id=$1
    local dn=$STORAGE/$id
    mkdir -p $dn
    chown $USERNAME. -R $dn
}

update_sshkey() {
    local id=$1
    local sshkey=$2
    local publickey=$STORAGE/$id/id_rsa.pub
    local sshdir=$ACCESSDIR/.ssh
    local authkeys=$sshdir/authorized_keys
    cp $sshkey $publickey
    chown $USERNAME. $publickey
    if [[ -f $authkeys ]]
    then
        sed -i "/access-shell $id/d" $authkeys
    else
        if [[ ! -d $sshdir ]]
        then
            mkdir -p $sshdir
            chown $USERNAME. $sshdir
        fi
        touch $authkeys
    fi
    cat >>$authkeys <<EOF
command="~/bin/access-shell $id",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $(cat $publickey)
EOF
    chown $USERNAME. $authkeys
}

ask_rewrite_sshkey() {
    while true
    do
        read -p $"Do you want replace authorzied key? " yn
        case $yn in
            [Yy]* ) return 0;;
            [Nn]* ) return 1;;
            * ) ewarn $"Please answer yes or no." ;;
        esac
    done
}

check_sshkey() {
    local sshkey=$1
    if ! [[ -f $sshkey ]]
    then
        eerror $"Public authorized key not found"
        return 1
    fi
    if grep -q "PRIVATE KEY" $sshkey
    then
        eerror $"You should use public key instead private"
        return 1
    fi
    if ! ssh-keygen -l -f $sshkey &>/dev/null
    then
        eerror $"$sshkey is not public key"
        return 1
    fi

    return 0
}

check_luks_header() {
    local header=$1
    if ! [[ -f $header ]]
    then
        eerror $"LUKS header not found"
        return 1
    fi
    return 0
}

check_luks_key() {
    local key=$1
    local header=$2

    if ! [[ -f $key ]]
    then
        eerror $"LUKS key not found"
        return 1
    fi
}

check_device_name() {
    local device=$1
    is_uuid $device || is_dev $device || eerror $"Device must be PARTUUID or /dev"
}

is_uuid() {
    [[ "$1" =~ ^(PARTUUID=)?\"?(([0-9a-f]+-)+[0-9a-f]+)\"?$ ]]
}

is_dev() {
    [[ "$1" =~ ^/dev/ ]]
}

create_record() {
    local id=$1
    local key=$2
    local device=$3
    local mp=$4
    local header=$5
    for rec in {0..99}
    do
        recdn=$STORAGE/$id/$rec
        if [[ ! -d $recdn ]]
        then
            mkdir -p $recdn
            [[ -n $header ]] && cp $header $recdn/header
            cp $key $recdn/key
            if is_uuid $device
            then
                echo ${BASH_REMATCH[2]} >$recdn/partuuid
            else
                echo $device >$recdn/dev
            fi
            echo  $mp >$recdn/mountpoint

            break
        fi
    done
}

check_setup || eerror $"Calculate access is not setup"

[[ -z $ID ]] && usage && eerror $"Please specify ID"
[[ -z $SSHKEY ]] && id_not_exists $ID && eerror $"You should specify ssh key for register new ID"
[[ -z $KEY ]] && usage && eerror $"Please specify LUKS key"
[[ -z $DEVICE ]] && usage && eerror $"Please specify LUKS device"
[[ -z $MP ]] && usage && eerror $"Please specify mount point"


[[ -n $HEADER ]] && check_luks_header $HEADER
[[ -n $KEY ]] && check_luks_key $KEY $HEADER
[[ -n $SSHKEY ]] && check_sshkey $SSHKEY
#check_mount_point_name $MOUNTPOINT
check_device_name $DEVICE

if [[ -n $SSHKEY ]]
then
	id_not_exists $ID || ask_rewrite_sshkey
fi

id_not_exists $ID && create_id $ID

create_record "$ID" "$KEY" "$DEVICE" "$MP" "$HEADER"

[[ -n $SSHKEY ]] && update_sshkey $ID $SSHKEY

[[ -n $HEADER ]] && rm -f $HEADER
[[ -n $KEY ]] && rm -f $KEY
[[ -n $SSHKEY ]] && rm -f $SSHKEY

einfo "All OK!"
