Files
coredesktop/configure.d/20-backup.sh
T
2026-10-26 16:21:27 -06:00

112 lines
4.0 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
}
is_configured() {
source "$COREDESKTOP/system/backup-env.sh" > /dev/null || return 1
[ -n "$RESTIC_PASSWORD_COMMAND" ] && systemctl --user is-enabled -q coredesktop-backup.timer
}
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"
}
run_configure() {
local pass
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
}