#!/usr/bin/env bash

set -euo pipefail

UMBREL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/../..)"
BACKUP_ROOT="${UMBREL_ROOT}/.backup/$RANDOM"
BACKUP_FOLDER_NAME="backup"
BACKUP_FOLDER_PATH="${BACKUP_ROOT}/${BACKUP_FOLDER_NAME}"
BACKUP_FILE="${BACKUP_ROOT}/backup.tar.gz.pgp"
BACKUP_STATUS_FILE="${UMBREL_ROOT}/statuses/backup-status.json"

check_dependencies () {
  for cmd in "$@"; do
    if ! command -v "$cmd" >/dev/null 2>&1; then
      echo "This script requires \"${cmd}\" to be installed"
      exit 1
    fi
  done
}

check_dependencies openssl tar gpg shuf curl

# Deterministically derives 128 bits of cryptographically secure entropy
derive_entropy () {
  identifier="${1}"

  # Attempt to get new app seed
  {
    seed_length=$(jq -r '.seed | length' "${UMBREL_ROOT}/app-data/lightning/data/lightning/state.json")
    if [[ "${seed_length}" = "24" ]]; then
      umbrel_seed=$(jq -r '.seed | join(" ")' "${UMBREL_ROOT}/app-data/lightning/data/lightning/state.json")
    else
      umbrel_seed=""
    fi
  } 2>/dev/null || true

  # Else fall back to umbrel seed
  if [[ -z "$umbrel_seed" ]]; then
    umbrel_seed=$(cat "${UMBREL_ROOT}/db/umbrel-seed/seed" 2>/dev/null) || true
  fi

  if [[ -z "$umbrel_seed" ]] || [[ -z "$identifier" ]]; then
    >&2 echo "Missing derivation parameter, this is unsafe, exiting."
    exit 1
  fi

  # We need `sed 's/^.* //'` to trim the "(stdin)= " prefix from some versions of openssl
  printf "%s" "${identifier}" | openssl dgst -sha256 -hmac "${umbrel_seed}" | sed 's/^.* //'
}

[[ -f "${UMBREL_ROOT}/.env" ]] && source "${UMBREL_ROOT}/.env"
BITCOIN_NETWORK=${BITCOIN_NETWORK:-mainnet}

echo "Deriving keys..."

backup_id=$(derive_entropy "umbrel_backup_id")
encryption_key=$(derive_entropy "umbrel_backup_encryption_key")

echo "Creating backup..."

mkdir -p "${BACKUP_FOLDER_PATH}"

CHANNEL_BACKUP_FILE="${UMBREL_ROOT}/app-data/lightning/data/lnd/data/chain/bitcoin/${BITCOIN_NETWORK}/channel.backup"

if [[ -f "${CHANNEL_BACKUP_FILE}" ]]; then
  cp --archive "${CHANNEL_BACKUP_FILE}" "${BACKUP_FOLDER_PATH}/channel.backup"
fi

# We want to back up user settings too, however we currently store the encrypted
# mnemonic in this file which is not safe to backup remotely.
# Uncomment this in the future once we've ensured there's no critical data in
# this file.
# cp --archive "${UMBREL_ROOT}/db/user.json" "${BACKUP_FOLDER_PATH}/user.json"

echo "Adding random padding..."

# Up to 10KB of random binary data
# This prevents the server from being able to tell if the backup has increased
# decreased or stayed the sme size. Combined with random interval decoy backups
# this makes a (already very difficult) timing analysis attack to correlate backup
# activity with channel state changes practically impossible.
padding="$(shuf -i 0-10240 -n 1)"
dd if=/dev/urandom bs="${padding}" count=1 > "${BACKUP_FOLDER_PATH}/.padding"

echo "Creating encrypted tarball..."

tar \
  --create \
  --gzip \
  --verbose \
  --directory "${BACKUP_FOLDER_PATH}/.." \
  "${BACKUP_FOLDER_NAME}" \
  | gpg \
  --batch \
  --symmetric \
  --cipher-algo AES256 \
  --passphrase "${encryption_key}" \
  --output "${BACKUP_FILE}"

# To decrypt:
# cat "${BACKUP_FILE}" | gpg \
#   --batch \
#   --decrypt \
#   --passphrase "${encryption_key}" \
#   | tar \
#   --extract \
#   --verbose \
#   --gzip

BACKUP_API_URL="https://pvf3ozmmfl.execute-api.us-east-1.amazonaws.com/prod/v1/upload"

if [[ $BITCOIN_NETWORK == "testnet" ]]; then
    BACKUP_API_URL="https://as0ot0lg7h.execute-api.us-east-1.amazonaws.com/dev/v1/upload"
fi
if [[ $BITCOIN_NETWORK == "regtest" ]]; then
    BACKUP_API_URL="https://5fxwqbum7g.execute-api.us-east-1.amazonaws.com/dev/v1/upload"
fi

echo "Uploading backup..."
if curl --socks5 "localhost:${TOR_PROXY_PORT}" -F "file=@/${BACKUP_FILE}" "${BACKUP_API_URL}/${backup_id}"; then
  status="success"
else
  status="failed"
fi
echo

rm -rf "${BACKUP_ROOT}"

# Update status file
cat <<EOF > ${BACKUP_STATUS_FILE}
{"status": "${status}", "timestamp": $(date +%s000)}
EOF

echo "============================="
echo "====== Backup ${status} ======="
echo "============================="

exit 0
