#!/usr/bin/env bash
#/ Usage: ghe-detect-leaked-ssh-key [-s <snapshot-id>]
#/
#/ This utility will check each snapshot's existing SSH host keys against the list
#/ of known leaked SSH host keys from GitHub Enterprise packages.
#/
#/ OPTIONS:
#/   -h | --help                    Show this message.
#/   -s |--snapshot <snapshot-id>   Scan the snapshot with the given id.
#/                                  Available snapshots may be listed under the data directory.
#/
set -e

usage() {
  grep '^#/' < "$0" | cut -c 4-
  exit 2
}

TEMPDIR=$(mktemp -d)

while [ $# -gt 0 ]; do
  case "$1" in
    -h|--help)
      usage
      ;;
    -s|--snapshot)
      snapshot=$2
      shift
      ;;
    *)
      usage
      ;;
  esac
  shift
done

ppid_script=$(ps -o args= $PPID 2>/dev/null | awk '{print $2}')
if [ -n "$ppid_script" ]; then
  ppid_name=$(basename $ppid_script)
fi

sshkeygen_multiple_hash_formats=false
if (ssh-keygen -E 2>&1 | head -1 |  grep -q 'option requires an argument'); then
  sshkeygen_multiple_hash_formats=true
fi

# Bring in the backup configuration
# shellcheck source=share/github-backup-utils/ghe-backup-config
. "$( dirname "${BASH_SOURCE[0]}" )/ghe-backup-config"

FINGERPRINT_BLACKLIST="${FINGERPRINT_BLACKLIST:-$(cat "$GHE_BACKUP_ROOT/share/github-backup-utils/ghe-ssh-leaked-host-keys-list.txt")}"

keys="ssh_host_dsa_key.pub ssh_host_ecdsa_key.pub ssh_host_ed25519_key.pub ssh_host_rsa_key.pub"

# Get all the host ssh keys tar from all snapshots directories
if [ -n "$snapshot" ]; then
  if [ ! -d "$snapshot" ]; then
    echo "Invalid snapshot directory: $snapshot" >&2
    exit 1
  fi
  ssh_tars=$(find "$snapshot" -maxdepth 1 -type f -iname 'ssh-host-keys.tar')
else
  ssh_tars=$(find "$GHE_DATA_DIR" -maxdepth 2 -type f -iname 'ssh-host-keys.tar')
fi

# Store the current backup snapshot folder
if [ -L "$GHE_DATA_DIR/current" ]; then
  current_dir=$(cd "$GHE_DATA_DIR/current"; pwd -P)
fi

leaked_keys_found=false
leaked_keys_skippedcheck=false
current_bkup=false
for tar_file in $ssh_tars; do
  for key in $keys; do
    if tar -tvf "$tar_file" $key &>/dev/null; then
      tar -C $TEMPDIR -xvf "$tar_file" $key &>/dev/null
      if $sshkeygen_multiple_hash_formats; then
        fingerprint=$(ssh-keygen -l -E md5 -f $TEMPDIR/$key | cut -d ' ' -f 2 | cut -f2- -d':')
      else
        fingerprint=$(ssh-keygen -lf $TEMPDIR/$key | cut -d ' ' -f 2)
      fi
      if [ -z "$fingerprint" ]; then
        leaked_keys_skippedcheck=true
      elif echo "$FINGERPRINT_BLACKLIST" | grep -q "$fingerprint"; then
        leaked_keys_found=true
        if [ "$current_dir" == "$(dirname "$tar_file")" ]; then
          current_bkup=true
          log_warn "* Leaked key found in current backup snapshot."
        else
          log_warn "* Leaked key found in backup snapshot."
        fi
        echo "* Snapshot file: $tar_file"
        echo "* Key file: $key"
        echo "* Key: $fingerprint"
        echo
      fi
    fi
  done
done

if $leaked_keys_found; then
  if  echo "$ppid_name" | grep -q 'ghe-restore'; then
    echo
    echo "* The snapshot that is being restored contains a leaked SSH host key."
    echo "* We recommend rolling the SSH host keys after completing the restore."
    echo "* Roll the keys either manually or with ghe-ssh-roll-host-keys on the appliance."
    echo "* (An upgrade may be required)"
    echo
  elif echo "$ppid_name" | grep -q 'ghe-backup'; then
    echo "* The current backup contains leaked SSH host keys."
    echo "* We strongly recommend rolling your SSH host keys and making a new backup."
    echo "* Roll the keys either manually or with ghe-ssh-roll-host-keys on the appliance."
    echo "* (An upgrade may be required)"
  else
    if $current_bkup; then
      echo "* The current backup contains leaked SSH host keys."
      echo "* Current backup directory: $current_dir"
      echo "* We strongly recommend rolling your SSH host keys and making a new backup."
      echo "* Roll the keys either manually or with ghe-ssh-roll-host-keys on the appliance."
      echo "* (An upgrade may be required)"
    fi
    echo
    echo "* One or more older backup snapshots contain leaked SSH host keys."
    echo "* No immediate action is needed but when you use one of these older snapshots for a restore, "
    echo "* please make sure to roll the SSH host keys after restore."
    echo "* Roll the keys either manually or with ghe-ssh-roll-host-keys on the appliance."
    echo "* (An upgrade may be required)"
    echo
  fi
else
  if $leaked_keys_skippedcheck; then
    log_info "* No result - check not performed since host key fingerprint was empty"
  else
    log_info "* No leaked keys found"
  fi
fi

# Cleanup temp dir
rm -rf $TEMPDIR
