#!/bin/bash
#(c) 2019 BIT

##### VARS ######
umask 077
export LANG="en_US.UTF-8"
export LANGUAGE="en_US:en"
export PATH="/bin:/usr/bin:/sbin:/usr/sbin"

ssh_dir="$HOME/.ssh"
bit_keys_dir="${ssh_dir}/bit-keys"
auth_file="${ssh_dir}/authorized_keys2"
bit_keys_history="${bit_keys_dir}/.history"
bit_keys_noacl="${bit_keys_dir}/.no-acl"
old_pre_deploy_key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEb/pvTou5eDm6DfPFcbT0UE6ig2S/Kfr4l3KO8M3sSE"

### FUNCTIONS ###
fatal() {
    echo "$*"
    exit 127
}

showHelp() {
    cat <<EOT
Usage: $0 --force ...[parameters]....

 Commands:
   --force   MUST BE FIRST PARAM  force bit-keys to run if cfengine detected
   
   --cc, -c                 Also place Customer Care SSH keys.
   --colo, -co              Also place Data Center Engineer SSH keys.
   --dev, -d                Also place Research & Development SSH keys.
        Usage of these option are remembered for future runs of bit-keys.

   --flush, -f              Reset the BIT-keys history & ACL choices.

   --no-acl, -n             Do *NOT* put from="" IP-ACL on bit-keys.
        Usage of this option is remembered for future runs of bit-keys.
        By default an IP-ACL is placed on bit-keys. This does *NOT*
        apply to included ".local" files, they get added verbatim.
        Use this option to *NOT* put IP-ACLs on bit-keys.

   --help, -h               Show this help message.
EOT
}

get_bitkey_file() {
    wget_cmd="wget -t 20 -qO"
    # fallback to curl if wget is unavailable
    if ! command -v wget >/dev/null; then
        wget_cmd="curl --retry 20 -so"
    fi
    ${wget_cmd} bit-keys-$1.tar     https://bitkeys.bit.nl/bit-keys/bit-keys-$1.tar
    ${wget_cmd} bit-keys-$1.tar.sig https://bitkeys.bit.nl/bit-keys/bit-keys-$1.tar.sig
    [ -f bit-keys-$1.tar -a -f bit-keys-$1.tar.sig ] || fatal "Downloading bit-keys ($1) failed? Files non-existant."
    [ -z bit-keys-$1.tar -o -z bit-keys-$1.tar.sig ] && fatal "Downloading bit-keys ($1) failed? Files empty."

    gpg -q --list-key 7703B420B543BD2DF9AF6197F22B95441BFBE521 >/dev/null 2>&1
    rval=$?
    if [ $rval != 0 ]; then
        gpg -q --import >/dev/null 2>&1 <<EOT
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
vg2f4Rg=
=8KrM
-----END PGP PUBLIC KEY BLOCK-----
EOT
        rval=$?
        [ $rval = 0 ] || fatal "GPG public key import failed?"
        echo "The GPG public key was imported."
    fi


    gpg --quiet --verify bit-keys-$1.tar.sig bit-keys-$1.tar >/dev/null 2>&1
    rval=$?
    case "$rval" in
        0)
            # sig verified
            ;;
        1)
            # sig invalid
            fatal "Invalid GPG signature for this tarball. Bailing!"
            ;;
        2)
            # key not found
            fatal "The GPG public key was not found or source file(s) empty. Bailing!"
            exit 0
            ;;
        *)
            # unhandled GPG error state
            fatal "Unhandled GPG error state '$rval'. Bailing!"
            ;;
    esac

    tar xf bit-keys-$1.tar
    [ $rval = 0 ] || fatal "Untar failed?"

    # Save history
    if [ -f "$bit_keys_history" ]; then
        # Check if group already exists
        if ! grep -Fxq "$1" $bit_keys_history; then
            echo "$1" >> $bit_keys_history
        fi
    else
        echo "$1" >> $bit_keys_history
    fi
}



