mirror of https://github.com/lukechilds/umbrel.git
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
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
|
|
|