Tools/Extractors: Load additional tact keys from wow.tools (optional for extracting)

This commit is contained in:
Shauren
2020-11-06 00:27:01 +01:00
parent 6b6d5aff05
commit 587ec1fd21
2 changed files with 118 additions and 10 deletions

View File

@@ -16,8 +16,16 @@
*/
#include "CascHandles.h"
#include "IoContext.h"
#include "Resolver.h"
#include <CascLib.h>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/filesystem/operations.hpp>
#include <string>
char const* CASC::HumanReadableCASCError(uint32 error)
{
@@ -43,10 +51,113 @@ char const* CASC::HumanReadableCASCError(uint32 error)
}
}
namespace
{
Optional<std::string> DownloadFile(std::string const& serverName, int16 port, std::string const& getCommand)
{
boost::system::error_code error;
Trinity::Asio::IoContext ioContext;
boost::asio::ssl::context sslContext(boost::asio::ssl::context::sslv23);
sslContext.set_options(boost::asio::ssl::context::no_sslv2, error);
sslContext.set_options(boost::asio::ssl::context::no_sslv3, error);
sslContext.set_options(boost::asio::ssl::context::no_tlsv1, error);
sslContext.set_options(boost::asio::ssl::context::no_tlsv1_1, error);
sslContext.set_default_verify_paths(error);
boost::asio::ip::tcp::resolver resolver(ioContext);
Optional<boost::asio::ip::tcp::endpoint> endpoint = Trinity::Net::Resolve(resolver, boost::asio::ip::tcp::v4(), serverName, std::to_string(port));
if (!endpoint)
return {};
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(ioContext, sslContext);
socket.set_verify_mode(boost::asio::ssl::verify_none, error);
if (error)
return {};
socket.lowest_layer().connect(*endpoint, error);
if (error)
return {};
if (!SSL_set_tlsext_host_name(socket.native_handle(), serverName.c_str()))
return {};
socket.handshake(boost::asio::ssl::stream_base::client, error);
if (error)
return {};
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << getCommand << " HTTP/1.0\r\n";
request_stream << "Host: " << serverName << "\r\n";
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
// Read the response status line.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::string http_version;
uint32 status_code;
std::string status_message;
std::istream response_stream(&response);
response_stream >> http_version;
response_stream >> status_code;
std::getline(response_stream, status_message);
if (status_code != 200)
{
printf("Downloading tact key list failed with server response %u %s", status_code, status_message.c_str());
return {};
}
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r")
{
}
std::stringstream rawBody;
// Write whatever content we already have to output.
if (response.size() > 0)
rawBody << &response;
// Read until EOF, writing data to output as we go.
while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error))
rawBody << &response;
return rawBody.str();
}
template<typename T>
bool GetStorageInfo(HANDLE storage, CASC_STORAGE_INFO_CLASS storageInfoClass, T* value)
{
size_t infoDataSizeNeeded = 0;
return ::CascGetStorageInfo(storage, storageInfoClass, value, sizeof(T), &infoDataSizeNeeded);
}
}
CASC::Storage::Storage(HANDLE handle) : _handle(handle)
{
}
bool CASC::Storage::LoadOnlineTactKeys()
{
// attempt to download only once, not every storage opening
static Optional<std::string> const tactKeys = DownloadFile("wow.tools", 443, "/api.php?type=tactkeys");
return tactKeys && CascImportKeysFromString(_handle, tactKeys->c_str());
}
CASC::Storage::~Storage()
{
::CascCloseStorage(_handle);
@@ -71,17 +182,12 @@ CASC::Storage* CASC::Storage::Open(boost::filesystem::path const& path, uint32 l
}
printf("Opened casc storage '%s'\n", path.string().c_str());
return new Storage(handle);
}
Storage* storage = new Storage(handle);
namespace CASC
{
template<typename T>
static bool GetStorageInfo(HANDLE storage, CASC_STORAGE_INFO_CLASS storageInfoClass, T* value)
{
size_t infoDataSizeNeeded = 0;
return ::CascGetStorageInfo(storage, storageInfoClass, value, sizeof(T), &infoDataSizeNeeded);
}
if (!storage->LoadOnlineTactKeys())
printf("Failed to load additional encryption keys from wow.tools, some files might not be extracted.\n");
return storage;
}
uint32 CASC::Storage::GetBuildNumber() const

View File

@@ -53,6 +53,8 @@ namespace CASC
private:
Storage(HANDLE handle);
bool LoadOnlineTactKeys();
HANDLE _handle;
};