From 1a7502952c1f6040f3a3b1c3d32302f9d967787b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 May 2026 21:34:49 +0000 Subject: [PATCH] feat: move panel update UI to Update module, add backup-only button & DB logging, fix password input exposure Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/a08c8b94-1b12-4eec-86c6-770cb435bb06 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com> --- modules/administration/administration.php | 5 - modules/administration/panel_update.php | 143 ++++++++++++++++++++-- modules/update/module.php | 23 +++- modules/update/update.php | 18 ++- modules/user_games/edit_home.php | 4 +- 5 files changed, 164 insertions(+), 29 deletions(-) diff --git a/modules/administration/administration.php b/modules/administration/administration.php index 84a33480..01fcb711 100644 --- a/modules/administration/administration.php +++ b/modules/administration/administration.php @@ -181,11 +181,6 @@ function exec_ogp_module() "\n"; ### END ICONS TO FRAMES - ### PANEL UPDATES - require_once(dirname(__FILE__) . '/panel_update.php'); - gsp_panel_update_section(); - ### END PANEL UPDATES - ### CHANGE MENU ORDER if ( isset( $_POST['changeOrder'] ) ) diff --git a/modules/administration/panel_update.php b/modules/administration/panel_update.php index cab711ef..1b822b5b 100644 --- a/modules/administration/panel_update.php +++ b/modules/administration/panel_update.php @@ -16,11 +16,11 @@ */ // Panel root is two directories up from this file (modules/administration/panel_update.php) -define('GSP_PANEL_DIR', realpath(dirname(__FILE__) . '/../../')); -define('GSP_BACKUP_BASE', GSP_PANEL_DIR . '/backups'); -define('GSP_UPDATE_LOG', GSP_PANEL_DIR . '/logs/panel_updates.log'); -define('GSP_VERSION_FILE', GSP_PANEL_DIR . '/includes/panel_version.php'); -define('GSP_VERSION_JSON', GSP_PANEL_DIR . '/version.json'); +defined('GSP_PANEL_DIR') || define('GSP_PANEL_DIR', realpath(dirname(__FILE__) . '/../../')); +defined('GSP_BACKUP_BASE') || define('GSP_BACKUP_BASE', GSP_PANEL_DIR . '/backups'); +defined('GSP_UPDATE_LOG') || define('GSP_UPDATE_LOG', GSP_PANEL_DIR . '/logs/panel_updates.log'); +defined('GSP_VERSION_FILE') || define('GSP_VERSION_FILE', GSP_PANEL_DIR . '/includes/panel_version.php'); +defined('GSP_VERSION_JSON') || define('GSP_VERSION_JSON', GSP_PANEL_DIR . '/version.json'); // --------------------------------------------------------------------------- // Helper: write a line to the panel update log @@ -35,6 +35,35 @@ function gsp_update_log($message) @file_put_contents(GSP_UPDATE_LOG, $line, FILE_APPEND | LOCK_EX); } +// --------------------------------------------------------------------------- +// Helper: insert a row into gsp_panel_update_log (silently skips on failure) +// --------------------------------------------------------------------------- +function gsp_log_update_to_db($channel, $branch, $status, $message, $backup_path = null, $db_backup_path = null, $file_backup_path = null, $started_at = null, $finished_at = null) +{ + global $db; + if (!isset($db) || !is_object($db)) { + return; + } + if ($started_at === null) { + $started_at = date('Y-m-d H:i:s'); + } + $channel = $db->real_escape_string((string) $channel); + $branch = $branch !== null ? "'" . $db->real_escape_string((string) $branch) . "'" : 'NULL'; + $status = $db->real_escape_string((string) $status); + $message_esc = $message !== null ? "'" . $db->real_escape_string((string) $message) . "'" : 'NULL'; + $backup_path_esc = $backup_path !== null ? "'" . $db->real_escape_string((string) $backup_path) . "'" : 'NULL'; + $db_backup_esc = $db_backup_path !== null ? "'" . $db->real_escape_string((string) $db_backup_path) . "'" : 'NULL'; + $file_backup_esc = $file_backup_path !== null ? "'" . $db->real_escape_string((string) $file_backup_path) . "'" : 'NULL'; + $started_esc = "'" . $db->real_escape_string($started_at) . "'"; + $finished_esc = $finished_at !== null ? "'" . $db->real_escape_string((string) $finished_at) . "'" : 'NULL'; + $db->query( + "INSERT INTO OGP_DB_PREFIXpanel_update_log" + . " (channel, branch, status, message, backup_path, db_backup_path, file_backup_path, started_at, finished_at)" + . " VALUES ('{$channel}', {$branch}, '{$status}', {$message_esc}," + . " {$backup_path_esc}, {$db_backup_esc}, {$file_backup_esc}, {$started_esc}, {$finished_esc})" + ); +} + // --------------------------------------------------------------------------- // Helper: read the installed version / branch from panel_version.php // --------------------------------------------------------------------------- @@ -836,7 +865,7 @@ function gsp_do_update($repo_owner, $repo_name, $ref, $update_type) } gsp_update_log("Update to {$ref} (type={$update_type}) complete"); - return ['success' => true, 'files_copied' => $files_copied]; + return ['success' => true, 'files_copied' => $files_copied, 'backup_dir' => $backup['backup_dir']]; } // --------------------------------------------------------------------------- @@ -1004,26 +1033,69 @@ function gsp_panel_update_section() $user_label = htmlspecialchars($_SESSION['users_login']) . ' (IP: ' . htmlspecialchars($_SERVER['REMOTE_ADDR']) . ')'; - if ($action === 'update_release') { + if ($action === 'backup_only') { + $started_at = date('Y-m-d H:i:s'); + $result = gsp_create_full_backup('backup-only', 'manual'); + $finished_at = date('Y-m-d H:i:s'); + if ($result['success']) { + $bk_dir = htmlspecialchars($result['backup_dir']); + print_success('Backup created successfully at ' . $bk_dir . '.'); + gsp_update_log("Admin {$user_label} created manual backup at {$result['backup_dir']}"); + gsp_log_update_to_db( + 'backup-only', null, 'success', + 'Manual backup by ' . $_SESSION['users_login'], + $result['backup_dir'], + $result['backup_dir'] . '/database.sql', + $result['backup_dir'] . '/panel-files.tar.gz', + $started_at, $finished_at + ); + } else { + print_failure('Backup failed: ' . htmlspecialchars($result['error'])); + gsp_update_log("Admin {$user_label} manual backup FAILED: {$result['error']}"); + gsp_log_update_to_db( + 'backup-only', null, 'failed', + 'Manual backup failed: ' . $result['error'], + null, null, null, $started_at, $finished_at + ); + } + + } elseif ($action === 'update_release') { $version = isset($_POST['gsp_release_version']) ? trim($_POST['gsp_release_version']) : ''; if (!preg_match('/^[a-zA-Z0-9._\-]+$/', $version) || strlen($version) > 80) { print_failure('Invalid release tag selected.'); } else { + $started_at = date('Y-m-d H:i:s'); $result = gsp_do_update($repo_owner, $repo_name, $version, 'release'); + $finished_at = date('Y-m-d H:i:s'); if ($result['success']) { print_success( 'Panel updated to release ' . htmlspecialchars($version) . '. ' . intval($result['files_copied']) . ' file(s) updated. Source: GitHub Releases' ); gsp_update_log("Admin {$user_label} updated panel to release {$version}"); + gsp_log_update_to_db( + 'release', $version, 'success', + 'Updated to release ' . $version . ' by ' . $_SESSION['users_login'], + $result['backup_dir'] ?? null, + isset($result['backup_dir']) ? $result['backup_dir'] . '/database.sql' : null, + isset($result['backup_dir']) ? $result['backup_dir'] . '/panel-files.tar.gz': null, + $started_at, $finished_at + ); } else { print_failure('Update failed: ' . htmlspecialchars($result['error'])); gsp_update_log("Admin {$user_label} update to release {$version} FAILED: {$result['error']}"); + gsp_log_update_to_db( + 'release', $version, 'failed', + 'Update to release ' . $version . ' failed: ' . $result['error'], + null, null, null, $started_at, $finished_at + ); } } } elseif ($action === 'update_stable') { + $started_at = date('Y-m-d H:i:s'); $result = gsp_do_update($repo_owner, $repo_name, $stable_branch, 'development'); + $finished_at = date('Y-m-d H:i:s'); if ($result['success']) { print_success( 'Panel updated to development version (' . htmlspecialchars($stable_branch) . '). ' @@ -1031,13 +1103,28 @@ function gsp_panel_update_section() . htmlspecialchars($stable_branch) . '' ); gsp_update_log("Admin {$user_label} updated panel to stable branch {$stable_branch}"); + gsp_log_update_to_db( + 'development', $stable_branch, 'success', + 'Updated to stable branch ' . $stable_branch . ' by ' . $_SESSION['users_login'], + $result['backup_dir'] ?? null, + isset($result['backup_dir']) ? $result['backup_dir'] . '/database.sql' : null, + isset($result['backup_dir']) ? $result['backup_dir'] . '/panel-files.tar.gz': null, + $started_at, $finished_at + ); } else { print_failure('Update failed: ' . htmlspecialchars($result['error'])); gsp_update_log("Admin {$user_label} update to stable branch {$stable_branch} FAILED: {$result['error']}"); + gsp_log_update_to_db( + 'development', $stable_branch, 'failed', + 'Update to stable branch ' . $stable_branch . ' failed: ' . $result['error'], + null, null, null, $started_at, $finished_at + ); } } elseif ($action === 'update_unstable') { + $started_at = date('Y-m-d H:i:s'); $result = gsp_do_update($repo_owner, $repo_name, $unstable_branch, 'cutting-edge'); + $finished_at = date('Y-m-d H:i:s'); if ($result['success']) { print_success( 'Panel updated to cutting edge version (' . htmlspecialchars($unstable_branch) . '). ' @@ -1045,9 +1132,22 @@ function gsp_panel_update_section() . htmlspecialchars($unstable_branch) . '' ); gsp_update_log("Admin {$user_label} updated panel to unstable branch {$unstable_branch}"); + gsp_log_update_to_db( + 'cutting-edge', $unstable_branch, 'success', + 'Updated to cutting-edge branch ' . $unstable_branch . ' by ' . $_SESSION['users_login'], + $result['backup_dir'] ?? null, + isset($result['backup_dir']) ? $result['backup_dir'] . '/database.sql' : null, + isset($result['backup_dir']) ? $result['backup_dir'] . '/panel-files.tar.gz': null, + $started_at, $finished_at + ); } else { print_failure('Update failed: ' . htmlspecialchars($result['error'])); gsp_update_log("Admin {$user_label} update to unstable branch {$unstable_branch} FAILED: {$result['error']}"); + gsp_log_update_to_db( + 'cutting-edge', $unstable_branch, 'failed', + 'Update to cutting-edge branch ' . $unstable_branch . ' failed: ' . $result['error'], + null, null, null, $started_at, $finished_at + ); } } elseif ($action === 'revert') { @@ -1055,16 +1155,31 @@ function gsp_panel_update_section() if (!preg_match('/^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$/', $backup_ts)) { print_failure('Invalid backup timestamp selected.'); } else { + $started_at = date('Y-m-d H:i:s'); $result = gsp_do_revert($backup_ts); + $finished_at = date('Y-m-d H:i:s'); if ($result['success']) { print_success( 'Panel reverted to backup from ' . htmlspecialchars($backup_ts) . '. ' . intval($result['files_restored']) . ' file(s) restored.' ); gsp_update_log("Admin {$user_label} reverted panel to backup {$backup_ts}"); + gsp_log_update_to_db( + 'revert', $backup_ts, 'success', + 'Reverted to backup ' . $backup_ts . ' by ' . $_SESSION['users_login'], + GSP_BACKUP_BASE . '/' . $backup_ts, + GSP_BACKUP_BASE . '/' . $backup_ts . '/database.sql', + GSP_BACKUP_BASE . '/' . $backup_ts . '/panel-files.tar.gz', + $started_at, $finished_at + ); } else { print_failure('Revert failed: ' . htmlspecialchars($result['error'])); gsp_update_log("Admin {$user_label} revert to backup {$backup_ts} FAILED: {$result['error']}"); + gsp_log_update_to_db( + 'revert', $backup_ts, 'failed', + 'Revert to backup ' . $backup_ts . ' failed: ' . $result['error'], + null, null, null, $started_at, $finished_at + ); } } } @@ -1130,6 +1245,20 @@ function gsp_panel_update_section() } echo "\n
\n"; + // ---- Backup Only -------------------------------------------------------- + echo "

