Add FileFlows ApiKey guard against [REDACTED] key corruption
Die FileFlows-API liefert ApiKey-Felder im GET als [REDACTED]. Ein Save aus der Web-UI (oder GET->PUT-Roundtrip) schreibt diesen Platzhalter in die DB, wodurch alle vier Arr-Manual-Import-Nodes still mit 401 fehlschlagen. Der n8n-Handoff bleibt auf processing, movetdarr.sh pollt weiter und der SAB-Job haengt bis zum 24h-Timeout in der Queue. Negativtest bestaetigt: ein sabotierter Key korrumpiert alle vier, weil der GET alle vier als [REDACTED] ausliefert. Guard prueft die FileFlows-SQLite auf ApiKeys != 32 Zeichen und schreibt die echten Keys via Butler-Proxy zurueck. Laeuft als systemd-Timer alle 15min auf tdarr (cron dort inaktiv).
This commit is contained in:
parent
bb90021adc
commit
18e123bdb2
2 changed files with 192 additions and 0 deletions
105
fileflows/guard/ff-apikey-guard.sh
Executable file
105
fileflows/guard/ff-apikey-guard.sh
Executable file
|
|
@ -0,0 +1,105 @@
|
|||
#!/bin/bash
|
||||
# ff-apikey-guard.sh — repariert kaputte Arr-ApiKeys in FileFlows-Flows
|
||||
#
|
||||
# URSACHE: Die FileFlows-API liefert ApiKey-Felder im GET als "[REDACTED]".
|
||||
# Wird ein Flow aus der Web-UI (oder per GET->PUT-Roundtrip) gespeichert,
|
||||
# landet dieser Platzhalter in der DB. Die "Trigger Manual Import"-Nodes
|
||||
# schlagen dann still fehl (Arr antwortet 401), der n8n-Handoff bleibt auf
|
||||
# "processing" und der SAB-Job haengt bis zum 24h-Timeout in der Queue.
|
||||
#
|
||||
# Dieses Skript erkennt ApiKeys != 32 Zeichen und schreibt die echten Keys
|
||||
# aus /app-config/ff-guard/arr-keys.map zurueck (Format: "<port> <key>").
|
||||
set -u
|
||||
|
||||
BUTLER="${BUTLER:-http://10.5.85.2:8888}"
|
||||
GUARD_DIR="${GUARD_DIR:-/app-config/ff-guard}"
|
||||
TOKEN_FILE="$GUARD_DIR/butler.token"
|
||||
KEYMAP="$GUARD_DIR/arr-keys.map"
|
||||
LOG="$GUARD_DIR/guard.log"
|
||||
DB="${DB:-/app-config/fileflows-data/Data/FileFlows.sqlite}"
|
||||
|
||||
mkdir -p "$GUARD_DIR"
|
||||
log() { echo "$(date '+%d.%m.%Y %H:%M:%S'): $1" >> "$LOG"; }
|
||||
|
||||
for f in "$TOKEN_FILE" "$KEYMAP"; do
|
||||
[ -r "$f" ] || { log "FEHLER: Datei fehlt oder nicht lesbar: $f"; exit 1; }
|
||||
done
|
||||
[ -r "$DB" ] || { log "FEHLER: DB nicht lesbar: $DB"; exit 1; }
|
||||
|
||||
TOKEN="$(tr -d '\n\r' < "$TOKEN_FILE")"
|
||||
|
||||
# Flows mit defekten Keys ermitteln
|
||||
FLOWUIDS="$(python3 - "$DB" <<'PY'
|
||||
import sqlite3, json, sys
|
||||
con = sqlite3.connect("file:%s?mode=ro" % sys.argv[1], uri=True)
|
||||
for uid, name, typ, d in con.execute(
|
||||
"select Uid,Name,Type,Data from DbObject where Type like '%Flow%'"):
|
||||
try:
|
||||
o = json.loads(d)
|
||||
except Exception:
|
||||
continue
|
||||
for p in o.get("Parts", []):
|
||||
k = (p.get("Model") or {}).get("ApiKey")
|
||||
if k is not None and len(str(k)) != 32:
|
||||
print(uid)
|
||||
break
|
||||
PY
|
||||
)"
|
||||
|
||||
if [ -z "$FLOWUIDS" ]; then
|
||||
log "OK: alle Flow-ApiKeys 32 Zeichen"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RC=0
|
||||
for uid in $FLOWUIDS; do
|
||||
log "WARNUNG: defekte ApiKeys in Flow $uid — repariere"
|
||||
OUT="$(mktemp)"; PATCHED="$(mktemp)"
|
||||
|
||||
if ! curl -sf -m 60 -H "Authorization: Bearer $TOKEN" \
|
||||
"$BUTLER/fileflows/api/flow/$uid" -o "$OUT"; then
|
||||
log "FEHLER: GET flow $uid fehlgeschlagen"
|
||||
rm -f "$OUT" "$PATCHED"; RC=1; continue
|
||||
fi
|
||||
|
||||
CHANGED="$(python3 - "$OUT" "$KEYMAP" "$PATCHED" <<'PY'
|
||||
import json, sys
|
||||
flow = json.load(open(sys.argv[1]))
|
||||
keys = {}
|
||||
for line in open(sys.argv[2]):
|
||||
parts = line.split()
|
||||
if len(parts) == 2 and len(parts[1]) == 32:
|
||||
keys[parts[0]] = parts[1]
|
||||
n = 0
|
||||
for p in flow.get("Parts", []):
|
||||
mod = p.get("Model") or {}
|
||||
if "ApiKey" not in mod:
|
||||
continue
|
||||
url = str(mod.get("URL") or mod.get("ApiUrl") or "")
|
||||
port = url.rstrip("/").rsplit(":", 1)[-1]
|
||||
if port in keys and str(mod["ApiKey"]) != keys[port]:
|
||||
mod["ApiKey"] = keys[port]
|
||||
n += 1
|
||||
json.dump(flow, open(sys.argv[3], "w"))
|
||||
print(n)
|
||||
PY
|
||||
)"
|
||||
|
||||
if [ "${CHANGED:-0}" = "0" ]; then
|
||||
log "WARNUNG: Flow $uid — kein Key konnte gemappt werden (Ports pruefen)"
|
||||
rm -f "$OUT" "$PATCHED"; RC=1; continue
|
||||
fi
|
||||
|
||||
HTTP="$(curl -s -m 60 -o /dev/null -w '%{http_code}' -X PUT \
|
||||
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
|
||||
"$BUTLER/fileflows/api/flow" --data @"$PATCHED")"
|
||||
|
||||
if [ "$HTTP" = "200" ]; then
|
||||
log "Flow $uid repariert: $CHANGED Key(s) zurueckgeschrieben (HTTP 200)"
|
||||
else
|
||||
log "FEHLER: PUT flow $uid -> HTTP $HTTP"
|
||||
RC=1
|
||||
fi
|
||||
rm -f "$OUT" "$PATCHED"
|
||||
done
|
||||
exit $RC
|
||||
Loading…
Add table
Add a link
Reference in a new issue