#!/usr/bin/env bash

# a script to generate backups for my GPG keys

# Literally all of active keys I use for different purposes. For things like shared keys,
# I override them via PUBLIC_KEYS AND PRIVATE_KEYS variables at runtime.
DEFAULT_PRIVATE_KEYS="0527234A430387EA5695D824A30EBE40AD856D88 4D5E631758CB9CC45941B1CE67BFC91B3DA12BE8 EA957E7086E934F8DB9CAD21940047813E9D641C 5D69E717C5BC95731C2AD8BD120C218ED2291996 2CFF8721393487AEEF2C38987067DB4C7768552F 18C97CF46F06176E7EC43BDC7E4E0EF8B968A952 51D2F9710A20AAE56DC9A9AB77D63E4A0C267204"
DEFAULT_PUBLIC_KEYS="0527234A430387EA5695D824A30EBE40AD856D88 4D5E631758CB9CC45941B1CE67BFC91B3DA12BE8 EA957E7086E934F8DB9CAD21940047813E9D641C 5D69E717C5BC95731C2AD8BD120C218ED2291996"

# allow anybody to automate this via envvars
PRIVATE_KEYS="${PRIVATE_KEYS:-"$DEFAULT_PRIVATE_KEYS"}"
PUBLIC_KEYS="${PUBLIC_KEYS:-"$DEFAULT_PUBLIC_KEYS"}"

# Command snippet taken from OpenKeychain FAQs
# https://www.openkeychain.org/faq/#what-is-the-best-way-to-transfer-my-own-key-to-openkeychain
BACKUP_FILE_PASSWORD=$(gpg --armor --gen-random 1 20)
TIMESTAMP=$(date +%s)

generate_pubkey_bak() {
  echo "[Stage 1]: Export all public keys per PUBLIC_KEYS to '$EXPORT_DIR/pubkeys-$TIMESTAMP.asc'"
  echo
  sleep 3

  if [[ $_arg_secretkeys_only == "true" ]]; then
    echo "warning: Skipping because --only-secret flag is used"
    return
  fi

  for key in $PUBLIC_KEYS; do
    echo "Exporting keyid $key's public key"
    if [[ $_arg_dryrun == "true" ]]; then
      echo "+ gpg --armor --export \"$key\" >> \"$EXPORT_DIR/pubkeys-$TIMESTAMP.asc\""
    else
      gpg --armor --export "$key" >> "$EXPORT_DIR/pubkeys-$TIMESTAMP.asc"
    fi
    sleep 3
  done
  echo
}

generate_privkey_bak() {
  echo "[Stage 2]: Export all private keys per PRIVATE_KEYS to '$EXPORT_DIR/gpg-keys-backup-$TIMESTAMP.asc'"
  echo
  sleep 3

  if [[ $_arg_pubkeys_only == "true" ]]; then
    echo "warning: Skipping because --only-public flag is used"
    return
  fi

  if [[ $_arg_dryrun == "true" ]]; then
    for key in $PRIVATE_KEYS; do
      echo "Exporting keyid $key with private key"
      echo "+ gpg --armor --export-secret-keys $key >> $EXPORT_DIR/gpg-keys-backup-$TIMESTAMP.asc"
      sleep 5
    done
    echo "+ gpg --armor --batch --passphrase ${BACKUP_FILE_PASSWORD} --symmetric --output ${EXPORT_DIR}/gpg-keys-encrypted-backup-${TIMESTAMP} < ${EXPORT_DIR}/gpg-keys-backup-${TIMESTAMP}.asc"
    return
  fi

  for key in $PRIVATE_KEYS; do
    echo "Exporting keyid $key with private key"
    gpg --armor --export-secret-keys "$key" >> "${EXPORT_DIR}/gpg-keys-backup-${TIMESTAMP}.asc"
    sleep 5
  done
  echo "[private-keys-backup] Here's the encrypted passphrase for ${BACKUP_FILE_PASSWORD}"
  sleep 10
  gpg --armor --batch --passphrase "${BACKUP_FILE_PASSWORD}" --symmetric --output "${EXPORT_DIR}/gpg-keys-encrypted-backup-${TIMESTAMP}" < "${EXPORT_DIR}/gpg-keys-backup-${TIMESTAMP}.asc"
  echo
}

check_export_dir() {
  echo "[Stage 0]: Check if the \$EXPORT_DIR exists and create if necessary"
  echo
  sleep 3
  # dry-run
  if [[ $_arg_dryrun == "true" ]]; then
    echo "+ mkdir $EXPORT_DIR"
    return
  fi

  if [[ ! -d "$EXPORT_DIR" ]]; then
    echo "warning: Directory $EXPORT_DIR doesn't exist, attempting to create dir..."
    if mkdir "$EXPORT_DIR"; then
      true
    else
      error_code=$?
      echo "error: Something gone horribly wrong while creating export directory."
      echo "error: Check the logs, fix perms with chmod/chown/sudo and try again."
      exit $error_code
    fi
  else
    echo "info: export directory exists, contiuning..."
  fi
}

usage() {
  echo "Usage: $0 [--only-public | --only-secret | --dry-run]"
  echo
  echo "Available params:"
  echo "    --dry-run, -d        Run a simultation of commands"
  echo "    --help               Show this help page"
  echo "    --only-secret, -s    Only export secret keys"
  echo "    --only-public, -p    Only export public keys"
  echo
  echo "Supported variables to override defaults:"
  echo "    DEBUG                Set to any value to enable debug logging (via 'set -x')"
  echo "    EXPORT_DIR           Directory for storing exports"
  echo "    PUBLIC_KEYS          List of GPG keys for exporting public keys, seperated by spaces"
  echo "    PRIVATE_KEYS         List of GPG keys for exporting private keys, seperated by spaces"
}

main() {
  if [[ $DEBUG != "" ]]; then
    set -x
  fi

  _arg_pubkeys_only=false
  _arg_secretkeys_only=false
  _arg_dryrun=false
  EXPORT_DIR=${EXPORT_DIR:-"$HOME/.export-toolkit"}

  # arg parser goes here
  for _arg in "${@}"; do {
    if test "$_arg" != "--" && [[ "$_arg" == -* ]]; then {
      case "$_arg" in
        --help | -h)
           usage; exit 0
           ;;
        --pubkeys | --only-public | -p)
           _arg_pubkeys_only=true
           ;;
        --secretkeys | --only-secret | -s)
           _arg_secretkeys_only=true
           ;;
        --dryrun | --dry-run | -d)
           _arg_dryrun=true
           ;;
      esac
      shift;
    } fi
  } done

  check_export_dir
  generate_pubkey_bak
  generate_privkey_bak
}

main "$@"
