#!/usr/bin/env bash
# vaultwarden-backup.sh — consistent, verifiable backup of a Vaultwarden data dir.
# Usage: ./vaultwarden-backup.sh /path/to/vaultwarden/data /path/to/backups
# Safe while the container is running: the database is copied through SQLite's
# online backup API, not with cp, so the -wal file's contents are included.
set -euo pipefail

DATA=${1:?usage: vaultwarden-backup.sh DATA_DIR BACKUP_ROOT}
ROOT=${2:?usage: vaultwarden-backup.sh DATA_DIR BACKUP_ROOT}
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
DEST="$ROOT/vaultwarden-$STAMP"

mkdir -p "$DEST"

# 1. Database: one consistent file, WAL included.
python3 - "$DATA/db.sqlite3" "$DEST/db.sqlite3" <<'PY'
import sqlite3, sys
src = sqlite3.connect("file:" + sys.argv[1] + "?mode=ro", uri=True)
dst = sqlite3.connect(sys.argv[2])
src.backup(dst)
dst.close()
src.close()
PY

# 2. Attachment blobs live outside the database.
if [ -d "$DATA/attachments" ]; then
  cp -a "$DATA/attachments" "$DEST/attachments"
fi

# 3. The signing key. Without it the restored server mints a new one and
#    every existing client session is logged out.
cp -a "$DATA/rsa_key.pem" "$DEST/rsa_key.pem"

# 4. Anything else the instance keeps beside the database.
for f in sends config.json; do
  if [ -e "$DATA/$f" ]; then cp -a "$DATA/$f" "$DEST/"; fi
done

# 5. Prove the copy before calling it a backup.
python3 - "$DEST/db.sqlite3" <<'PY'
import sqlite3, sys
p = sys.argv[1]
c = sqlite3.connect("file:" + p + "?mode=ro", uri=True)
integrity = c.execute("pragma integrity_check").fetchone()[0]
if integrity != "ok":
    raise SystemExit("integrity_check failed: " + integrity)
counts = {t: c.execute("select count(*) from " + t).fetchone()[0]
          for t in ("users", "ciphers", "folders", "attachments", "devices")}
if counts["users"] == 0:
    raise SystemExit("backup contains no users: the database copy is empty")
print("integrity ok; " + " ".join(k + "=" + str(v) for k, v in counts.items()))
PY

( cd "$DEST" && find . -type f -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS )
tar -C "$DEST" -czf "$DEST.tar.gz" .
rm -rf "$DEST"

echo "backup written: $DEST.tar.gz ($(stat -c %s "$DEST.tar.gz") bytes)"
