You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

125 lines
3.7 KiB

#!/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}"
umbrel_seed=$(cat "${UMBREL_ROOT}/db/umbrel-seed/seed") || true
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..."
if [[ ! -f "${UMBREL_ROOT}/lnd/data/chain/bitcoin/${BITCOIN_NETWORK}/channel.backup" ]]; then
echo "No channel.backup file found, skipping backup..."
exit 1
fi
mkdir -p "${BACKUP_FOLDER_PATH}"
cp --archive "${UMBREL_ROOT}/lnd/data/chain/bitcoin/${BITCOIN_NETWORK}/channel.backup" "${BACKUP_FOLDER_PATH}/channel.backup"
# 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