mirror of
https://github.com/phpbb/phpbb.git
synced 2025-06-07 20:08:53 +00:00
[ticket/15851] Automatic update downloader
PHPBB3-15851
This commit is contained in:
parent
84ec3dc6c3
commit
d2c402f038
9 changed files with 352 additions and 1 deletions
|
@ -29,6 +29,7 @@
|
||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"ext-zlib": "*",
|
"ext-zlib": "*",
|
||||||
|
"ext-sodium": "*",
|
||||||
"bantu/ini-get-wrapper": "~1.0",
|
"bantu/ini-get-wrapper": "~1.0",
|
||||||
"carlos-mg89/oauth": "^0.8.15",
|
"carlos-mg89/oauth": "^0.8.15",
|
||||||
"chita/topological_sort": "^3.0",
|
"chita/topological_sort": "^3.0",
|
||||||
|
|
|
@ -20,3 +20,5 @@ parameters:
|
||||||
- passwords.driver.bcrypt
|
- passwords.driver.bcrypt
|
||||||
- passwords.driver.salted_md5
|
- passwords.driver.salted_md5
|
||||||
- passwords.driver.phpass
|
- passwords.driver.phpass
|
||||||
|
|
||||||
|
public_key: 'auJX0pGetfYatE7t/rX5hAkCLZv9s78TwKkLfR3YGuQ='
|
||||||
|
|
|
@ -37,6 +37,7 @@ imports:
|
||||||
- { resource: services_twig.yml }
|
- { resource: services_twig.yml }
|
||||||
- { resource: services_twig_extensions.yml }
|
- { resource: services_twig_extensions.yml }
|
||||||
- { resource: services_ucp.yml }
|
- { resource: services_ucp.yml }
|
||||||
|
- { resource: services_updater.yml }
|
||||||
- { resource: services_user.yml }
|
- { resource: services_user.yml }
|
||||||
|
|
||||||
- { resource: tables.yml }
|
- { resource: tables.yml }
|
||||||
|
|
14
phpBB/config/default/container/services_updater.yml
Normal file
14
phpBB/config/default/container/services_updater.yml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
services:
|
||||||
|
updater.get_updates:
|
||||||
|
class: phpbb\update\get_updates
|
||||||
|
arguments:
|
||||||
|
- '@filesystem'
|
||||||
|
- '%public_key%'
|
||||||
|
- '%core.root_path%'
|
||||||
|
|
||||||
|
updater.controller:
|
||||||
|
class: phpbb\update\controller
|
||||||
|
arguments:
|
||||||
|
- '@filesystem'
|
||||||
|
- '@updater.get_updates'
|
||||||
|
- '%core.root_path%'
|
|
@ -38,12 +38,32 @@ class acp_update
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$recheck = $request->variable('versioncheck_force', false);
|
$recheck = $request->variable('versioncheck_force', false);
|
||||||
|
$do_update = $request->variable('do_update', false);
|
||||||
|
|
||||||
$updates_available = $version_helper->get_update_on_branch($recheck);
|
$updates_available = $version_helper->get_update_on_branch($recheck);
|
||||||
$upgrades_available = $version_helper->get_suggested_updates();
|
$upgrades_available = $version_helper->get_suggested_updates();
|
||||||
|
$branch = '';
|
||||||
if (!empty($upgrades_available))
|
if (!empty($upgrades_available))
|
||||||
{
|
{
|
||||||
|
$branch = array_key_last($upgrades_available);
|
||||||
$upgrades_available = array_pop($upgrades_available);
|
$upgrades_available = array_pop($upgrades_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($do_update && !empty($updates_available))
|
||||||
|
{
|
||||||
|
$updater = $phpbb_container->get('updater.controller');
|
||||||
|
$current_version = $config['version'];
|
||||||
|
$new_version = $upgrades_available['current'];
|
||||||
|
$download_url = 'https://download.phpbb.com/pub/release/';
|
||||||
|
$download_url .= $branch . '/' . $new_version . '/';
|
||||||
|
$download_url .= 'phpBB-' . $current_version . '_to_' . $new_version . '.zip';
|
||||||
|
$data = $updater->handle(
|
||||||
|
$download_url
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = new \phpbb\json_response();
|
||||||
|
$response->send($data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (\RuntimeException $e)
|
catch (\RuntimeException $e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -221,6 +221,13 @@ $lang = array_merge($lang, array(
|
||||||
|
|
||||||
<p>We noticed that the last update of your phpBB installation hasn’t been completed. Visit the <a href="%1$s" title="%1$s">database updater</a>, ensure <em>Update database only</em> is selected and click on <strong>Submit</strong>. Don\'t forget to delete the "install"-directory after you have updated the database successfully.</p>',
|
<p>We noticed that the last update of your phpBB installation hasn’t been completed. Visit the <a href="%1$s" title="%1$s">database updater</a>, ensure <em>Update database only</em> is selected and click on <strong>Submit</strong>. Don\'t forget to delete the "install"-directory after you have updated the database successfully.</p>',
|
||||||
|
|
||||||
|
// Auto update
|
||||||
|
'COULD_NOT_DOWNLOAD_UPDATE_PACKAGE' => 'Failed to download the update package.',
|
||||||
|
'COULD_NOT_DOWNLOAD_UPDATE_SIGNATURE' => 'Failed to download the update package signature.',
|
||||||
|
'UPDATE_SIGNATURE_INVALID' => 'The update package is corrupted.',
|
||||||
|
'COULD_NOT_EXTRACT_UPDATE' => 'Could not extract files from the update package.',
|
||||||
|
'COULD_NOT_WRITE_UPDATE_FILES' => 'Could not copy files from the update package.',
|
||||||
|
|
||||||
//
|
//
|
||||||
// Server data
|
// Server data
|
||||||
//
|
//
|
||||||
|
|
|
@ -96,7 +96,7 @@ class check_server_environment extends \phpbb\install\task_base
|
||||||
*/
|
*/
|
||||||
protected function check_php_version()
|
protected function check_php_version()
|
||||||
{
|
{
|
||||||
if (version_compare(PHP_VERSION, '7.2.0', '<'))
|
if (version_compare(PHP_VERSION, '8.1.0', '<'))
|
||||||
{
|
{
|
||||||
$this->response_helper->add_error_message('PHP_VERSION_REQD', 'PHP_VERSION_REQD_EXPLAIN');
|
$this->response_helper->add_error_message('PHP_VERSION_REQD', 'PHP_VERSION_REQD_EXPLAIN');
|
||||||
|
|
||||||
|
|
137
phpBB/phpbb/update/controller.php
Normal file
137
phpBB/phpbb/update/controller.php
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This file is part of the phpBB Forum Software package.
|
||||||
|
*
|
||||||
|
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||||
|
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||||
|
*
|
||||||
|
* For full copyright and license information, please see
|
||||||
|
* the docs/CREDITS.txt file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace phpbb\update;
|
||||||
|
|
||||||
|
use phpbb\filesystem\filesystem_interface;
|
||||||
|
use phpbb\language\language;
|
||||||
|
|
||||||
|
class controller
|
||||||
|
{
|
||||||
|
/** @var filesystem_interface Filesystem manager */
|
||||||
|
private filesystem_interface $filesystem;
|
||||||
|
|
||||||
|
/** @var get_updates Updater class */
|
||||||
|
private get_updates $updater;
|
||||||
|
|
||||||
|
/** @var language Translation handler */
|
||||||
|
private language $language;
|
||||||
|
|
||||||
|
/** @var string phpBB root path */
|
||||||
|
private string $phpbb_root_path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param filesystem_interface $filesystem
|
||||||
|
* @param get_updates $updater
|
||||||
|
* @param language $language
|
||||||
|
* @param string $phpbb_root_path
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
filesystem_interface $filesystem,
|
||||||
|
get_updates $updater,
|
||||||
|
language $language,
|
||||||
|
string $phpbb_root_path)
|
||||||
|
{
|
||||||
|
$this->filesystem = $filesystem;
|
||||||
|
$this->language = $language;
|
||||||
|
$this->updater = $updater;
|
||||||
|
$this->phpbb_root_path = $phpbb_root_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle requests.
|
||||||
|
*
|
||||||
|
* @param string $download The download URL.
|
||||||
|
*
|
||||||
|
* @return string[] Unencoded json response.
|
||||||
|
*/
|
||||||
|
public function handle(string $download): array
|
||||||
|
{
|
||||||
|
$update_path = $this->phpbb_root_path . 'store/update.zip';
|
||||||
|
$status = ['status' => 'continue'];
|
||||||
|
if (!file_exists($update_path))
|
||||||
|
{
|
||||||
|
$result = $this->updater->download($download, $update_path);
|
||||||
|
if (!$result)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => 'error',
|
||||||
|
'error' => $this->language->lang('COULD_NOT_DOWNLOAD_UPDATE_PACKAGE')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($update_path . '.sig'))
|
||||||
|
{
|
||||||
|
$result = $this->updater->download($download . '.sig', $update_path . '.sig');
|
||||||
|
if (!$result)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => 'error',
|
||||||
|
'error' => $this->language->lang('COULD_NOT_DOWNLOAD_UPDATE_SIGNATURE')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_dir($this->phpbb_root_path . 'store/update'))
|
||||||
|
{
|
||||||
|
$result = $this->updater->validate($update_path, $update_path . '.sig');
|
||||||
|
if (!$result)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => 'error',
|
||||||
|
'error' => $this->language->lang('UPDATE_SIGNATURE_INVALID')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->updater->extract($update_path, $this->phpbb_root_path . 'store/update');
|
||||||
|
if (!$result)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => 'error',
|
||||||
|
'error' => $this->language->lang('COULD_NOT_EXTRACT_UPDATE')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_dir($this->phpbb_root_path . 'install'))
|
||||||
|
{
|
||||||
|
$result = $this->updater->copy($this->phpbb_root_path . 'store/update');
|
||||||
|
if (!$result)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'status' => 'error',
|
||||||
|
'error' => $this->language->lang('COULD_NOT_WRITE_UPDATE_FILES')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->filesystem->remove([
|
||||||
|
$this->phpbb_root_path . 'store/update',
|
||||||
|
$update_path,
|
||||||
|
$update_path . '.sig'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$status['status'] = 'done';
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
}
|
169
phpBB/phpbb/update/get_updates.php
Normal file
169
phpBB/phpbb/update/get_updates.php
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This file is part of the phpBB Forum Software package.
|
||||||
|
*
|
||||||
|
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||||
|
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||||
|
*
|
||||||
|
* For full copyright and license information, please see
|
||||||
|
* the docs/CREDITS.txt file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace phpbb\update;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use phpbb\filesystem\exception\filesystem_exception;
|
||||||
|
use phpbb\filesystem\filesystem_interface;
|
||||||
|
use SodiumException;
|
||||||
|
use ZipArchive;
|
||||||
|
|
||||||
|
class get_updates
|
||||||
|
{
|
||||||
|
/** @var filesystem_interface Filesystem managerr */
|
||||||
|
private filesystem_interface $filesystem;
|
||||||
|
|
||||||
|
/** @var Client HTTP client */
|
||||||
|
private Client $http_client;
|
||||||
|
|
||||||
|
/** @var string Public key to verify package */
|
||||||
|
private string $public_key;
|
||||||
|
|
||||||
|
/** @var string phpBB root path */
|
||||||
|
private string $phpbb_root_path;
|
||||||
|
|
||||||
|
/** @var ZipArchive Zip extractor */
|
||||||
|
private ZipArchive $zipper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param filesystem_interface $filesystem
|
||||||
|
* @param string $public_key
|
||||||
|
* @param string $phpbb_root_path
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
filesystem_interface $filesystem,
|
||||||
|
string $public_key,
|
||||||
|
string $phpbb_root_path)
|
||||||
|
{
|
||||||
|
$this->filesystem = $filesystem;
|
||||||
|
$this->http_client = new Client();
|
||||||
|
$this->public_key = base64_decode($public_key);
|
||||||
|
$this->phpbb_root_path = $phpbb_root_path;
|
||||||
|
$this->zipper = new ZipArchive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download the update package.
|
||||||
|
*
|
||||||
|
* @param string $url Download link to the update.
|
||||||
|
* @param string $storage_path Location for the download.
|
||||||
|
*
|
||||||
|
* @return bool Whether the download completed successfully.
|
||||||
|
*/
|
||||||
|
public function download(string $url, string $storage_path): bool
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$this->http_client->request('GET', $url, [
|
||||||
|
'sink' => $storage_path,
|
||||||
|
'allow_redirects' => false
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
catch (GuzzleException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the downloaded file.
|
||||||
|
*
|
||||||
|
* @param string $file_path Path to the download.
|
||||||
|
* @param string $signature_path The signature file.
|
||||||
|
*
|
||||||
|
* @return bool Whether the signature is correct or not.
|
||||||
|
*/
|
||||||
|
public function validate(string $file_path, string $signature_path): bool
|
||||||
|
{
|
||||||
|
if (file_exists($file_path) === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($signature_path) === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$raw_signature = file_get_contents($signature_path);
|
||||||
|
|
||||||
|
$hash = hash_file('sha384', $file_path, true);
|
||||||
|
if ($hash === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$signature = base64_decode($raw_signature);
|
||||||
|
if ($signature === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return sodium_crypto_sign_verify_detached($signature, $hash, $this->public_key);
|
||||||
|
}
|
||||||
|
catch (SodiumException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the downloaded archive.
|
||||||
|
*
|
||||||
|
* @param string $zip_file Path to the archive.
|
||||||
|
* @param string $to Path to where to extract the archive to.
|
||||||
|
*
|
||||||
|
* @return bool Whether the extraction completed successfully.
|
||||||
|
*/
|
||||||
|
public function extract(string $zip_file, string $to): bool
|
||||||
|
{
|
||||||
|
if ($this->zipper->open($zip_file) === false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->zipper->extractTo($to);
|
||||||
|
$this->zipper->close();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the update package to the root folder.
|
||||||
|
*
|
||||||
|
* @param string $src_dir Where to copy from.
|
||||||
|
*
|
||||||
|
* @return bool Whether the files were copied successfully.
|
||||||
|
*/
|
||||||
|
public function copy(string $src_dir): bool
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$this->filesystem->mirror($src_dir, $this->phpbb_root_path);
|
||||||
|
}
|
||||||
|
catch (filesystem_exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue