#!/usr/bin/env bash
set -euo pipefail

function print_verbose() {
  if [ "${VERBOSE}" = true ]; then
    echo $1
  fi
}

function print_error() {
  echo "$@" 1>&2;
}

function download() {
  local URL=$1
  local OUTPUT_FILE=$2
  local TMP_FILE=$(mktemp)
  local HTTP_CODE=$(curl --silent --output ${TMP_FILE} --write-out "%{http_code}" -L "${URL}")
  if [[ ${HTTP_CODE} -lt 200 || ${HTTP_CODE} -gt 299 ]]; then
    rm -f ${TMP_FILE}
    return 1
  fi

  if [ ! -s "${TMP_FILE}" ]; then
    rm -f ${TMP_FILE}
    return 1
  fi

  cp ${TMP_FILE} ${OUTPUT_FILE}
  rm -f ${TMP_FILE}
  return 0
}

function download_public_key_from_github() {
  local USER="$1"
  local KEY_FILE="$2"

  if ! download "https://github.com/${USER}.keys" ${KEY_FILE}; then
    return 1
  else
    return 0
  fi
}

function download_public_key_from_gitlab() {
  local USER="$1"
  local KEY_FILE="$2"

  if ! download "https://gitlab.eclipse.org/${USER}.keys" ${KEY_FILE}; then
    return 1
  else
    return 0
  fi
}

function get_eclipse_profile() {
  local USER=$1
  local TMP_FILE=$(mktemp)

  if download "https://api.eclipse.org/account/profile/${USER}" ${TMP_FILE}; then
    cat "${TMP_FILE}"
  fi

  rm -f ${TMP_FILE}
}

function get_github_handle() {
  local PROFILE=$1
  local GITHUB_HANDLE=$(echo "${PROFILE}" | jq -r ".github_handle")
  echo ${GITHUB_HANDLE}
}

function encrypt_content() {
  local INPUT=$1
  local OUTPUT=$2
  shift
  shift
  local KEY_FILES=("$@")

  local ARGS="-a "

  for KEY_FILE in "${KEY_FILES[@]}"
  do
    ARGS+="-R ${KEY_FILE} "
  done

  if [ ! -z ${OUTPUT} ]; then
    ARGS+="-o ${OUTPUT} "
  fi

  if ! age ${ARGS} "${INPUT}"; then
    return 1
  else
    return 0
  fi
}

function cleanup() {
  for KEY_FILE in "${KEY_FILES[@]}"
  do
      rm -f ${KEY_FILE}
  done
}

usage() {
  local USAGE
  USAGE="
Usage: $(basename "${0}") [OPTIONS] [INPUT]

"${0}" encrypts INPUT to OUTPUT. The INPUT argument is optional and defaults to standard input.
Only a single INPUT file may be specified. If -o is not specified, OUTPUT defaults to standard output.

Options:
  -e USER        Encrypt for a recipient identified by an Eclipse user id.
                 This option can be repeated and combined with -g and the file can be decrypted
                 by all provided recipients independently.
  -g USER        Encrypt for a recipient identified by a GitHub user id.
                 This option can be repeated and combined with -e and the file can be decrypted
                 by all provided recipients independently.
  -o OUTPUT      Write encrypted or decrypted file to OUTPUT instead of standard output.
                 If OUTPUT already exists it will be overwritten.
  -v             Enable verbose output.
  -h             Show this help.

"
  echo "$USAGE"
  exit 1
}

if ! command -v age &> /dev/null
then
    echo "age could not be found, installation instructions can be found at: https://github.com/FiloSottile/age"
    exit 1
fi

if ! command -v jq &> /dev/null
then
    echo "jq could not be found, installation instructions can be found: https://github.com/jqlang/jq"
    exit 1
fi

ECLIPSE_USERS=()
GITHUB_USERS=()
VERBOSE=false

while getopts ":e:g:i:o:v" o; do
    case "${o}" in
        e)
            ECLIPSE_USERS+=(${OPTARG})
            ;;
        g)
            GITHUB_USERS+=(${OPTARG})
            ;;
        i)
            INPUT_FILE=${OPTARG}
            ;;
        o)
            OUTPUT_FILE=${OPTARG}
            ;;
        v)
            VERBOSE=true
            ;;
        *)
            usage
            ;;
    esac
done

shift $((OPTIND-1))

if [ ${#ECLIPSE_USERS[@]} -eq 0 ] && [ ${#GITHUB_USERS[@]} -eq 0 ]; then
  print_error "Need to specify at least 1 recipient"
  usage
  exit 1
fi

trap cleanup EXIT

KEY_FILES=()

# trying to get keyfiles for any eclipse user
for USER in "${ECLIPSE_USERS[@]}"
do
  print_verbose "Downloading keyfile for Eclipse user '${USER}'"

  ECLIPSE_PROFILE=$(get_eclipse_profile "${USER}")
  if [ -z "${ECLIPSE_PROFILE}" ]; then
    print_error "No Eclipse profile found for user '${USER}'"
    exit 1
  fi

  KEY_FILE=$(mktemp)

  if ! download_public_key_from_gitlab "${USER}" "${KEY_FILE}"; then
    print_verbose "Failed to download keys from Gitlab for user '${USER}', trying GitHub..."

    GITHUB_USER=$(get_github_handle "${ECLIPSE_PROFILE}")
    if [ -z ${GITHUB_USER} ]; then
      rm -f "${KEY_FILE}"
      print_error "Failed to get GitHub handle for Eclipse user '${USER}'"
      exit 1
    fi

    if ! download_public_key_from_github "${GITHUB_USER}" "${KEY_FILE}"; then
      rm -f "${KEY_FILE}"
      print_error "Failed to download keys from GitHub for user '${GITHUB_USER}'"
      exit 1
    else
      print_verbose "Downloaded keys from GitHub for user '${GITHUB_USER}'"
    fi
  else
    print_verbose "Downloaded keys from Gitlab for user '${USER}'"
  fi

  KEY_FILES+=($KEY_FILE)
done

# trying to get keyfiles for any github user
for USER in "${GITHUB_USERS[@]}"
do
  print_verbose "Downloading keyfile for GitHub user '${USER}'"
  KEY_FILE=$(mktemp)

  if ! download_public_key_from_github "${USER}" "${KEY_FILE}"; then
    rm -f "${KEY_FILE}"
    print_error "Failed to download keys from GitHub for user '${USER}'"
    exit 1
  else
    print_verbose "Downloaded keys from GitHub for user '${USER}'"
  fi

  KEY_FILES+=($KEY_FILE)
done

INPUT=${1--}

if [ -z ${OUTPUT_FILE-} ]; then
  print_verbose "Encrypting to standard output"
else
  print_verbose "Encrypting to '${OUTPUT_FILE}'"
fi

encrypt_content "${INPUT}" "${OUTPUT_FILE-}" "${KEY_FILES[@]}"
