#!/bin/bash

set -eo pipefail

if ! type jq >/dev/null 2>&1; then
  echo "missing jq" >&2
  exit 1
fi

ISENGARD_CACHE_DIR="${ISENGARD_CACHE_DIR-"$HOME/.cache/isengard"}"

# Fetch credentials from isengard.  These creds are used by AWS SDK to authenticate.  Note that
# it uses a local file system cache to prevent spamming isengard.
# The location is ${ISENGARD_CACHE_DIR} (set above)
# $1 is the account ID and $2 is the role name
function get_credentials() {
  set -u

  if [ ! -f ~/.midway/cookie ]; then
    echo "midway cookie not found.  You may need to run mwinit" >&2
    return 1
  fi

  local account_id="$1" role="$2"
  mkdir -p "${ISENGARD_CACHE_DIR}"
  chmod 0700 "${ISENGARD_CACHE_DIR}"
  local isengard_cache="${ISENGARD_CACHE_DIR}/${account_id}-${role}.json"
  # refresh cache at 10 minutes
  local refresh_at=${ISENGARD_CACHE_TIME-600000}
  if [ -f "${isengard_cache}" ]; then
    local credentials="$(cat ${isengard_cache})"
    local expiration="$(echo "$credentials" | jq -r '.expiration')";
    local curtime=$(($(date +%s)*1000))
    local leftover=$(($expiration - $curtime))
    if (( leftover > refresh_at)); then
      echo ${credentials}
      return 0
    fi
    # Cache bad.  Kill it with fire
    rm -f "${isengard_cache}"
  fi
  local credentials_and_code=$(curl --silent --write-out "HTTPSTATUS:%{http_code}" -k -b ~/.midway/cookie -c ~/.midway/cookie -L -X POST --header "X-Amz-Target: IsengardService.GetAssumeRoleCredentials" --header "Content-Encoding: amz-1.0" --header "Content-Type: application/json; charset=UTF-8" -d "{\"AWSAccountID\": \"$1\", \"IAMRoleName\":\"$2\"}" https://isengard-service.amazon.com);
  local http_status=$(echo "${credentials_and_code}" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
  local http_body=$(echo "${credentials_and_code}" | sed -e 's/HTTPSTATUS\:.*//g')
  if (( "200" != "${http_status}")); then
    echo "Invalid isengard status code: ${http_status}" >&2
    echo "${http_body}" >&2
    return 1
  fi
  local credentials=$(echo "${http_body}" | jq -r '.AssumeRoleResult | fromjson | .credentials')
  echo ${credentials} > "${isengard_cache}"
  chmod 0600 "${isengard_cache}"
  echo ${credentials}
}

function usage-error() {
  if [ -n "$1" ]; then
    echo "$1" >&2
  fi
  echo "Usage: $(basename "$0") --account-id <account_id> --role <role>" >&2
  echo "--account-id <account_id> is the AWS account ID" >&2
  echo "--role <role> is the Isengard role name" >&2
  exit 1
}

function require-argument() {
  [ -n "$2" ] || usage-error "Missing required argument $1"
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --account-id)
      account_id="$2"
      shift 2
      ;;
    --role)
      role="$2"
      shift 2
      ;;
    *)
      usage-error "Unrecognized option $1"
      ;;
  esac
done

require-argument --account-id "$account_id"
require-argument --role "$role"

CREDS="$(get_credentials "$account_id" "$role")"

# Remap keys to format
# {
#   "Version": 1,
#   "AccessKeyId": "",
#   "SecretAccessKey": "",
#   "SessionToken": "",
#   "Expiration": ""
# }
echo "$CREDS" | jq -r '.["AccessKeyId"] = .accessKeyId | .["SecretAccessKey"] = .secretAccessKey | .["SessionToken"] = .sessionToken | .["Expiration"] = (.expiration / 1000 | todate) | del(.accessKeyId, .secretAccessKey, .sessionToken, .expiration) | .["Version"] = 1'
