X-Git-Url: https://jfr.im/git/irc/unrealircd/unrealircd-webpanel.git/blobdiff_plain/840c8c3e5de4be4bd70f40f8eed2d5217c2bed98..cd26522ba6ff68c18e1504b022ca92f4d01827be:/Classes/class-upgrade.php diff --git a/Classes/class-upgrade.php b/Classes/class-upgrade.php index ea99377..e29f6df 100644 --- a/Classes/class-upgrade.php +++ b/Classes/class-upgrade.php @@ -3,7 +3,8 @@ class Upgrade { public $web_dir; - public $download_dir; + private $temp_dir; + private static $temp_extracted_dir; public static $upgrade_available; public static $last_check; public $error; @@ -21,19 +22,21 @@ class Upgrade $tok = split(__DIR__, '/'); unset($tok[count($tok) - 1]); $this->web_dir = implode('/',$tok).'/'; - $this->download_dir = $this->web_dir.'downloads'; + /** prepare the temp directory */ + $temp_dir = $this->web_dir."panel_upgrade"; + $temp_dir .= ($temp_dir[strlen($temp_dir) - 1] != '/') ? "/" : ""; + if (file_exists($temp_dir)) { + deleteDirectoryContents($temp_dir); + rmdir($temp_dir); + } + $mkdir = mkdir($temp_dir, 0755, true); + + $this->temp_dir = $mkdir ? $temp_dir : NULL; + $this->error = $mkdir ? NULL : "Could not create directory: $temp_dir"; Upgrade::$upgrade_available = false; - $this->checkForNew(); if ($this->error) error_log($this->error); - else - { - if (Upgrade::$upgrade_available) - error_log("Upgrade available! Version ".Upgrade::$latest_version); - else - error_log("No upgrade available"); - } } /** Checks for a new upgrade */ @@ -41,12 +44,18 @@ class Upgrade { global $config; read_config_db(); - if (time() - $config['upgrade']['last_check'] < 300) // only check every 15 mins - return $config['upgrade']['latest_version'] > WEBPANEL_VERSION ? true : false; + $last_check = &$config['upgrade']['last_check']; + if (isset($last_check) && time() - $last_check < 300) // only check every 15 mins + { + error_log("Skipping upgrade check, checked ".time() - $last_check." seconds ago"); + return false; + } + error_log(time()." - ".$last_check." = ".time()-$last_check); + $apiUrl = "https://api.github.com/repos/unrealircd/unrealircd-webpanel/releases"; + $response = file_get_contents($apiUrl, false, stream_context_create( + ["http" => ["method" => "GET", "header" => "User-agent: UnrealIRCd Webpanel"]] + )); - // Define the API URL to check for updates - $apiUrl = "https://api.github.com/repos/unrealircd/unrealircd-webpanel/releases"; // Replace with your API URL - $response = file_get_contents($apiUrl, false, stream_context_create(["http" => ["method" => "GET", "header" => "User-agent: UnrealIRCd Webpanel"]])); if ($response === false) { $this->error = "Couldn't check github."; @@ -55,7 +64,7 @@ class Upgrade $data = json_decode($response, true); $latest = $data[count($data) - 1]; $config['upgrade']['latest_version'] = $latest['tag_name']; - $config['upgrade']['last_check'] = time(); + $last_check = time(); $config['upgrade']['download_link'] = $latest['zipball_url']; write_config('upgrade'); Upgrade::$upgrade_available = (float)$latest['tag_name'] > WEBPANEL_VERSION ? true : false; @@ -64,7 +73,7 @@ class Upgrade function downloadUpgradeZip() { $ch = curl_init(get_config('upgrade::download_link')); - $fp = fopen($this->download_dir."/unrealircd-webpanel-upgrade.zip", 'w+'); + $fp = fopen($this->temp_dir."unrealircd-webpanel-upgrade.zip", 'w+'); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_TIMEOUT, 60); @@ -73,80 +82,183 @@ class Upgrade 'User-Agent: UnrealIRCd Webpanel', ]); $success = curl_exec($ch); - + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + if ($code == "403" || $code == "404") + { + $this->error ="Unable to download"; + } curl_close($ch); fclose($fp); return $success; } + function extractZip() { + $zip = new ZipArchive; + if ($zip->open($this->temp_dir."unrealircd-webpanel-upgrade.zip") === true) + { + $zip->extractTo("$this->temp_dir"); + $zip->close(); + self::$temp_extracted_dir = findOnlyDirectory($this->temp_dir); + error_log(self::$temp_extracted_dir); + return true; + } else { + return false; + } + } + function cleanupOldFiles() + { + foreach ($this->compareAndGetFilesToDelete() as $file) + { + unlink("$this->web_dir$file"); + error_log("Deleting: $file"); + } + } + function compareAndGetFilesToDelete() : array + { + $currentFiles = $this->listFiles($this->web_dir); + $updateFiles = $this->listFiles(self::$temp_extracted_dir); + $filesToDelete = array_diff($currentFiles, $updateFiles); + $filesToActuallyDelete = []; + error_log("Comparing... Files to delete:"); + foreach ($filesToDelete as $file) + { + // skip the relevant directories + if (str_starts_with($file, "panel_upgrade/") + || str_starts_with($file, "vendor/") + || str_starts_with($file, "config/") + || str_starts_with($file, "data/") + || str_starts_with($file, "plugins/")) + continue; + $filesToActuallyDelete[] = $file; + } + return $filesToActuallyDelete; + } + + function extractToWebdir() + { + recurse_copy(self::$temp_extracted_dir, $this->web_dir); + } + + /** + * Cleans up the extracted update files + * @return void + */ + function cleanupDownloadFiles() + { + $ex_dir = self::$temp_extracted_dir ?? findOnlyDirectory($this->temp_dir); + deleteDirectoryContents($ex_dir); + rmdir($ex_dir); + } + + function listFiles($dir) { + $files = []; + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); + foreach ($iterator as $file) + { + if ($file->isFile()) + { + $f = substr($file->getPathname(), strlen($dir)); + if ($f[0] == "/") $f = substr($f,1); + + $files[] = $f; + } + } + return $files; + } } - // Define the URL to download the update -$downloadUrl = "https://example.com/api/download_update"; // Replace with your download URL - -// Define the URL to download the update -$downloadUrl = "https://example.com/api/download_update"; // Replace with your download URL -// Define the directory where the update will be extracted -$webDir = __DIR__; // Current directory +function findOnlyDirectory($topDir) { + // Ensure the directory exists and is indeed a directory + if (!is_dir($topDir)) { + die("The specified path is not a directory."); + } -// Function to check for updates -function checkForUpdate($url) { - $response = file_get_contents($url); - if ($response === FALSE) { - die("Error checking for updates."); + // Open the directory + $dirHandle = opendir($topDir); + if ($dirHandle === false) { + die("Unable to open directory."); } - $data = json_decode($response, true); - return $data['update_available'] ?? false; -} -// Function to download the update -function downloadUpdate($url, $savePath) { - $ch = curl_init($url); - $fp = fopen($savePath, 'w+'); + $directories = []; + + // Read through the directory contents + while (($entry = readdir($dirHandle)) !== false) { + $fullPath = $topDir . DIRECTORY_SEPARATOR . $entry; + // Check if the entry is a directory and not . or .. + if (is_dir($fullPath) && $entry !== '.' && $entry !== '..') { + $directories[] = $fullPath; + } + } - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_setopt($ch, CURLOPT_TIMEOUT, 60); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + // Close the directory handle + closedir($dirHandle); - $success = curl_exec($ch); + // Check if there is exactly one directory + if (count($directories) === 1) { + return $directories[0]; + } elseif (count($directories) === 0) { + return "No directories found after extracting. Possibly missing php-zip extention. Aborting upgrade."; + } else { + return "Multiple directories found. Previous cleanup was unsuccessful for some reason, maybe a permissions error? Aborting upgrade."; + } +} - curl_close($ch); - fclose($fp); - return $success; -} +function deleteDirectoryContents($dir) { + error_log("Deleting directory contents at $dir"); + if (!is_dir($dir)) { + echo "The provided path is not a directory."; + return false; + } -// Function to extract the zip file -function extractZip($zipPath, $extractTo) { - $zip = new ZipArchive; - if ($zip->open($zipPath) === TRUE) { - $zip->extractTo($extractTo); - $zip->close(); - return true; - } else { + // Open the directory + $handle = opendir($dir); + if ($handle === false) { + echo "Failed to open the directory."; return false; } -} -/** -// Check for updates -if (checkForUpdate($apiUrl)) { - $tempZipFile = $webDir . '/update.zip'; - - // Download the update - if (downloadUpdate($downloadUrl, $tempZipFile)) { - // Extract the update - if (extractZip($tempZipFile, $webDir)) { - echo "Update applied successfully."; + + // Loop through the directory contents + while (($item = readdir($handle)) !== false) { + // Skip the special entries "." and ".." + if ($item == "." || $item == "..") { + continue; + } + + $itemPath = $dir."/".$item; + + // If the item is a directory, recursively delete its contents + if (is_dir($itemPath)) { + deleteDirectoryContents($itemPath); + // Remove the empty directory + rmdir($itemPath); } else { - echo "Failed to extract the update."; + // If the item is a file, delete it + unlink($itemPath); } - // Clean up the temporary zip file - unlink($tempZipFile); - } else { - echo "Failed to download the update."; } -} else { - echo "No update available."; + + // Close the directory handle + closedir($handle); + + return true; +} + +function recurse_copy($src, $dst) { + $dir = opendir($src); + @mkdir($dst); + while(false !== ( $file = readdir($dir)) ) + if (( $file != '.' ) && ( $file != '..' )) + { + if ( is_dir($src . '/' . $file) ) + recurse_copy($src . '/' . $file, $dst . '/' . $file); + + else + copy($src . '/' . $file, $dst . '/' . $file); + } + + + closedir($dir); } -*/