Files
darktable-sync/scripts/darktable_sync.sh
T
martin 92a5d50082 Sicherheitshaertung: Injection-Schutz, atomares Locking, Pfad-Validierung
- load_config blockiert Shell-Operatoren (;|&`) in .env-Werten
- validate_path prueft Sonderzeichen und Path-Traversal in Pfad-Variablen
- validate_config prüft DARKTABLE_BIN-basename und ruft validate_path auf
- Lockdir-Trap erst nach erfolgreicher Lock-Akquisition registriert
  (verhindert dass externer Lockdir bei gescheitertem Lock entfernt wird)
- uninstall.sh nutzt rmdir statt rm -rf fuer Lockdir
- security.bats mit 10 Tests fuer alle Sicherheitsanforderungen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 19:57:39 +02:00

165 lines
5.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=darktable_common.sh
source "$SCRIPT_DIR/darktable_common.sh"
check_dependency rsync
check_dependency ssh openssh-client
check_dependency notify-send libnotify-bin
check_dependency darktable
load_config
validate_config
export DISPLAY="${DISPLAY:-:0}"
count_synced_files() {
local log_file="$1" direction="$2" count=0
case "$direction" in
up) count=$(grep -cE '^>f|^cd' "$log_file" 2>/dev/null) || count=0 ;;
down) count=$(grep -cE '^<f|^cd' "$log_file" 2>/dev/null) || count=0 ;;
esac
echo "$count"
}
LOCKDIR="$CONFIG_DIR/sync.lock"
TMPFILES=()
# Atomares Locking per mkdir (verhindert Race Condition und Symlink-Attacken)
if ! mkdir "$LOCKDIR" 2>/dev/null; then
echo "Script laeuft bereits oder Lockdir loeschen: $LOCKDIR"
exit 1
fi
trap 'rm -f "${TMPFILES[@]}"; rmdir "$LOCKDIR" 2>/dev/null || true' EXIT
SHOW_NOTIFY_START_STOP=false
if [[ "${1:-}" == "--with-notify-start-stop" ]]; then
SHOW_NOTIFY_START_STOP=true
fi
if [ -f "$CONFIG_DIR/sync_pending" ]; then
notify-send "Darktable Sync" "Ausstehender Sync wird jetzt ausgefuehrt..." -t 3000
fi
if ! server_reachable; then
log "Server nicht erreichbar Sync uebersprungen."
touch "$CONFIG_DIR/sync_pending"
exit 0
fi
if [ "$SHOW_NOTIFY_START_STOP" = true ]; then
notify-send "Darktable Sync" "Sync gestartet..." -t 3000
fi
ACTIVE=$(ssh_server "cat '$SERVER_DB_DIR/darktable.active' 2>/dev/null || true")
if [ -n "$ACTIVE" ]; then
notify-send "Darktable Sync Warnung" \
"Darktable laueft moeglicherweise auf: $ACTIVE" -u normal -t 10000
fi
SERVER_VERSION=$(ssh_server "cat '$SERVER_DB_DIR/darktable_version' 2>/dev/null || true")
LOCAL_VERSION=$(darktable --version 2>&1 | head -1)
if [ -n "$SERVER_VERSION" ]; then
LOCAL_MM=$(echo "$LOCAL_VERSION" | grep -oP '\d+\.\d+' | head -1 || true)
SERVER_MM=$(echo "$SERVER_VERSION" | grep -oP '\d+\.\d+' | head -1 || true)
if [ -n "$SERVER_MM" ] && [ "$LOCAL_MM" != "$SERVER_MM" ]; then
log "WARNUNG: Darktable-Versionen unterschiedlich!"
log " Lokal: $LOCAL_VERSION"
log " Server: $SERVER_VERSION"
log " Bitte beide Rechner auf gleichen Stand bringen."
notify-send "Darktable Sync Versionskonflikt" \
"Lokal: $LOCAL_MM Server: $SERVER_MM\nBitte angleichen!" \
-u critical
touch "$CONFIG_DIR/sync_pending"
exit 1
fi
fi
log "Datenbank-Backup erstellen..."
cp "$LOCAL_DARKTABLE_DB_DIR/library.db" "$LOCAL_DARKTABLE_DB_DIR/library.db.bak"
cp "$LOCAL_DARKTABLE_DB_DIR/data.db" "$LOCAL_DARKTABLE_DB_DIR/data.db.bak"
SYNC_LOG=$(mktemp)
TMPFILES+=("$SYNC_LOG")
log "Datenbank hochladen..."
UPLOAD_LOG_DB=$(mktemp)
TMPFILES+=("$UPLOAD_LOG_DB")
if ! rsync -uavh --itemize-changes \
--exclude '*.lock' \
--exclude 'darktable_version' \
-e "ssh -p $SERVER_SSH_PORT" \
"$LOCAL_DARKTABLE_DB_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" \
2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_DB"; then
log "Fehler beim Hochladen der Datenbank."
touch "$CONFIG_DIR/sync_pending"
exit 1
fi
SENT_DB=$(count_synced_files "$UPLOAD_LOG_DB" "up")
log "Fotos hochladen..."
UPLOAD_LOG_PHOTOS=$(mktemp)
TMPFILES+=("$UPLOAD_LOG_PHOTOS")
if ! rsync -uavh --itemize-changes \
--exclude '*.lock' \
-e "ssh -p $SERVER_SSH_PORT" \
"$LOCAL_PHOTO_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" \
2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_PHOTOS"; then
log "Fehler beim Hochladen der Fotos."
touch "$CONFIG_DIR/sync_pending"
exit 1
fi
SENT_PHOTOS=$(count_synced_files "$UPLOAD_LOG_PHOTOS" "up")
log "Datenbank herunterladen..."
DOWNLOAD_LOG_DB=$(mktemp)
TMPFILES+=("$DOWNLOAD_LOG_DB")
if ! rsync -uavh --itemize-changes \
--exclude '*.lock' \
-e "ssh -p $SERVER_SSH_PORT" \
"$SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" "$LOCAL_DARKTABLE_DB_DIR/" \
2>&1 | tee -a "$SYNC_LOG" "$DOWNLOAD_LOG_DB"; then
log "Fehler beim Herunterladen der Datenbank."
touch "$CONFIG_DIR/sync_pending"
exit 1
fi
RECEIVED_DB=$(count_synced_files "$DOWNLOAD_LOG_DB" "down")
log "Fotos herunterladen..."
DOWNLOAD_LOG_PHOTOS=$(mktemp)
TMPFILES+=("$DOWNLOAD_LOG_PHOTOS")
if ! rsync -uavh --itemize-changes \
--exclude '*.lock' \
-e "ssh -p $SERVER_SSH_PORT" \
"$SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" "$LOCAL_PHOTO_DIR/" \
2>&1 | tee -a "$SYNC_LOG" "$DOWNLOAD_LOG_PHOTOS"; then
log "Fehler beim Herunterladen der Fotos."
touch "$CONFIG_DIR/sync_pending"
exit 1
fi
RECEIVED_PHOTOS=$(count_synced_files "$DOWNLOAD_LOG_PHOTOS" "down")
echo "$LOCAL_VERSION" > "$LOCAL_DARKTABLE_DB_DIR/darktable_version"
rm -f "$CONFIG_DIR/sync_pending"
TOTAL_SENT=$((SENT_DB + SENT_PHOTOS))
TOTAL_RECEIVED=$((RECEIVED_DB + RECEIVED_PHOTOS))
if [ "$TOTAL_SENT" -gt 0 ] || [ "$TOTAL_RECEIVED" -gt 0 ]; then
log "Hochgeladen: $TOTAL_SENT Dateien"
log "Heruntergeladen: $TOTAL_RECEIVED Dateien"
notify-send "Darktable Sync" \
"$TOTAL_SENT hochgeladen | ↓ $TOTAL_RECEIVED heruntergeladen" -t 10000
else
log "Keine Aenderungen."
fi
if [ "$SHOW_NOTIFY_START_STOP" = true ]; then
notify-send "Darktable Sync" "Sync abgeschlossen." -t 3000
fi