frankbook: propagate skip-state before restart, PBKDF2 qB seed
The frankbook handler ran port verification even for services the credential gate skipped, so a parked qbittorrent failed the deploy and aborted the five arrs. Gate now lives Mac-side (test -s gluetun/env inside the VM) before restart+verify. The qB first-boot seed wrote a plaintext WebUI\Password, which qB >= 4.2 ignores (PBKDF2 @ByteArray only), and omitted HostHeaderValidation=false, which would 401 the LAN forwarder path. Seed now generates the PBKDF2 hash in the VM (python3 hashlib) and sets ServerDomains=* + HostHeaderValidation=false. Arr categories (lidarr/radarr/tv-sonarr) pre-created with save_path=/Volumes/COMPLETE/Finished Torrents so any grab lands in the review dir regardless of wiring details.
This commit is contained in:
+51
-35
@@ -841,64 +841,80 @@ deploy_frankbook_stack() {
|
||||
done
|
||||
local tmp
|
||||
tmp="$(mktemp /tmp/frankbook-vm.XXXXXX)"
|
||||
cat > "$tmp" <<'VM_SETUP'
|
||||
cat > "$tmp" <<'VM_SEED'
|
||||
set -euo pipefail
|
||||
SVC="${1:?service required}"
|
||||
# qBittorrent first-boot seed: conf + categories + machine-local password.
|
||||
# qBittorrent first-boot seed: conf + categories + machine-local PBKDF2
|
||||
# password. qB >= 4.2 ignores plaintext passwords, so the conf carries the
|
||||
# @ByteArray(salt:hash) form (PBKDF2-HMAC-SHA512, 100k iterations, 64 bytes).
|
||||
if [ ! -e /home/core/Containers/qbittorrent/qbit-seeded ]; then
|
||||
mkdir -p /Volumes/COMPLETE/qbittorrent-data/qBittorrent
|
||||
QBIT_PW="$(openssl rand -base64 18 | tr -d '/+=')"
|
||||
QBIT_PW="$(openssl rand -base64 18 | tr -d '/+=' | head -c 20)"
|
||||
QBIT_HASH="$(python3 - "$QBIT_PW" <<'PYH'
|
||||
import hashlib, base64, os, sys
|
||||
pw = sys.argv[1].encode()
|
||||
salt = os.urandom(16)
|
||||
h = hashlib.pbkdf2_hmac("sha512", pw, salt, 100000, dklen=64)
|
||||
print("@ByteArray(%s:%s)" % (base64.b64encode(salt).decode(), base64.b64encode(h).decode()))
|
||||
PYH
|
||||
)"
|
||||
umask 077
|
||||
printf 'QBIT_WEBUI_PASSWORD=%s\n' "$QBIT_PW" > /home/core/Containers/qbittorrent/env
|
||||
umask 022
|
||||
{
|
||||
cat <<'QCONF'
|
||||
[AutoRun]
|
||||
|
||||
cat > /Volumes/COMPLETE/qbittorrent-data/qBittorrent/qBittorrent.conf <<QCONF
|
||||
[BitTorrent]
|
||||
Session\DefaultSavePath=/Volumes/COMPLETE
|
||||
Session\Port=6881
|
||||
Session\QueueingSystemEnabled=true
|
||||
Session\TempPath=/Volumes/INCOMPLETE/incomplete
|
||||
Session\TempPathEnabled=true
|
||||
Session\\DefaultSavePath=/Volumes/COMPLETE
|
||||
Session\\Port=6881
|
||||
Session\\QueueingSystemEnabled=true
|
||||
Session\\TempPath=/Volumes/INCOMPLETE/incomplete
|
||||
Session\\TempPathEnabled=true
|
||||
|
||||
[LegalNotice]
|
||||
Accepted=true
|
||||
|
||||
[Meta]
|
||||
MigrationVersion=8
|
||||
|
||||
[Network]
|
||||
Cookies\Enabled=true
|
||||
Cookies\\Enabled=true
|
||||
|
||||
[Preferences]
|
||||
WebUI\Address=*
|
||||
WebUI\Username=admin
|
||||
WebUI\\Address=*
|
||||
WebUI\\ServerDomains=*
|
||||
WebUI\\HostHeaderValidation=false
|
||||
WebUI\\Username=admin
|
||||
WebUI\\Password=$QBIT_HASH
|
||||
QCONF
|
||||
printf 'WebUI\\Password=%s\n' "$QBIT_PW"
|
||||
} > /Volumes/COMPLETE/qbittorrent-data/qBittorrent/qBittorrent.conf
|
||||
cat > /Volumes/COMPLETE/qbittorrent-data/qBittorrent/categories.json <<'QCAT'
|
||||
{
|
||||
"Finished Torrents": {
|
||||
"save_path": "/Volumes/COMPLETE/Finished Torrents"
|
||||
},
|
||||
"lidarr": {"save_path": ""},
|
||||
"radarr": {"save_path": ""},
|
||||
"tv-sonarr": {"save_path": ""}
|
||||
"Finished Torrents": {"save_path": "/Volumes/COMPLETE/Finished Torrents"},
|
||||
"lidarr": {"save_path": "/Volumes/COMPLETE/Finished Torrents"},
|
||||
"radarr": {"save_path": "/Volumes/COMPLETE/Finished Torrents"},
|
||||
"tv-sonarr": {"save_path": "/Volumes/COMPLETE/Finished Torrents"}
|
||||
}
|
||||
QCAT
|
||||
touch /home/core/Containers/qbittorrent/qbit-seeded
|
||||
echo " seeded qBittorrent config (WebUI password: /home/core/Containers/qbittorrent/env inside the VM)"
|
||||
fi
|
||||
if [ "$SVC" = gluetun ] && [ ! -s /home/core/Containers/gluetun/env ]; then
|
||||
echo "SKIP: gluetun has no credentials yet."
|
||||
echo " Write the ProtonVPN WireGuard keys into /home/core/Containers/gluetun/env inside the VM"
|
||||
echo " (podman machine ssh), then re-run: ./scripts/deploy.sh frankbook-pro --service gluetun"
|
||||
exit 0
|
||||
fi
|
||||
if [ "$SVC" = qbittorrent ] && [ ! -s /home/core/Containers/gluetun/env ]; then
|
||||
echo "SKIP: qbittorrent waits for gluetun credentials."
|
||||
exit 0
|
||||
fi
|
||||
VM_SEED
|
||||
podman machine ssh bash -s < "$tmp"
|
||||
rm -f "$tmp"
|
||||
# Credential gate: without a WireGuard env the tunnel stays parked, and
|
||||
# qBittorrent (which downloads through it) waits with it. The arrs run
|
||||
# without the tunnel, so only these two services are gated.
|
||||
case "$service" in
|
||||
gluetun|qbittorrent)
|
||||
if ! podman machine ssh '[ -s /home/core/Containers/gluetun/env ]' >/dev/null 2>&1; then
|
||||
echo "SKIP: $service waits for gluetun credentials."
|
||||
echo " Write the WireGuard env into /home/core/Containers/gluetun/env inside the VM"
|
||||
echo " (podman machine ssh), then re-run: ./scripts/deploy.sh frankbook-pro --service gluetun --service qbittorrent"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
tmp="$(mktemp /tmp/frankbook-vm.XXXXXX)"
|
||||
cat > "$tmp" <<'VM_START'
|
||||
set -euo pipefail
|
||||
SVC="${1:?service required}"
|
||||
systemctl --user daemon-reload
|
||||
unit="$(systemctl --user list-units --all --no-legend "${SVC}.service" "container-${SVC}.service" 2>/dev/null | head -n1 | awk '{print $1}')"
|
||||
[ -n "$unit" ] || { echo "FAIL: no generated systemd unit for $SVC" >&2; exit 1; }
|
||||
@@ -910,7 +926,7 @@ if [ "$state" != active ] && [ "$state" != activating ]; then
|
||||
systemctl --user status "$unit" --no-pager -l || true
|
||||
exit 1
|
||||
fi
|
||||
VM_SETUP
|
||||
VM_START
|
||||
podman machine ssh bash -s "$service" < "$tmp"
|
||||
rm -f "$tmp"
|
||||
local port path
|
||||
|
||||
Reference in New Issue
Block a user