### MAIN SCRIPT ###
if [ "$1" != "--force" -a -x /usr/sbin/cfagent ]; then
    echo "CFEngine is installed on this box. Refusing to run. Run with --force to force."
    exit 127
fi

# Clean up and householding
mkdir -p ${bit_keys_dir}
cd ${bit_keys_dir}
rm -f bit-keys*.tar bit-keys*.tar.sig
rm -f ${ssh_dir}/bitkeys.tar*

# Parse arguments
while [ ! $# -eq 0 ]; do
    case "$1" in
        --cc | -c)
            get_bitkey_file custcare
        ;;
        --colo | -co)
            get_bitkey_file colo
        ;;
        --dev | -d)
            get_bitkey_file dev
        ;;
        --flush | -f)
            rm -f $bit_keys_history $bit_keys_noacl
            echo "Flushed history & ACL settings!"
            exit
        ;;
        --no-acl | -n)
            touch ${bit_keys_noacl}
        ;;
        --help | -h)
            showHelp
            exit
        ;;
        *)
            echo "$0: invalid option: '$1'"
            showHelp
            exit
        ;;
  esac
  shift
done

# Check if there is a history file
if [ -f "$bit_keys_history" ]; then
    for i in $(cat $bit_keys_history); do
        [[ $i == "eng" ]] && continue
        echo "Using ${bit_keys_history} for group '$i'."
        get_bitkey_file $i
    done
fi

# Always download UNIX & NOC SSH keys
get_bitkey_file eng

# Mangle the trusted_from_addrs into a string for the from="" lines
if [ ! -e "${bit_keys_dir}/trusted_from_addrs.sh" ]; then
    echo "The bit-keys tar ball did not have the expected trusted_from_addrs.sh file! Bailing."
    exit 127
fi

source ${bit_keys_dir}/trusted_from_addrs.sh
trusted_from_str=""
for ip in ${trusted_from_addrs[@]}; do
    trusted_from_str="${trusted_from_str}${ip},"
done
trusted_from_str=$(echo "$trusted_from_str" | sed -e 's/,$//')

# Add all bit-keys
temp_file=$(mktemp)
find . -maxdepth 1 -type f -iname 'id_*.pub.*' | while read idfile
do
    idname=`echo "$idfile" | rev | cut -d"." -f1 | rev | cut -d"_" -f1`
    cat $idfile >> ${temp_file}
    echo "Added key: ${idname}"
done

# Prepend from="" IP-ACL limits to all bit-keys unless disabled.
if [ -e "${bit_keys_noacl}" ]; then
    echo "Found '${bit_keys_noacl}', not enforcing IP-ACLs"
else
    sed -i -e "s!^!from=\"${trusted_from_str}\" !g" ${temp_file}
fi

# Add *.local file contents
for aklf in authorized_keys.local authorized_keys2.local
do
    if [ -e ${ssh_dir}/${aklf} ]; then
        echo "Added keys from ${ssh_dir}/${aklf}"
        cat ${ssh_dir}/${aklf} >> ${temp_file}
    fi
done

# Update the auth_file
rm -f      ${auth_file}
touch      ${auth_file}
chmod 0640 ${auth_file}
cat >>${auth_file} <<EOT
# Updated: $(date -R)
#
# DO NOT CHANGE THIS FILE - IT IS MANAGED BY BIT-KEYS!
# ADD YOUR LOCAL SSH PUBLIC KEYS TO A FILE NAMED
# authorized_keys.local OR authorized_keys2.local
# AND IT WILL BE INCLUDED IN THIS FILE BY BIT-KEYS!
#
EOT
cat "${temp_file}" >> ${auth_file}

rm -f -- "${temp_file}" identity.pub.* id_*.pub.*

# Remove old pre-deploy key if exists
if [ -f "${ssh_dir}/authorized_keys" ]; then
     if grep -q "${old_pre_deploy_key}" "${ssh_dir}/authorized_keys"; then
	 sed -i "\|^${old_pre_deploy_key}.*|d" "${ssh_dir}/authorized_keys" && echo "Removed key: Pre-deploy"
     fi
fi
