#!/bin/bash
# Create a consistent SQLite backup of the vaultwarden database.
#
# Run as root via a NOPASSWD sudoers rule, because the database lives in a
# root-owned Docker volume. The destination is constrained to the backup
# directory so this grant cannot be used to write a file anywhere else.
#
# Install to /usr/local/sbin/vw-backup-db owned by root, mode 755. The copy
# under scripts/ is the source of truth; do not sudo this one directly, or the
# grant becomes a way to run arbitrary code as root.

set -euo pipefail

DB="/var/lib/docker/volumes/caddy_vaultwarden_data/_data/db.sqlite3"
BACKUP_DIR="/tmp/vaultwarden-backup"
OUT="${1:-}"

if [ -z "$OUT" ]; then
    echo "vw-backup-db: no destination given" >&2
    exit 1
fi

# Only ever write a backup file into the backup directory. This is the
# constraint that makes the sudoers grant safe, so it is checked here too and
# not just in sudoers.
case "$OUT" in
    "${BACKUP_DIR}"/vaultwarden-*.db) ;;
    *)
        echo "vw-backup-db: refusing to write outside ${BACKUP_DIR}: ${OUT}" >&2
        exit 1
        ;;
esac

if [ ! -f "$DB" ]; then
    echo "vw-backup-db: database not found at ${DB}" >&2
    exit 1
fi

mkdir -p "$BACKUP_DIR"
# Remove a stale file so a failed backup cannot be mistaken for a good one.
rm -f "$OUT"

# .backup takes a read lock and produces a consistent snapshot. The database
# runs in WAL mode with an uncheckpointed WAL, so copying the file with cp
# would capture stale data; .backup is required.
if ! /usr/bin/sqlite3 "$DB" ".backup '${OUT}'"; then
    echo "vw-backup-db: sqlite3 .backup failed" >&2
    rm -f "$OUT"
    exit 1
fi

if [ ! -s "$OUT" ]; then
    echo "vw-backup-db: backup file is missing or empty" >&2
    rm -f "$OUT"
    exit 1
fi

# Hand the file back to the calling user so it can be uploaded without sudo.
if [ -n "${SUDO_UID:-}" ] && [ -n "${SUDO_GID:-}" ]; then
    chown "${SUDO_UID}:${SUDO_GID}" "$OUT"
fi

echo "vw-backup-db: wrote ${OUT} ($(stat -c %s "$OUT") bytes)"
