fix backup
This commit is contained in:
+2
-25
@@ -6,6 +6,7 @@ DESCRIPTION="Superpanel, Tailscale, Nextcloud, email, files and Element"
|
||||
# What you entered last time, so running this again only does what's missing
|
||||
CORE_CONF="$HOME/.config/coredesktop/core.conf"
|
||||
GOA_ACCOUNT="$COREDESKTOP/configure.d/lib/goa-account"
|
||||
source "$COREDESKTOP/configure.d/lib/nextcloud.sh"
|
||||
[ -f "$CORE_CONF" ] && source "$CORE_CONF"
|
||||
|
||||
# CORE_DOMAIN, CORE_EMAIL and CORE_NAME come from core.conf; the rest follow
|
||||
@@ -70,30 +71,6 @@ save_conf() {
|
||||
} > "$CORE_CONF"
|
||||
}
|
||||
|
||||
# Basic auth header for curl, read from stdin (-H @-) so the password isn't
|
||||
# in the process list
|
||||
auth_header() {
|
||||
printf 'Authorization: Basic %s\n' "$(printf '%s:%s' "$1" "$2" | base64 -w0)"
|
||||
}
|
||||
|
||||
# Create a Nextcloud app password for the Online Accounts account and the
|
||||
# files mount, so they don't keep your Core password. It shows in Nextcloud
|
||||
# under Settings > Security as "CoreDesktop on <this computer>", where it can
|
||||
# be revoked. Returns 2 if Nextcloud says the password is wrong.
|
||||
nextcloud_app_password() {
|
||||
local response code
|
||||
response="$(auth_header "$CORE_USER" "$PASSWORD" | curl -s -w '\n%{http_code}' -H @- \
|
||||
-H 'OCS-APIRequest: true' -A "CoreDesktop on $HOSTNAME" \
|
||||
"$NEXTCLOUD/ocs/v2.php/core/getapppassword?format=json")"
|
||||
code="${response##*$'\n'}"
|
||||
case "$code" in
|
||||
200) APP_PASSWORD="$(jq -r '.ocs.data.apppassword // empty' <<< "${response%$'\n'*}")"
|
||||
[ -n "$APP_PASSWORD" ] ;;
|
||||
401) return 2 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
desktop_entry() {
|
||||
local file="$1" name="$2" comment="$3" url="$4" icon="$5"
|
||||
mkdir -p "$(dirname "$file")"
|
||||
@@ -332,7 +309,7 @@ run_configure() {
|
||||
for tries in 1 2 3; do
|
||||
read -rsp "Your Core password: " PASSWORD
|
||||
echo
|
||||
nextcloud_app_password
|
||||
nextcloud_app_password "CoreDesktop on $HOSTNAME"
|
||||
case $? in
|
||||
0) break ;;
|
||||
2) echo "Nextcloud says that password is wrong."; PASSWORD="" ;;
|
||||
|
||||
+73
-56
@@ -6,86 +6,103 @@ 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"
|
||||
[ -f "$BACKUP_CONF" ] && source "$BACKUP_CONF"
|
||||
|
||||
is_installed() {
|
||||
command -v borg > /dev/null && command -v secret-tool > /dev/null
|
||||
}
|
||||
|
||||
# The passphrase is in the keyring under the repository's path, so the
|
||||
# backup can run without asking
|
||||
passphrase() {
|
||||
secret-tool lookup coredesktop backup repo "$1"
|
||||
command -v restic > /dev/null && command -v rclone > /dev/null && command -v secret-tool > /dev/null
|
||||
}
|
||||
|
||||
is_configured() {
|
||||
[ -n "$BORG_REPO" ] && [ -n "$(passphrase "$BORG_REPO")" ] \
|
||||
&& systemctl --user is-enabled -q coredesktop-backup.timer
|
||||
source "$COREDESKTOP/system/backup-env.sh" > /dev/null || return 1
|
||||
[ -n "$RESTIC_PASSWORD_COMMAND" ] && systemctl --user is-enabled -q coredesktop-backup.timer
|
||||
}
|
||||
|
||||
# system/backup uses borg 1.2 to 1.4; borg 2 changed its commands
|
||||
borg_supported() {
|
||||
local version
|
||||
version="$(borg --version | awk '{print $2}')"
|
||||
[[ "$version" =~ ^1\.([2-9]|[1-9][0-9])\. ]] && return 0
|
||||
echo "This needs borg 1.2 to 1.4, and borg $version is installed."
|
||||
return 1
|
||||
save_secret() {
|
||||
printf '%s' "$3" | secret-tool store --label "CoreDesktop backup $1 ($2)" \
|
||||
coredesktop backup item "$1" url "$2"
|
||||
}
|
||||
|
||||
save_passphrase() {
|
||||
printf '%s' "$2" | secret-tool store --label "CoreDesktop backup ($1)" coredesktop backup repo "$1"
|
||||
# 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 mount="/mnt/$CORE_DOMAIN" repo pass
|
||||
borg_supported || return 1
|
||||
if [ -z "$CORE_DOMAIN" ] || ! mountpoint -q "$mount"; then
|
||||
echo "Backups go to your Nextcloud files, so set those up first (configure core), and check they're mounted."
|
||||
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
|
||||
repo="$mount/.backup-$HOSTNAME"
|
||||
|
||||
if [ -f "$repo/config" ]; then
|
||||
# Already there, e.g. after reinstalling: it needs the passphrase from then
|
||||
pass="$(passphrase "$repo")"
|
||||
if [ -z "$pass" ] || ! BORG_PASSPHRASE="$pass" borg info "$repo" &> /dev/null; then
|
||||
echo "There's already a backup at $repo."
|
||||
read -rsp "Its passphrase: " pass
|
||||
echo
|
||||
BORG_PASSPHRASE="$pass" borg info "$repo" > /dev/null || { echo "borg couldn't open it with that passphrase."; return 1; }
|
||||
save_passphrase "$repo" "$pass" || return 1
|
||||
fi
|
||||
echo "Using the backup at $repo."
|
||||
else
|
||||
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_passphrase "$repo" "$pass" || return 1
|
||||
echo "Creating the backup at $repo..."
|
||||
BORG_PASSPHRASE="$pass" borg init --encryption=repokey-blake2 "$repo" || return 1
|
||||
# davfs2 copies each file to a local cache before uploading it, and some
|
||||
# servers refuse large uploads, so keep borg's files to 50 MB, not 500
|
||||
BORG_PASSPHRASE="$pass" borg config "$repo" max_segment_size 52428800 || 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 'BORG_REPO=%q\n' "$repo"
|
||||
printf 'BACKUP_MOUNT=%q\n' "$mount"
|
||||
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 $repo."
|
||||
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
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Purpose : Nextcloud app passwords for configure.d items. Source this file.
|
||||
|
||||
# Basic auth header for curl, read from stdin (-H @-) so the password isn't
|
||||
# in the process list
|
||||
auth_header() {
|
||||
printf 'Authorization: Basic %s\n' "$(printf '%s:%s' "$1" "$2" | base64 -w0)"
|
||||
}
|
||||
|
||||
# Create a Nextcloud app password, so what CoreDesktop sets up doesn't keep
|
||||
# your Core password. It shows in Nextcloud under Settings > Security with the
|
||||
# name given, where it can be revoked. Uses CORE_USER, PASSWORD and NEXTCLOUD;
|
||||
# sets APP_PASSWORD. Returns 2 if Nextcloud says the password is wrong.
|
||||
nextcloud_app_password() {
|
||||
local name="$1" response code
|
||||
response="$(auth_header "$CORE_USER" "$PASSWORD" | curl -s -w '\n%{http_code}' -H @- \
|
||||
-H 'OCS-APIRequest: true' -A "$name" \
|
||||
"$NEXTCLOUD/ocs/v2.php/core/getapppassword?format=json")"
|
||||
code="${response##*$'\n'}"
|
||||
case "$code" in
|
||||
200) APP_PASSWORD="$(jq -r '.ocs.data.apppassword // empty' <<< "${response%$'\n'*}")"
|
||||
[ -n "$APP_PASSWORD" ] ;;
|
||||
401) return 2 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
Reference in New Issue
Block a user