#!/bin/bash
set -euo pipefail

# Usage:
#
# 1) Put this into your ~/.docker/config.json:
#    { "credsStore": "vault" }
#
# 2) Optional: Create ~/.config/docker-credential-vault with an
#    override for the $PREFIX variable which defaults to
#    "secret/docker-credential" in case you want to store the
#    credentials some place else. If you want the script to
#    behave more verbose you can set NO_LOG=0 in order to enable
#    logging all actions to STDERR
#
# 3) Ensure vault is installed and can access the path specified by
#    $PREFIX/*

config="${HOME}/.config/docker-credential-vault"
req_cmds=(jq md5sum vault)

: ${NO_LOG:=1}
PREFIX=secret/docker-credential

[[ -f $config ]] && source "${config}" || true

function check_command() {
  command -v "${1}" >/dev/null || {
    echo "Missing tool: ${1}" >&2
    exit 1
  }
}

function get() {
  local hostname="$(cat -s)" # Missing newline at the end, read does not work

  log "Retrieving credential for ${hostname} if exists..."
  vault read -field=data -format=json "${PREFIX}/$(hash_hostname "${hostname}")" 2>/dev/null || echo "{}"
}

function erase() {
  local hostname="$(cat -s)" # Missing newline at the end, read does not work

  log "Deleting credential for ${hostname} if exists..."
  vault delete "${PREFIX}/$(hash_hostname "${hostname}")" >/dev/null
}

function hash_hostname() {
  echo "$1" | md5sum | cut -d ' ' -f 1
}

function list() {
  local creds="{}"

  for key in $(vault list -format=json secret/docker-credential | jq -r '.[]'); do
    creds="$(vault read -field=data -format=json "${PREFIX}/${key}" | jq -c "${creds} + {(.ServerURL): .Username}")"
  done

  echo "${creds}"
}

function log() {
  [ $NO_LOG -eq 0 ] || return 0
  echo "[$(date +%H:%M:%S)][docker-credential-vault] $@" >&2
}

function main() {
  for cmd in "${req_cmds[@]}"; do
    check_command "${cmd}"
  done

  case "${1:-}" in
  get) get ;;
  erase) erase ;;
  list) list ;;
  store) store ;;
  *)
    echo "$(basename $0): Supported are only: get, erase, store (called '${1:-}')" >&2
    exit 1
    ;;
  esac
}

function store() {
  local json="$(cat -s)"

  local hostname=$(echo "${json}" | jq -r '.ServerURL')
  local username=$(echo "${json}" | jq -r '.Username')
  local secret=$(echo "${json}" | jq -r '.Secret')

  log "Updating credential for ${hostname}..."
  vault write "${PREFIX}/$(hash_hostname "${hostname}")" \
    "ServerURL=${hostname}" \
    "Username=${username}" \
    "Secret=${secret}"
}

main "$@"