Create Backup

\n"; + echo "
\n"; + echo "\n"; + echo "\n"; + echo "\n"; + echo "Saves to: " + . htmlspecialchars(GSP_BACKUP_BASE) . "\n"; + echo "
\n"; + + echo "
\n"; + // ---- Numbered Releases -------------------------------------------------- echo "

Numbered Releases

\n"; if (is_array($releases) && !empty($releases)) { diff --git a/modules/update/module.php b/modules/update/module.php index ac0f930e..392833e1 100644 --- a/modules/update/module.php +++ b/modules/update/module.php @@ -24,8 +24,8 @@ // Module general information $module_title = "Update"; -$module_version = "1.1"; -$db_version = 2; // avoid 'duplicate table' error message. +$module_version = "1.2"; +$db_version = 3; // avoid 'duplicate table' error message. $module_required = TRUE; $module_menus = array( array( 'subpage' => '', 'name'=>'Update', 'group'=>'admin' ) @@ -38,13 +38,28 @@ $install_queries[1] = array( `file_path` VARCHAR(1000) UNIQUE NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1;"); $install_queries[2] = array( - "DELETE FROM ".OGP_DB_PREFIX."update_blacklist +"DELETE FROM ".OGP_DB_PREFIX."update_blacklist WHERE file_path IN (SELECT * FROM (SELECT file_path FROM ".OGP_DB_PREFIX."update_blacklist GROUP BY file_path HAVING (COUNT(*) > 1) ) AS A );", "ALTER TABLE ".OGP_DB_PREFIX."update_blacklist MODIFY file_path VARCHAR(1000);", - "ALTER TABLE ".OGP_DB_PREFIX."update_blacklist ADD UNIQUE (file_path);" +"ALTER TABLE ".OGP_DB_PREFIX."update_blacklist ADD UNIQUE (file_path);" +); +$install_queries[3] = array( +"CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."panel_update_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `channel` varchar(64) NOT NULL, + `branch` varchar(128) DEFAULT NULL, + `status` varchar(32) NOT NULL, + `message` text DEFAULT NULL, + `backup_path` varchar(255) DEFAULT NULL, + `db_backup_path` varchar(255) DEFAULT NULL, + `file_backup_path` varchar(255) DEFAULT NULL, + `started_at` datetime NOT NULL, + `finished_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" ); ?> diff --git a/modules/update/update.php b/modules/update/update.php index d1280ac5..8e5df585 100644 --- a/modules/update/update.php +++ b/modules/update/update.php @@ -22,18 +22,14 @@ * */ - // todo, make checking and updating functions for updateing on the background. - // todo, more specified updates in smaller packages function exec_ogp_module() { - global $db, $settings; - define('REPONAME', 'OGP-Website'); - - if ($_SESSION['users_group'] != "admin") - { - print_failure(get_lang('no_access')); - return; - } -echo "To update the panel, visit our git at http://git.iaregamer.com:3000, download the panel and replace your files."; + if ($_SESSION['users_group'] !== 'admin') { + print_failure(get_lang('no_access')); + return; + } + require_once(dirname(__FILE__) . '/../administration/panel_update.php'); + gsp_panel_update_section(); } +?> diff --git a/modules/user_games/edit_home.php b/modules/user_games/edit_home.php index 2423ea11..458fe986 100644 --- a/modules/user_games/edit_home.php +++ b/modules/user_games/edit_home.php @@ -715,7 +715,7 @@ function exec_ogp_module() echo "". get_lang("game_control_password") .":"; echo "
"; echo "\n"; - echo ""; + echo ""; echo ""; echo "
"; echo "". get_lang("change_control_password_info") .""; @@ -754,7 +754,7 @@ function exec_ogp_module() // Form to edit control ftp password echo "". get_lang("server_ftp_password") .":"; echo "
"; - echo ""; + echo ""; echo ""; echo "
"; echo "". get_lang("change_ftp_password_info") ."";