diff options
-rw-r--r-- | src/tools/extractor_common/CascHandles.cpp | 126 | ||||
-rw-r--r-- | src/tools/extractor_common/CascHandles.h | 2 |
2 files changed, 118 insertions, 10 deletions
diff --git a/src/tools/extractor_common/CascHandles.cpp b/src/tools/extractor_common/CascHandles.cpp index 868c4af27c5..c4ff0db19db 100644 --- a/src/tools/extractor_common/CascHandles.cpp +++ b/src/tools/extractor_common/CascHandles.cpp @@ -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 diff --git a/src/tools/extractor_common/CascHandles.h b/src/tools/extractor_common/CascHandles.h index 357d39a124e..cf40020feb6 100644 --- a/src/tools/extractor_common/CascHandles.h +++ b/src/tools/extractor_common/CascHandles.h @@ -53,6 +53,8 @@ namespace CASC private: Storage(HANDLE handle); + bool LoadOnlineTactKeys(); + HANDLE _handle; }; |