-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ticket/15851] Automatic update downloader
PHPBB3-15851
- Loading branch information
Showing
3 changed files
with
307 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |