From 7e4c29edc7b56163927e2c68143290d7a020659a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 9 May 2026 15:27:53 +0000 Subject: [PATCH 1/2] fix: resolve XML path for billing provisioning, set server_expiration_date, 6-char passwords Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/ce009e66-16ae-4ca7-a28c-5dac466cc014 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com> --- modules/billing/add_to_cart.php | 15 ++++++++--- modules/billing/create_servers.php | 33 ++++++++++++++++++----- modules/billing/includes/panel_bridge.php | 4 +++ modules/gamemanager/update_actions.php | 31 +++++++++++++++++++-- 4 files changed, 72 insertions(+), 11 deletions(-) diff --git a/modules/billing/add_to_cart.php b/modules/billing/add_to_cart.php index 4f36f8b4..a55b6e02 100644 --- a/modules/billing/add_to_cart.php +++ b/modules/billing/add_to_cart.php @@ -18,12 +18,21 @@ if (session_status() === PHP_SESSION_NONE) { session_start(); } -function billing_generate_password(int $bytes = 12): string +function billing_generate_password(): string { + $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + $len = strlen($alphabet); + $password = ''; try { - return substr(bin2hex(random_bytes($bytes)), 0, $bytes * 2); + for ($i = 0; $i < 6; $i++) { + $password .= $alphabet[random_int(0, $len - 1)]; + } + return $password; } catch (Throwable $e) { - return substr(hash('sha256', uniqid('gsp', true) . microtime(true)), 0, $bytes * 2); + for ($i = 0; $i < 6; $i++) { + $password .= $alphabet[mt_rand(0, $len - 1)]; + } + return $password; } } diff --git a/modules/billing/create_servers.php b/modules/billing/create_servers.php index a3f375e9..cb903088 100644 --- a/modules/billing/create_servers.php +++ b/modules/billing/create_servers.php @@ -183,9 +183,27 @@ if (!function_exists('billing_detect_install_state')) { $state['reason'] = 'home_cfg_file is missing; install completion cannot be verified.'; return $state; } - $server_xml = read_server_config(SERVER_CONFIG_LOCATION . "/" . $home_info['home_cfg_file']); + $xml_cfg_file = $home_info['home_cfg_file'] ?? ''; + $xml_rel = rtrim(SERVER_CONFIG_LOCATION, '/') . '/' . $xml_cfg_file; + $xml_abs = $xml_rel; + if (!is_readable($xml_rel)) { + $panel_root = realpath(__DIR__ . '/../../'); + if ($panel_root !== false) { + $xml_abs = $panel_root . '/' . ltrim($xml_rel, '/'); + } + } + billing_provision_trace('billing_detect_install_state: XML path resolution.', array( + 'home_id' => intval($home_info['home_id'] ?? 0), + 'home_cfg_file' => $xml_cfg_file, + 'xml_rel_path' => $xml_rel, + 'xml_abs_path' => $xml_abs, + 'cwd' => getcwd(), + 'xml_file_exists' => file_exists($xml_abs), + 'xml_is_readable' => is_readable($xml_abs), + )); + $server_xml = read_server_config($xml_abs); if (!$server_xml) { - $state['reason'] = 'Could not read server config XML; install completion cannot be verified.'; + $state['reason'] = "Could not read server config XML; install completion cannot be verified. Tried: {$xml_abs}"; return $state; } $server_exec_name = trim((string)($server_xml->server_exec_name ?? '')); @@ -1252,11 +1270,14 @@ function exec_ogp_module() } if ($home_id > 0) { - // Set billing_status and next_invoice_date on server_homes + // Set billing_status, next_invoice_date, and server_expiration_date on server_homes. + // server_expiration_date must match end_date so the billing cron can determine + // when to suspend / delete the server. $db->query("UPDATE `{$db_prefix}server_homes` - SET billing_status = 'Active', - next_invoice_date = '" . $db->realEscapeSingle($end_date_str) . "', - billing_enabled = 1 + SET billing_status = 'Active', + next_invoice_date = '" . $db->realEscapeSingle($end_date_str) . "', + server_expiration_date = '" . $db->realEscapeSingle($end_date_str) . "', + billing_enabled = 1 WHERE home_id = " . $db->realEscapeSingle($home_id)); $home_row_after = billing_get_server_home_row($db, $db_prefix, intval($home_id)); billing_provision_trace('Loaded server_homes row after billing linkage updates.', array( diff --git a/modules/billing/includes/panel_bridge.php b/modules/billing/includes/panel_bridge.php index ccfdf930..7d94188c 100644 --- a/modules/billing/includes/panel_bridge.php +++ b/modules/billing/includes/panel_bridge.php @@ -35,6 +35,10 @@ if (!function_exists('billing_panel_bootstrap')) { static $includeInjected = false; if (!$includeInjected) { set_include_path($root . PATH_SEPARATOR . get_include_path()); + // Change CWD to the panel root so that SERVER_CONFIG_LOCATION and other + // relative paths (e.g. XML_SCHEMA) resolve correctly when billing endpoints + // run outside of home.php (e.g. api/capture_order.php, PayPal webhooks). + chdir($root); $includeInjected = true; } diff --git a/modules/gamemanager/update_actions.php b/modules/gamemanager/update_actions.php index 88a5f5e9..16e7335b 100644 --- a/modules/gamemanager/update_actions.php +++ b/modules/gamemanager/update_actions.php @@ -33,9 +33,36 @@ if (!function_exists('gamemanager_trigger_update_install')) { return $resultBase + array('ok' => false, 'pending' => true, 'message' => "No mod profile configured for home #{$home_id}."); } - $server_xml = read_server_config(SERVER_CONFIG_LOCATION . "/" . $home_info['home_cfg_file']); + // Build the XML path and resolve it to an absolute location so provisioning + // paths that do not run from the panel root CWD (e.g. billing capture_order.php) + // can still locate the file. SERVER_CONFIG_LOCATION is a relative constant + // ("modules/config_games/server_configs/") that only works when CWD equals the + // panel root; update_actions.php lives in modules/gamemanager/ so the panel + // root is __DIR__ . '/../../'. + $xml_cfg_file = $home_info['home_cfg_file'] ?? ''; + $xml_rel = rtrim(SERVER_CONFIG_LOCATION, '/') . '/' . $xml_cfg_file; + $xml_abs = $xml_rel; + if (!is_readable($xml_rel)) { + $panel_root = realpath(__DIR__ . '/../../'); + if ($panel_root !== false) { + $xml_abs = $panel_root . '/' . ltrim($xml_rel, '/'); + } + } + if (function_exists('billing_provision_trace')) { + billing_provision_trace('gamemanager_trigger_update_install: XML path resolution.', array( + 'home_id' => $home_id, + 'home_cfg_file' => $xml_cfg_file, + 'server_config_location' => SERVER_CONFIG_LOCATION, + 'xml_rel_path' => $xml_rel, + 'xml_abs_path' => $xml_abs, + 'cwd' => getcwd(), + 'xml_file_exists' => file_exists($xml_abs), + 'xml_is_readable' => is_readable($xml_abs), + )); + } + $server_xml = read_server_config($xml_abs); if (!$server_xml) { - return $resultBase + array('ok' => false, 'pending' => true, 'message' => "Could not read server config XML for home #{$home_id}."); + return $resultBase + array('ok' => false, 'pending' => true, 'message' => "Could not read server config XML for home #{$home_id}. Tried: {$xml_abs}"); } $remote = new OGPRemoteLibrary($home_info['agent_ip'], $home_info['agent_port'], $home_info['encryption_key'], $home_info['timeout']); From 91ed67d2eb5815155700450a8d9b3334da83917b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 9 May 2026 15:28:55 +0000 Subject: [PATCH 2/2] fix: address code review feedback - guard billing_provision_trace, deduplicate password loop Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/ce009e66-16ae-4ca7-a28c-5dac466cc014 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com> --- modules/billing/add_to_cart.php | 11 ++++------- modules/billing/create_servers.php | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/modules/billing/add_to_cart.php b/modules/billing/add_to_cart.php index a55b6e02..1f531e20 100644 --- a/modules/billing/add_to_cart.php +++ b/modules/billing/add_to_cart.php @@ -23,17 +23,14 @@ function billing_generate_password(): string $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; $len = strlen($alphabet); $password = ''; - try { - for ($i = 0; $i < 6; $i++) { + for ($i = 0; $i < 6; $i++) { + try { $password .= $alphabet[random_int(0, $len - 1)]; - } - return $password; - } catch (Throwable $e) { - for ($i = 0; $i < 6; $i++) { + } catch (Throwable $e) { $password .= $alphabet[mt_rand(0, $len - 1)]; } - return $password; } + return $password; } function billing_normalize_duration(string $duration): array diff --git a/modules/billing/create_servers.php b/modules/billing/create_servers.php index cb903088..d9df1c21 100644 --- a/modules/billing/create_servers.php +++ b/modules/billing/create_servers.php @@ -192,15 +192,17 @@ if (!function_exists('billing_detect_install_state')) { $xml_abs = $panel_root . '/' . ltrim($xml_rel, '/'); } } - billing_provision_trace('billing_detect_install_state: XML path resolution.', array( - 'home_id' => intval($home_info['home_id'] ?? 0), - 'home_cfg_file' => $xml_cfg_file, - 'xml_rel_path' => $xml_rel, - 'xml_abs_path' => $xml_abs, - 'cwd' => getcwd(), - 'xml_file_exists' => file_exists($xml_abs), - 'xml_is_readable' => is_readable($xml_abs), - )); + if (function_exists('billing_provision_trace')) { + billing_provision_trace('billing_detect_install_state: XML path resolution.', array( + 'home_id' => intval($home_info['home_id'] ?? 0), + 'home_cfg_file' => $xml_cfg_file, + 'xml_rel_path' => $xml_rel, + 'xml_abs_path' => $xml_abs, + 'cwd' => getcwd(), + 'xml_file_exists' => file_exists($xml_abs), + 'xml_is_readable' => is_readable($xml_abs), + )); + } $server_xml = read_server_config($xml_abs); if (!$server_xml) { $state['reason'] = "Could not read server config XML; install completion cannot be verified. Tried: {$xml_abs}";