diff --git a/etc/skel/install-media-stack.sh b/etc/skel/install-media-stack.sh index 213aba82..bf0abe97 100755 --- a/etc/skel/install-media-stack.sh +++ b/etc/skel/install-media-stack.sh @@ -1541,6 +1541,15 @@ servarr_auth_payload_write() { MEDIA_STACK_AUTH_USERNAME="$MEDIA_STACK_AUTH_USERNAME" MEDIA_STACK_AUTH_PASSWORD="$password" php -r '$input = stream_get_contents(STDIN); $data = json_decode($input, true); if (!is_array($data)) { fwrite(STDERR, "Invalid Servarr host-config JSON\n"); exit(1); } $data["id"] = isset($data["id"]) ? $data["id"] : 1; $data["authenticationMethod"] = "forms"; $data["authenticationRequired"] = "enabled"; $data["username"] = getenv("MEDIA_STACK_AUTH_USERNAME"); $data["password"] = getenv("MEDIA_STACK_AUTH_PASSWORD"); $data["passwordConfirmation"] = getenv("MEDIA_STACK_AUTH_PASSWORD"); if (isset($data["updateMechanism"]) && $data["updateMechanism"] === "script" && (!isset($data["updateScriptPath"]) || $data["updateScriptPath"] === "")) { $data["updateMechanism"] = "builtIn"; } echo json_encode($data, JSON_UNESCAPED_SLASHES);' <"$source_json" >"$target_json" } +# The configure step writes UrlBase before seeding, so it is live on the seed start: +# unprefixed API paths answer an empty 307, which curl -f accepts. Build the host-config +# URL under the UrlBase so the JSON fetch and the PUT reach the API. +servarr_host_config_url() { + local config_file="$1" seed_port="$2" api_version="$3" url_base + url_base=$(sed -n -E 's|.*([^<]*).*|\1|p' "$config_file" 2>/dev/null | head -n 1 || true) + printf 'http://127.0.0.1:%s%s/api/%s/config/host' "$seed_port" "${url_base%/}" "$api_version" +} + servarr_auth_seed() { local app="$1" install_name="$2" dll="$3" desired_port="$4" api_version="$5" password="$6" extra_args="${7:-}" local datadir="$HOME/.config/${app}" @@ -1559,7 +1568,7 @@ servarr_auth_seed() { seed_port="$desired_port" session="${app}-auth-seed" - base_url="http://127.0.0.1:${seed_port}/api/${api_version}/config/host" + base_url=$(servarr_host_config_url "$config_file" "$seed_port" "$api_version") response_json=$(mktemp) payload_json=$(mktemp) curl_config=$(mktemp) diff --git a/scripts/lib/tests/development/installMediaStackScriptTest.php b/scripts/lib/tests/development/installMediaStackScriptTest.php index d5cafb8f..2dfc808f 100644 --- a/scripts/lib/tests/development/installMediaStackScriptTest.php +++ b/scripts/lib/tests/development/installMediaStackScriptTest.php @@ -225,11 +225,34 @@ public function testMediaStackCredentialsUseDelugeStylePhpCsprngAndOwnerOnlyFile ], $this->script); } + public function testServarrHostConfigUrlUsesUrlBase(): void + { + // Servarr answers unprefixed API paths with an empty 307 once UrlBase is set (Refs #858). + $script = implode("\n", array( + '#!/usr/bin/env bash', 'set -euo pipefail', 'dir=$(mktemp -d)', + $this->pmssExtractShellFunctions($this->script, array('servarr_host_config_url')), + 'probe() { printf "%s\n" "" "$1" "" >"$dir/config.xml"; servarr_host_config_url "$dir/config.xml" 17878 "$2"; printf "\n"; }', + 'probe " /public-bob/radarr" v3', + 'probe " /public-bob/prowlarr/" v1', + 'probe " " v3', + 'probe " " v3', + 'servarr_host_config_url "$dir/missing.xml" 17878 v3; printf "\n"', + 'rm -rf "$dir"', '', + )); + $this->assertSame(implode("\n", array( + 'http://127.0.0.1:17878/public-bob/radarr/api/v3/config/host', + 'http://127.0.0.1:17878/public-bob/prowlarr/api/v1/config/host', + 'http://127.0.0.1:17878/api/v3/config/host', + 'http://127.0.0.1:17878/api/v3/config/host', + 'http://127.0.0.1:17878/api/v3/config/host', + )), $this->pmssRunShellHarness($script)); + } + public function testServarrAuthSeedingUsesLocalApiAndFailsClosed(): void { $this->assertStringContainsAllStrings([ 'servarr_auth_seed() {', - 'base_url="http://127.0.0.1:${seed_port}/api/${api_version}/config/host"', + 'base_url=$(servarr_host_config_url "$config_file" "$seed_port" "$api_version")', '$data["authenticationMethod"] = "forms"', '$data["authenticationRequired"] = "enabled"', 'servarr_credentials_mark_existing_unknown() {', @@ -374,6 +397,7 @@ public function testServarrAuthSeedAuthenticatesProbeReadAndWrite(): void 'servarr_api_key_curl_config_write', 'servarr_api_key_curl_config_wait', 'servarr_auth_payload_write', + 'servarr_host_config_url', 'servarr_auth_seed', )); $script = implode("\n", array(