After batch 2 SSO, Sonarr/Radarr hitting nzbget.ginnoir.com got 302 from Caddy instead of NZBGet JSON-RPC.
182 lines
5.7 KiB
Bash
182 lines
5.7 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# TB-006 batch 2: disable local auth; Servarr -> External; skip tautulli.
|
|
# Run on valhalla as ginnoir.
|
|
|
|
set_servarr_external() {
|
|
local app="$1"
|
|
local cfg="/config/${app}/config.xml"
|
|
if [[ ! -f "$cfg" ]]; then
|
|
echo "SKIP ${app}: no ${cfg}"
|
|
return 0
|
|
fi
|
|
echo "=== ${app}: set External ==="
|
|
docker stop "$app" >/dev/null
|
|
python3 - "$cfg" <<'PY'
|
|
import sys
|
|
import xml.etree.ElementTree as ET
|
|
|
|
path = sys.argv[1]
|
|
tree = ET.parse(path)
|
|
root = tree.getroot()
|
|
|
|
auth_required = None
|
|
for el in list(root):
|
|
if el.tag == "AuthenticationRequired" and el.text:
|
|
auth_required = el.text.strip()
|
|
break
|
|
|
|
for el in list(root):
|
|
if el.tag in ("AuthenticationMethod", "AuthenticationRequired"):
|
|
root.remove(el)
|
|
|
|
ext = ET.SubElement(root, "AuthenticationMethod")
|
|
ext.text = "External"
|
|
req = ET.SubElement(root, "AuthenticationRequired")
|
|
req.text = auth_required or "Enabled"
|
|
|
|
tree.write(path, encoding="UTF-8", xml_declaration=True)
|
|
print(f" wrote External (AuthenticationRequired={req.text})")
|
|
PY
|
|
docker start "$app" >/dev/null
|
|
grep Authentication "$cfg"
|
|
}
|
|
|
|
for app in sonarr radarr prowlarr whisparr; do
|
|
set_servarr_external "$app"
|
|
done
|
|
|
|
echo "=== bazarr: verify auth disabled ==="
|
|
python3 - <<'PY'
|
|
import yaml
|
|
path = "/config/bazarr/config/config.yaml"
|
|
with open(path) as f:
|
|
d = yaml.safe_load(f)
|
|
auth = d.setdefault("auth", {})
|
|
changed = False
|
|
if auth.get("type") is not None:
|
|
auth["type"] = None
|
|
changed = True
|
|
if auth.get("username"):
|
|
auth["username"] = ""
|
|
changed = True
|
|
if auth.get("password"):
|
|
auth["password"] = ""
|
|
changed = True
|
|
if changed:
|
|
with open(path, "w") as f:
|
|
yaml.safe_dump(d, f, default_flow_style=False, sort_keys=False)
|
|
print(" updated bazarr auth -> type null")
|
|
else:
|
|
print(" already type null / no credentials")
|
|
PY
|
|
docker restart bazarr >/dev/null
|
|
|
|
echo "=== qbittorrent: disable WebUI auth (keep API key for *arr) ==="
|
|
QCONF="/config/qbittorrent/qBittorrent/qBittorrent.conf"
|
|
docker stop qbittorrent >/dev/null
|
|
python3 - "$QCONF" <<'PY'
|
|
from pathlib import Path
|
|
import sys
|
|
path = Path(sys.argv[1])
|
|
lines = path.read_text().splitlines()
|
|
out = []
|
|
added = False
|
|
for line in lines:
|
|
if line.startswith("WebUI\\AuthenticationEnabled="):
|
|
out.append("WebUI\\AuthenticationEnabled=false")
|
|
added = True
|
|
continue
|
|
out.append(line)
|
|
if not added:
|
|
final = []
|
|
for line in out:
|
|
final.append(line)
|
|
if line.strip() == "[Preferences]":
|
|
final.append("WebUI\\AuthenticationEnabled=false")
|
|
added = True
|
|
out = final
|
|
path.write_text("\n".join(out) + "\n")
|
|
print(" WebUI\\AuthenticationEnabled=false")
|
|
PY
|
|
grep 'WebUI\\AuthenticationEnabled' "$QCONF" || true
|
|
docker start qbittorrent >/dev/null
|
|
|
|
echo "=== nzbget: disable form auth (API creds unchanged) ==="
|
|
NZB="/config/nzbget/nzbget.conf"
|
|
sed -i 's/^FormAuth=.*/FormAuth=no/' "$NZB"
|
|
sed -i 's/^SecureControl=.*/SecureControl=no/' "$NZB"
|
|
grep -E '^(FormAuth|SecureControl)=' "$NZB"
|
|
docker restart nzbget >/dev/null
|
|
|
|
echo "=== stash: external authwall (Authentik + internal_only) ==="
|
|
python3 - <<'PY'
|
|
from pathlib import Path
|
|
import re
|
|
path = Path("/config/stash/config.yml")
|
|
text = path.read_text()
|
|
text = re.sub(r'^dangerous_allow_public_without_auth:.*$', 'dangerous_allow_public_without_auth: "true"', text, flags=re.M)
|
|
text = re.sub(r'^username:.*$', 'username: ""', text, flags=re.M)
|
|
text = re.sub(r'^password:.*$', 'password: ""', text, flags=re.M)
|
|
text = re.sub(r'^security_tripwire_accessed_from_public_internet:.*\n', '', text, flags=re.M)
|
|
path.write_text(text)
|
|
print(" dangerous_allow_public_without_auth=true, cleared username/password")
|
|
PY
|
|
docker restart stash >/dev/null
|
|
|
|
echo "=== *arr download clients: internal Docker URLs (bypass Caddy forward_auth) ==="
|
|
python3 - <<'PY'
|
|
import json
|
|
import sqlite3
|
|
|
|
# Servarr apps talk to download clients over the media network, not via *.ginnoir.com.
|
|
INTERNAL = {
|
|
"Nzbget": ("nzbget", 6789),
|
|
"QBittorrent": ("qbittorrent", 3232),
|
|
"Deluge": ("deluge", 8112),
|
|
}
|
|
PUBLIC_SUFFIX = ".ginnoir.com"
|
|
LOCALHOSTS = {"localhost", "127.0.0.1"}
|
|
|
|
for app in ("sonarr", "radarr", "prowlarr", "whisparr"):
|
|
db = f"/config/{app}/{app}.db"
|
|
conn = sqlite3.connect(db)
|
|
cur = conn.cursor()
|
|
cur.execute("SELECT Id, Name, Implementation, Settings FROM DownloadClients")
|
|
for cid, name, impl, settings_json in cur.fetchall():
|
|
if impl not in INTERNAL:
|
|
continue
|
|
settings = json.loads(settings_json)
|
|
host = (settings.get("host") or "").strip()
|
|
internal_host, port = INTERNAL[impl]
|
|
if host == internal_host and settings.get("port") == port and not settings.get("useSsl"):
|
|
continue
|
|
if PUBLIC_SUFFIX in host or host in LOCALHOSTS:
|
|
old = f"{host}:{settings.get('port')}"
|
|
if settings.get("useSsl"):
|
|
old += " ssl"
|
|
settings["host"] = internal_host
|
|
settings["port"] = port
|
|
settings["useSsl"] = False
|
|
cur.execute(
|
|
"UPDATE DownloadClients SET Settings=? WHERE Id=?",
|
|
(json.dumps(settings), cid),
|
|
)
|
|
print(f" {app}/{name}: {old} -> {internal_host}:{port} http")
|
|
conn.commit()
|
|
conn.close()
|
|
PY
|
|
|
|
echo "=== deluge: bypass web login (Authentik at edge; patch re-applies on recreate) ==="
|
|
if docker exec deluge grep -q 'homelab external auth' /lsiopy/lib/python3.12/site-packages/deluge/ui/web/auth.py 2>/dev/null; then
|
|
echo " already patched"
|
|
else
|
|
docker cp /tmp/patch-deluge-auth.py deluge:/tmp/patch-deluge-auth.py
|
|
docker exec deluge python3 /tmp/patch-deluge-auth.py
|
|
docker restart deluge >/dev/null
|
|
echo " patched and restarted"
|
|
fi
|
|
|
|
echo "=== done (tautulli untouched) ==="
|