#!/usr/bin/env nix-shell
#!nix-shell -i bash -p bash -p gnugrep -p oath-toolkit -p sops
# use: `sane-dump-secret /path/to/accounts/website.yaml`
# dumps relevant information about the account, include a OTP code if present
#
# N.B.: avoid leaking secrets into cmdline args, where they're globally visible via /proc/$PID/cmdline!
# `echo "$str" | something-else` manages to avoid this, but only if using the shell's builtin echo
# so e.g. `echo`ing the variable in a subshell might leak it.

secretName=
fields=()
format=

usage() {
  echo "sane-secrets-dump [flags ...] path-or-secret-name"
  echo ""
  echo "flags:"
  echo "- --field FIELD: dump a specific field within the secret"
  echo "                 specify multiple times to dump multiple fields, in the order specified"
  echo "- --pretty:      dump like 'key: value'"
  echo "- --raw:         dump just the values, no keys"
  exit "$1"
}

parseArgs() {
  while [ "$#" -ne 0 ]; do
    local arg=$1
    shift
    case $arg in
      (--field)
        fields+=("$1")
        shift
        ;;
      (--pretty)
        format=pretty
        ;;
      (--raw)
        format=raw
        ;;
      (--help)
        usage 0
        ;;
      (*)
        secretName="$arg"
        ;;
    esac
  done

  if [ -z "$format" ]; then
    if [ "${#fields[@]}" -eq 0 ]; then
      format=pretty
    else
      format=raw
    fi
  fi

  if [ -z "$secretName" ]; then
    usage 1
  fi
}

path=
tryPath() {
  if test -f "$1"; then
    path="$1"
    return 0
  else
    return 1
  fi
}

locateSecret() {
  tryPath "$1" \
    || tryPath ~/knowledge/secrets/accounts/low-risk/"$1.yaml" \
    || tryPath ~/knowledge/secrets/accounts/high-risk/"$1.yaml" \
    || tryPath ~/knowledge/secrets/accounts/"$1.yaml"
}

getValue() {
  local _outvar=$1
  local _from=$2
  local _field=$3
  local _value=$(echo "$_from" | grep "^$_field=" | cut -d '=' -f 2-)
  declare -g "$_outvar"="$_value"
}

printKeyValue() {
  local format=$1
  local field=$2
  local value=$3
  case $format in
    (raw)
      echo "$value"
      ;;
    (pretty)
      echo "$field: $value"
      ;;
    (*)
      usage 1
      ;;
  esac
}

main() {
  parseArgs "$@"
  if ! locateSecret "$secretName"; then
    echo "can't find any secret by name $secretName" >&2
    exit 2
  fi

  secrets=$(sops -d --output-type dotenv "$path")

  if [ "${#fields[@]}" -ne 0 ]; then
    for field in "${fields[@]}"; do
      getValue value "$secrets" "$field"
      printKeyValue "$format" "$field" "$value"
    done
  else
    getValue username "$secrets" "username"
    getValue password "$secrets" "password"
    getValue totp "$secrets" "totp-b32"
    printKeyValue "$format" "username" "$username"
    printKeyValue "$format" "password" "$password"
    if [ -n "$totp" ]; then
      totp=$(echo "$totp" | oathtool -b -)
      printKeyValue "$format" "totp" "$totp"
    fi
  fi
}

main "$@"
