Files
coredesktop/configure.d/20-backup.sh
T
2026-10-29 06:36:51 -06:00

187 lines
6.6 KiB
Bash

#!/bin/bash
TITLE="Backup"
DESCRIPTION="Back up your home folder daily to your Nextcloud files"
CORE_CONF="$HOME/.config/coredesktop/core.conf"
BACKUP_CONF="$HOME/.config/coredesktop/backup.conf"
UNITS="$HOME/.config/systemd/user"
source "$COREDESKTOP/configure.d/lib/nextcloud.sh"
[ -f "$CORE_CONF" ] && source "$CORE_CONF"
is_installed() {
command -v restic > /dev/null && command -v rclone > /dev/null && command -v secret-tool > /dev/null
}
backups_on() {
source "$COREDESKTOP/system/backup-env.sh" > /dev/null || return 1
[ -n "$RESTIC_PASSWORD_COMMAND" ] && systemctl --user is-enabled -q coredesktop-backup.timer
}
# Done when backing up to the main Core
is_configured() {
backups_on && [ "$BACKUP_WEBDAV" = "https://nextcloud.$CORE_DOMAIN/remote.php/dav/files/${CORE_EMAIL%@*}" ]
}
save_secret() {
printf '%s' "$3" | secret-tool store --label "CoreDesktop backup $1 ($2)" \
coredesktop backup item "$1" url "$2"
}
# The backup gets its own app password, so revoking it stops only backups
nextcloud_login() {
local tries
[ -n "$(backup_secret nextcloud "$WEBDAV")" ] \
&& rclone lsf --max-depth 1 ":webdav:" > /dev/null 2>&1 && return 0
for tries in 1 2 3; do
read -rsp "Your Core password: " PASSWORD
echo
nextcloud_app_password "CoreDesktop backup on $HOSTNAME"
case $? in
0) break ;;
2) echo "Nextcloud says that password is wrong." ;;
*) echo "Couldn't reach Nextcloud at $NEXTCLOUD."; return 1 ;;
esac
done
unset PASSWORD
[ -n "$APP_PASSWORD" ] || return 1
save_secret nextcloud "$WEBDAV" "$APP_PASSWORD" || return 1
unset APP_PASSWORD
RCLONE_WEBDAV_PASS="$(backup_secret nextcloud "$WEBDAV" | rclone obscure -)"
}
new_passphrase() {
local pass
pass="$(head -c 24 /dev/urandom | base64)"
echo "Your backup is encrypted with this passphrase:"
echo
echo " $pass"
echo
echo "Save it somewhere other than this computer, such as Bitwarden. Without it, the"
echo "backup can't be read if this computer is lost. It's kept in your keyring so the"
echo "daily backup can run."
until confirm "Have you saved it?"; do :; done
save_secret passphrase "$WEBDAV/$BACKUP_DIR" "$pass"
}
# Stop the daily backup and any running now, and remove its units
stop_backups() {
systemctl --user disable --now coredesktop-backup.timer 2> /dev/null
systemctl --user stop coredesktop-backup.service 2> /dev/null
rm -f "$UNITS"/coredesktop-backup.{service,timer}
systemctl --user daemon-reload
}
# Delete the backup from Nextcloud, then what's on this computer for it:
# without the backup, the passphrase and app password are no use
delete_backups() {
local app_password
nextcloud_login || { echo "Couldn't sign in to Nextcloud."; return 1; }
echo "Deleting $BACKUP_DIR from your Nextcloud files..."
rclone purge ":webdav:$BACKUP_DIR" \
|| { echo "rclone couldn't delete $BACKUP_DIR."; return 1; }
echo "Deleted. Nextcloud keeps it in its trash bin, where it still uses space, until you empty it."
app_password="$(backup_secret nextcloud "$WEBDAV")"
[ -n "$app_password" ] && nextcloud_revoke_app_password "$app_password"
secret-tool clear coredesktop backup item nextcloud url "$WEBDAV"
secret-tool clear coredesktop backup item passphrase url "$WEBDAV/$BACKUP_DIR"
rm -f "$BACKUP_CONF"
}
turn_off() {
local answer
WEBDAV="$BACKUP_WEBDAV"
CORE_USER="$BACKUP_USER"
NEXTCLOUD="${BACKUP_WEBDAV%%/remote.php/*}"
stop_backups
echo "Backups are off."
echo
echo "The backups made so far are still in $BACKUP_DIR in your Nextcloud files."
if ! confirm "Delete them? They can't be restored from after that."; then
echo "Kept them. To turn backups back on: configure backup"
return 0
fi
read -rp "To delete them, type the folder name ($BACKUP_DIR): " answer
if [ "$answer" != "$BACKUP_DIR" ]; then
echo "That's not the folder name, so the backups were kept."
return 0
fi
delete_backups
}
run_configure() {
local pass choice
if backups_on &> /dev/null; then
if is_configured &> /dev/null; then
echo "Your home folder is backed up daily to $BACKUP_DIR in your Nextcloud files."
echo
echo " 1) Set it up again"
else
echo "Your home folder is backed up daily to $BACKUP_DIR on ${BACKUP_WEBDAV%%/remote.php/*},"
echo "which isn't your main Core."
echo
echo " 1) Back up to your main Core ($CORE_DOMAIN) instead; the backups so far stay where they are"
fi
echo " 2) Turn backups off"
echo " q) Leave it as it is"
echo
read -rp "Choose: " choice
case "$choice" in
1) ;;
2) turn_off; return ;;
*) return 0 ;;
esac
fi
if [ -z "$CORE_DOMAIN" ] || [ -z "$CORE_EMAIL" ]; then
echo "Backups go to your Nextcloud files, so set up your Core first: configure core"
return 1
fi
CORE_USER="${CORE_EMAIL%@*}"
NEXTCLOUD="https://nextcloud.$CORE_DOMAIN"
WEBDAV="$NEXTCLOUD/remote.php/dav/files/$CORE_USER"
BACKUP_DIR=".backup-$HOSTNAME"
mkdir -p "$(dirname "$BACKUP_CONF")"
{
printf 'BACKUP_WEBDAV=%q\n' "$WEBDAV"
printf 'BACKUP_USER=%q\n' "$CORE_USER"
printf 'BACKUP_DIR=%q\n' "$BACKUP_DIR"
} > "$BACKUP_CONF"
source "$COREDESKTOP/system/backup-env.sh"
nextcloud_login || { echo "Couldn't sign in to Nextcloud."; return 1; }
if rclone lsf --files-only ":webdav:$BACKUP_DIR" 2> /dev/null | grep -qx config; then
# Already there, e.g. after reinstalling: it needs the passphrase from then
if [ -z "$RESTIC_PASSWORD_COMMAND" ] || ! restic cat config &> /dev/null; then
echo "There's already a backup in $BACKUP_DIR in your Nextcloud files."
read -rsp "Its passphrase: " pass
echo
RESTIC_PASSWORD_COMMAND= RESTIC_PASSWORD="$pass" restic cat config > /dev/null \
|| { echo "restic couldn't open it with that passphrase."; return 1; }
save_secret passphrase "$WEBDAV/$BACKUP_DIR" "$pass" || return 1
fi
echo "Using the backup in $BACKUP_DIR."
else
new_passphrase || return 1
source "$COREDESKTOP/system/backup-env.sh"
echo "Creating the backup in $BACKUP_DIR in your Nextcloud files..."
restic init || return 1
fi
mkdir -p "$UNITS"
cp "$COREDESKTOP"/system/systemd/coredesktop-backup.{service,timer} "$UNITS/" || return 1
systemctl --user daemon-reload
systemctl --user enable --now coredesktop-backup.timer || return 1
echo "Your home folder will be backed up daily to $BACKUP_DIR in your Nextcloud files."
if confirm_yes "Start the first backup now? It runs in the background and can take hours."; then
systemctl --user start --no-block coredesktop-backup.service
echo "Started. To follow it: journalctl --user -fu coredesktop-backup"
fi
}