92a5d50082
- 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>
165 lines
5.2 KiB
Bash
Executable File
165 lines
5.2 KiB
Bash
Executable File
#!/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
|