mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-21 13:20:56 +00:00
patch_manager: handle sha256 checksum
This commit is contained in:
parent
ca07605835
commit
570eee3202
@ -7,6 +7,8 @@
|
||||
#include "curl_handle.h"
|
||||
#include "progress_dialog.h"
|
||||
|
||||
#include "Crypto/sha256.h"
|
||||
|
||||
LOG_CHANNEL(network_log, "NETWORK");
|
||||
|
||||
size_t curl_write_cb_compat(char* ptr, size_t /*size*/, size_t nmemb, void* userdata)
|
||||
@ -120,6 +122,27 @@ progress_dialog* downloader::get_progress_dialog() const
|
||||
return m_progress_dialog;
|
||||
}
|
||||
|
||||
std::string downloader::get_hash(const char* data, size_t size, bool lower_case)
|
||||
{
|
||||
u8 res_hash[32];
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts_ret(&ctx, 0);
|
||||
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(data), size);
|
||||
mbedtls_sha256_finish_ret(&ctx, res_hash);
|
||||
|
||||
std::string res_hash_string("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
||||
for (size_t index = 0; index < 32; index++)
|
||||
{
|
||||
const auto pal = lower_case ? "0123456789abcdef" : "0123456789ABCDEF";
|
||||
res_hash_string[index * 2] = pal[res_hash[index] >> 4];
|
||||
res_hash_string[(index * 2) + 1] = pal[res_hash[index] & 15];
|
||||
}
|
||||
|
||||
return res_hash_string;
|
||||
}
|
||||
|
||||
size_t downloader::update_buffer(char* data, size_t size)
|
||||
{
|
||||
if (m_curl_abort)
|
||||
|
@ -22,6 +22,8 @@ public:
|
||||
|
||||
progress_dialog* get_progress_dialog() const;
|
||||
|
||||
static std::string get_hash(const char* data, size_t size, bool lower_case);
|
||||
|
||||
private Q_SLOTS:
|
||||
void handle_buffer_update(int size, int max);
|
||||
|
||||
|
@ -832,7 +832,26 @@ void patch_manager_dialog::dragLeaveEvent(QDragLeaveEvent* event)
|
||||
|
||||
void patch_manager_dialog::download_update()
|
||||
{
|
||||
m_downloader->start("https://rpcs3.net/compatibility?patch&api=v1", true, true, tr("Downloading latest patches"));
|
||||
patch_log.notice("Patch download triggered");
|
||||
|
||||
const std::string path = patch_engine::get_patches_path() + "patch.yml";
|
||||
std::string url = "https://rpcs3.net/compatibility?patch&api=v1&v=" + patch_engine_version;
|
||||
|
||||
if (fs::is_file(path))
|
||||
{
|
||||
if (fs::file patch_file{path})
|
||||
{
|
||||
const std::string hash = downloader::get_hash(patch_file.to_string().c_str(), patch_file.size(), true);
|
||||
url += "&sha256=" + hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
patch_log.error("Could not open patch file: %s", path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_downloader->start(url, true, true, tr("Downloading latest patches"));
|
||||
}
|
||||
|
||||
bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||
@ -845,8 +864,9 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||
std::string error_message;
|
||||
switch (return_code)
|
||||
{
|
||||
case -1: error_message = "Hash not found"; break;
|
||||
case -1: error_message = "No patches found for the specified version"; break;
|
||||
case -2: error_message = "Server Error - Maintenance Mode"; break;
|
||||
case -3: error_message = "Server Error - Illegal Search"; break;
|
||||
case -255: error_message = "Server Error - Return code not found"; break;
|
||||
default: error_message = "Server Error - Unknown Error"; break;
|
||||
}
|
||||
@ -859,6 +879,19 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (return_code == 1)
|
||||
{
|
||||
patch_log.notice("Patch download: No newer patches found");
|
||||
QMessageBox::information(this, tr("Download successful"), tr("Your patch file is already up to date."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (return_code != 0)
|
||||
{
|
||||
patch_log.error("Patch download error: unknown return code: %d", return_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
const QJsonValue& version_obj = json_data["version"];
|
||||
|
||||
if (!version_obj.isString())
|
||||
@ -874,6 +907,14 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
const QJsonValue& hash_obj = json_data["sha256"];
|
||||
|
||||
if (!hash_obj.isString())
|
||||
{
|
||||
patch_log.error("JSON doesn't contain sha256");
|
||||
return false;
|
||||
}
|
||||
|
||||
const QJsonValue& patch = json_data["patch"];
|
||||
|
||||
if (!patch.isString() || patch.toString().isEmpty())
|
||||
@ -887,18 +928,26 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||
|
||||
const std::string content = patch.toString().toStdString();
|
||||
|
||||
if (hash_obj.toString().toStdString() != downloader::get_hash(content.c_str(), content.size(), true))
|
||||
{
|
||||
patch_log.error("JSON content does not match the provided checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (patch_engine::load(patches, "From Download", content, true, &log_message))
|
||||
{
|
||||
patch_log.success("Successfully validated downloaded patch file");
|
||||
patch_log.notice("Successfully validated downloaded patch file");
|
||||
const std::string path = patch_engine::get_patches_path() + "patch.yml";
|
||||
|
||||
const std::string path = patch_engine::get_patches_path() + "patch.yml";
|
||||
const std::string path_old = path + ".old";
|
||||
|
||||
// Back up current patch file
|
||||
if (!fs::copy_file(path, path_old, true))
|
||||
// Back up current patch file if possible
|
||||
if (fs::is_file(path))
|
||||
{
|
||||
patch_log.error("Could not back up current patches to %s", path_old);
|
||||
return true;
|
||||
if (const std::string path_old = path + ".old";
|
||||
!fs::copy_file(path, path_old, true))
|
||||
{
|
||||
patch_log.error("Could not back up current patches to %s", path_old);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite current patch file
|
||||
@ -909,7 +958,7 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||
else
|
||||
{
|
||||
patch_log.error("Could not save new patches to %s", path);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
refresh();
|
||||
@ -920,5 +969,7 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||
QMessageBox::critical(this, tr("Validation failed"), tr("Errors were found in the downloaded patch file.\n\nLog:\n%0").arg(QString::fromStdString(log_message.str())));
|
||||
}
|
||||
|
||||
patch_log.success("Successfully downloaded latest patch file");
|
||||
QMessageBox::information(this, tr("Download successful"), tr("Your patch file is now up to date"));
|
||||
return true;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include "rpcs3_version.h"
|
||||
#include "downloader.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Crypto/sha256.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include <QApplication>
|
||||
@ -249,22 +248,8 @@ bool update_manager::handle_rpcs3(const QByteArray& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 res_hash[32];
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts_ret(&ctx, 0);
|
||||
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(data.data()), data.size());
|
||||
mbedtls_sha256_finish_ret(&ctx, res_hash);
|
||||
|
||||
std::string res_hash_string("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
for (size_t index = 0; index < 32; index++)
|
||||
{
|
||||
constexpr auto pal = "0123456789ABCDEF";
|
||||
res_hash_string[index * 2] = pal[res_hash[index] >> 4];
|
||||
res_hash_string[(index * 2) + 1] = pal[res_hash[index] & 15];
|
||||
}
|
||||
|
||||
if (m_expected_hash != res_hash_string)
|
||||
if (const std::string res_hash_string = downloader::get_hash(data.data(), data.size(), false);
|
||||
m_expected_hash != res_hash_string)
|
||||
{
|
||||
update_log.error("Hash mismatch: %s expected: %s", res_hash_string, m_expected_hash);
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user