From b9dd0695125a816a2e77ceae77f177f19840b150 Mon Sep 17 00:00:00 2001 From: Lucky <43052474+MrLuckyGamer@users.noreply.github.com> Date: Wed, 14 Jan 2026 02:51:09 +1100 Subject: [PATCH 1/3] Implement token caching for authentication process Added functions for handling cached authentication tokens, including checking, loading, and saving tokens. Refactored authentication process to utilize cached tokens if available, meaning the owner does not need to authenticate after each restart. --- start.sh | 321 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 196 insertions(+), 125 deletions(-) diff --git a/start.sh b/start.sh index 4077a67..b6cbfca 100644 --- a/start.sh +++ b/start.sh @@ -11,6 +11,7 @@ ################################################################################ DOWNLOADER="./hytale-downloader-linux-amd64" +AUTH_CACHE_FILE=".hytale-auth-tokens.json" # Function to extract downloaded server files extract_server_files() { @@ -48,6 +49,196 @@ extract_server_files() { fi } +# Function to check if cached tokens exist +check_cached_tokens() { + if [ -f "$AUTH_CACHE_FILE" ]; then + # Check if jq is available + if ! command -v jq &> /dev/null; then + echo "Warning: jq not found, cannot use cached tokens" + return 1 + fi + + # Validate JSON format + if ! jq empty "$AUTH_CACHE_FILE" 2>/dev/null; then + echo "Warning: Invalid cached token file, removing..." + rm "$AUTH_CACHE_FILE" + return 1 + fi + + echo "✓ Found cached authentication tokens" + return 0 + fi + return 1 +} + +# Function to load cached tokens +load_cached_tokens() { + ACCESS_TOKEN=$(jq -r '.access_token' "$AUTH_CACHE_FILE") + SESSION_TOKEN=$(jq -r '.session_token' "$AUTH_CACHE_FILE") + IDENTITY_TOKEN=$(jq -r '.identity_token' "$AUTH_CACHE_FILE") + PROFILE_UUID=$(jq -r '.profile_uuid' "$AUTH_CACHE_FILE") + + # Validate all required tokens are present + if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ] || \ + [ -z "$SESSION_TOKEN" ] || [ "$SESSION_TOKEN" = "null" ] || \ + [ -z "$IDENTITY_TOKEN" ] || [ "$IDENTITY_TOKEN" = "null" ] || \ + [ -z "$PROFILE_UUID" ] || [ "$PROFILE_UUID" = "null" ]; then + echo "Error: Incomplete cached tokens, re-authenticating..." + rm "$AUTH_CACHE_FILE" + return 1 + fi + + echo "✓ Loaded cached authentication tokens" + return 0 +} + +# Function to save authentication tokens +save_auth_tokens() { + cat > "$AUTH_CACHE_FILE" << EOF +{ + "access_token": "$ACCESS_TOKEN", + "session_token": "$SESSION_TOKEN", + "identity_token": "$IDENTITY_TOKEN", + "profile_uuid": "$PROFILE_UUID", + "timestamp": $(date +%s) +} +EOF + echo "✓ Authentication tokens cached for future use" +} + +# Function to perform full authentication +perform_authentication() { + echo "Obtaining authentication tokens..." + + # Step 1: Request device code + AUTH_RESPONSE=$(curl -s -X POST "https://oauth.accounts.hytale.com/oauth2/device/auth" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "client_id=hytale-server" \ + -d "scope=openid offline auth:server") + + # Extract device_code and verification_uri_complete using jq + DEVICE_CODE=$(echo "$AUTH_RESPONSE" | jq -r '.device_code') + VERIFICATION_URI=$(echo "$AUTH_RESPONSE" | jq -r '.verification_uri_complete') + POLL_INTERVAL=$(echo "$AUTH_RESPONSE" | jq -r '.interval') + + # Display authentication banner + echo "" + echo "╔═════════════════════════════════════════════════════════════════════════════╗" + echo "║ HYTALE SERVER AUTHENTICATION REQUIRED ║" + echo "╠═════════════════════════════════════════════════════════════════════════════╣" + echo "║ ║" + echo "║ Please authenticate the server by visiting the following URL: ║" + echo "║ ║" + echo "║ $VERIFICATION_URI ║" + echo "║ ║" + echo "║ 1. Click the link above or copy it to your browser ║" + echo "║ 2. Sign in with your Hytale account ║" + echo "║ 3. Authorize the server ║" + echo "║ ║" + echo "║ Waiting for authentication... ║" + echo "║ ║" + echo "╚═════════════════════════════════════════════════════════════════════════════╝" + echo "" + + # Step 2: Poll for access token + ACCESS_TOKEN="" + while [ -z "$ACCESS_TOKEN" ]; do + sleep $POLL_INTERVAL + + TOKEN_RESPONSE=$(curl -s -X POST "https://oauth.accounts.hytale.com/oauth2/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "client_id=hytale-server" \ + -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \ + -d "device_code=$DEVICE_CODE") + + # Check if we got an error + ERROR=$(echo "$TOKEN_RESPONSE" | jq -r '.error // empty') + + if [ "$ERROR" = "authorization_pending" ]; then + echo "Still waiting for authentication..." + continue + elif [ -n "$ERROR" ]; then + echo "Authentication error: $ERROR" + exit 1 + else + # Successfully authenticated + ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token') + echo "" + echo "✓ Authentication successful!" + echo "" + fi + done + + # Fetch available game profiles + echo "Fetching game profiles..." + + PROFILES_RESPONSE=$(curl -s -X GET "https://account-data.hytale.com/my-account/get-profiles" \ + -H "Authorization: Bearer $ACCESS_TOKEN") + + # Check if profiles list is empty + PROFILES_COUNT=$(echo "$PROFILES_RESPONSE" | jq '.profiles | length') + + if [ "$PROFILES_COUNT" -eq 0 ]; then + echo "Error: No game profiles found. You need to purchase Hytale to run a server." + exit 1 + fi + + # Select profile based on GAME_PROFILE variable + if [ -n "$GAME_PROFILE" ]; then + # User specified a profile username, find matching UUID + echo "Looking for profile: $GAME_PROFILE" + PROFILE_UUID=$(echo "$PROFILES_RESPONSE" | jq -r ".profiles[] | select(.username == \"$GAME_PROFILE\") | .uuid") + + if [ -z "$PROFILE_UUID" ] || [ "$PROFILE_UUID" = "null" ]; then + echo "Error: Profile '$GAME_PROFILE' not found." + echo "Available profiles:" + echo "$PROFILES_RESPONSE" | jq -r '.profiles[] | " - \(.username)"' + exit 1 + fi + + echo "✓ Using profile: $GAME_PROFILE (UUID: $PROFILE_UUID)" + else + # Use first profile from the list + PROFILE_UUID=$(echo "$PROFILES_RESPONSE" | jq -r '.profiles[0].uuid') + PROFILE_USERNAME=$(echo "$PROFILES_RESPONSE" | jq -r '.profiles[0].username') + + echo "✓ Using default profile: $PROFILE_USERNAME (UUID: $PROFILE_UUID)" + fi + + echo "" + + # Create game server session + echo "Creating game server session..." + + SESSION_RESPONSE=$(curl -s -X POST "https://sessions.hytale.com/game-session/new" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"uuid\": \"${PROFILE_UUID}\"}") + + # Validate JSON response + if ! echo "$SESSION_RESPONSE" | jq empty 2>/dev/null; then + echo "Error: Invalid JSON response from game session creation" + echo "Response: $SESSION_RESPONSE" + exit 1 + fi + + # Extract session and identity tokens + SESSION_TOKEN=$(echo "$SESSION_RESPONSE" | jq -r '.sessionToken') + IDENTITY_TOKEN=$(echo "$SESSION_RESPONSE" | jq -r '.identityToken') + + if [ -z "$SESSION_TOKEN" ] || [ "$SESSION_TOKEN" = "null" ]; then + echo "Error: Failed to create game server session" + echo "Response: $SESSION_RESPONSE" + exit 1 + fi + + echo "✓ Game server session created successfully!" + echo "" + + # Save tokens for future use + save_auth_tokens +} + # Check if the downloader exists if [ ! -f "$DOWNLOADER" ]; then echo "Error: Hytale downloader not found!" @@ -85,134 +276,14 @@ if [ ! -f "HytaleServer.jar" ]; then exit 1 fi -# Obtain authentication tokens -echo "Obtaining authentication tokens..." - -# Step 1: Request device code -AUTH_RESPONSE=$(curl -s -X POST "https://oauth.accounts.hytale.com/oauth2/device/auth" \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -d "client_id=hytale-server" \ - -d "scope=openid offline auth:server") - -# Extract device_code and verification_uri_complete using jq -DEVICE_CODE=$(echo "$AUTH_RESPONSE" | jq -r '.device_code') -VERIFICATION_URI=$(echo "$AUTH_RESPONSE" | jq -r '.verification_uri_complete') -POLL_INTERVAL=$(echo "$AUTH_RESPONSE" | jq -r '.interval') - -# Display authentication banner -echo "" -echo "╔═════════════════════════════════════════════════════════════════════════════╗" -echo "║ HYTALE SERVER AUTHENTICATION REQUIRED ║" -echo "╠═════════════════════════════════════════════════════════════════════════════╣" -echo "║ ║" -echo "║ Please authenticate the server by visiting the following URL: ║" -echo "║ ║" -echo "║ $VERIFICATION_URI ║" -echo "║ ║" -echo "║ 1. Click the link above or copy it to your browser ║" -echo "║ 2. Sign in with your Hytale account ║" -echo "║ 3. Authorize the server ║" -echo "║ ║" -echo "║ Waiting for authentication... ║" -echo "║ ║" -echo "╚═════════════════════════════════════════════════════════════════════════════╝" -echo "" - -# Step 2: Poll for access token -ACCESS_TOKEN="" -while [ -z "$ACCESS_TOKEN" ]; do - sleep $POLL_INTERVAL - - TOKEN_RESPONSE=$(curl -s -X POST "https://oauth.accounts.hytale.com/oauth2/token" \ - -H "Content-Type: application/x-www-form-urlencoded" \ - -d "client_id=hytale-server" \ - -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \ - -d "device_code=$DEVICE_CODE") - - # Check if we got an error - ERROR=$(echo "$TOKEN_RESPONSE" | jq -r '.error // empty') - - if [ "$ERROR" = "authorization_pending" ]; then - echo "Still waiting for authentication..." - continue - elif [ -n "$ERROR" ]; then - echo "Authentication error: $ERROR" - exit 1 - else - # Successfully authenticated - ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token') - echo "" - echo "✓ Authentication successful!" - echo "" - fi -done - -# Fetch available game profiles -echo "Fetching game profiles..." - -PROFILES_RESPONSE=$(curl -s -X GET "https://account-data.hytale.com/my-account/get-profiles" \ - -H "Authorization: Bearer $ACCESS_TOKEN") - -# Check if profiles list is empty -PROFILES_COUNT=$(echo "$PROFILES_RESPONSE" | jq '.profiles | length') - -if [ "$PROFILES_COUNT" -eq 0 ]; then - echo "Error: No game profiles found. You need to purchase Hytale to run a server." - exit 1 -fi - -# Select profile based on GAME_PROFILE variable -if [ -n "$GAME_PROFILE" ]; then - # User specified a profile username, find matching UUID - echo "Looking for profile: $GAME_PROFILE" - PROFILE_UUID=$(echo "$PROFILES_RESPONSE" | jq -r ".profiles[] | select(.username == \"$GAME_PROFILE\") | .uuid") - - if [ -z "$PROFILE_UUID" ] || [ "$PROFILE_UUID" = "null" ]; then - echo "Error: Profile '$GAME_PROFILE' not found." - echo "Available profiles:" - echo "$PROFILES_RESPONSE" | jq -r '.profiles[] | " - \(.username)"' - exit 1 - fi - - echo "✓ Using profile: $GAME_PROFILE (UUID: $PROFILE_UUID)" +# Check for cached authentication tokens +if check_cached_tokens && load_cached_tokens; then + echo "Using cached authentication - skipping login prompt" else - # Use first profile from the list - PROFILE_UUID=$(echo "$PROFILES_RESPONSE" | jq -r '.profiles[0].uuid') - PROFILE_USERNAME=$(echo "$PROFILES_RESPONSE" | jq -r '.profiles[0].username') - - echo "✓ Using default profile: $PROFILE_USERNAME (UUID: $PROFILE_UUID)" + # Perform full authentication if no valid cache exists + perform_authentication fi -echo "" - -# Create game server session -echo "Creating game server session..." - -SESSION_RESPONSE=$(curl -s -X POST "https://sessions.hytale.com/game-session/new" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"uuid\": \"${PROFILE_UUID}\"}") - -# Validate JSON response -if ! echo "$SESSION_RESPONSE" | jq empty 2>/dev/null; then - echo "Error: Invalid JSON response from game session creation" - echo "Response: $SESSION_RESPONSE" - exit 1 -fi - -# Extract session and identity tokens -SESSION_TOKEN=$(echo "$SESSION_RESPONSE" | jq -r '.sessionToken') -IDENTITY_TOKEN=$(echo "$SESSION_RESPONSE" | jq -r '.identityToken') - -if [ -z "$SESSION_TOKEN" ] || [ "$SESSION_TOKEN" = "null" ]; then - echo "Error: Failed to create game server session" - echo "Response: $SESSION_RESPONSE" - exit 1 -fi - -echo "✓ Game server session created successfully!" -echo "" - echo "Starting Hytale server..." # Build the Java command From f7baea86a2323c3118ddde20388505fd10691da9 Mon Sep 17 00:00:00 2001 From: Lucky <43052474+MrLuckyGamer@users.noreply.github.com> Date: Wed, 14 Jan 2026 03:01:12 +1100 Subject: [PATCH 2/3] Change backup directory to './backup' --- start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.sh b/start.sh index b6cbfca..3529ca1 100644 --- a/start.sh +++ b/start.sh @@ -330,7 +330,7 @@ fi # Add backup parameters if enabled if [ "${ENABLE_BACKUPS}" = "1" ]; then - JAVA_CMD="${JAVA_CMD} --backup --backup-dir ${BACKUP_DIRECTORY} --backup-frequency ${BACKUP_FREQUENCY}" + JAVA_CMD="${JAVA_CMD} --backup --backup-dir ./backup --backup-frequency ${BACKUP_FREQUENCY}" fi # Add session tokens and owner UUID From bd0f722c25ea06a495ce21625ab17d52f4d7b0a6 Mon Sep 17 00:00:00 2001 From: Lucky <43052474+MrLuckyGamer@users.noreply.github.com> Date: Wed, 14 Jan 2026 03:23:14 +1100 Subject: [PATCH 3/3] Implement version check and update for downloader Added version check for downloader and updated version.txt after successful update. --- start.sh | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/start.sh b/start.sh index 3529ca1..1fcfe02 100644 --- a/start.sh +++ b/start.sh @@ -264,9 +264,34 @@ fi # Run automatic update if enabled if [ "${AUTOMATIC_UPDATE}" = "1" ]; then echo "Starting Hytale downloader..." - $DOWNLOADER -check-update - $DOWNLOADER -patchline $PATCHLINE -download-path server.zip - extract_server_files + + # Read local version from file + if [ -f "version.txt" ]; then + LOCAL_VERSION=$(cat version.txt) + else + echo "version.txt not found, forcing update" + LOCAL_VERSION="" + fi + + # Get remote/downloader version + DOWNLOADER_VERSION=$($DOWNLOADER -print-version) + + echo "Local version: $LOCAL_VERSION" + echo "Downloader version: $DOWNLOADER_VERSION" + + # Compare versions + if [ "$LOCAL_VERSION" != "$DOWNLOADER_VERSION" ]; then + echo "Version mismatch, running update..." + + $DOWNLOADER -check-update + $DOWNLOADER -patchline $PATCHLINE -download-path server.zip + extract_server_files + + # Update version.txt after successful update + echo "$DOWNLOADER_VERSION" > version.txt + else + echo "Versions match, skipping update" + fi fi # Check if server files were downloaded correctly