From c27d7326557b302ef12f0960a7053d589af18e24 Mon Sep 17 00:00:00 2001 From: Peter Sykora Date: Mon, 15 Nov 2021 00:10:53 +0100 Subject: [PATCH] [impl] Support for online activation --- .../CCServer.cpp | 0 {CMakeProject1 => CCEngineServer}/CCServer.h | 0 .../CMakeLists.txt | 17 +- .../CryptoUtils.cpp | 0 .../CryptoUtils.h | 0 CCEngineServer/HTTPClient.cpp | 321 ++++++++++++++++++ CCEngineServer/HTTPClient.h | 24 ++ .../HashUtils.cpp | 0 {CMakeProject1 => CCEngineServer}/HashUtils.h | 0 .../JSONSerialization.cpp | 0 .../JSONSerialization.h | 0 .../LicenseClient.cpp | 81 ++++- .../LicenseClient.h | 5 +- {CMakeProject1 => CCEngineServer}/OSUtils.h | 0 .../OSUtils_win.cpp | 0 .../SystemParams.cpp | 0 .../SystemParams.h | 0 .../SystemParamsProvider.h | 0 .../SystemParamsProvider_linux.cpp | 0 .../SystemParamsProvider_linux.h | 0 .../SystemParamsProvider_win.cpp | 0 .../SystemParamsProvider_win.h | 0 .../conanfile.txt | 5 +- .../main.cpp | 98 +++++- CCEngineServer/version.h | 2 + CMakeLists.txt | 4 +- CMakeProject1/CMakeProject1.h | 8 - 27 files changed, 542 insertions(+), 23 deletions(-) rename {CMakeProject1 => CCEngineServer}/CCServer.cpp (100%) rename {CMakeProject1 => CCEngineServer}/CCServer.h (100%) rename {CMakeProject1 => CCEngineServer}/CMakeLists.txt (64%) rename {CMakeProject1 => CCEngineServer}/CryptoUtils.cpp (100%) rename {CMakeProject1 => CCEngineServer}/CryptoUtils.h (100%) create mode 100644 CCEngineServer/HTTPClient.cpp create mode 100644 CCEngineServer/HTTPClient.h rename {CMakeProject1 => CCEngineServer}/HashUtils.cpp (100%) rename {CMakeProject1 => CCEngineServer}/HashUtils.h (100%) rename {CMakeProject1 => CCEngineServer}/JSONSerialization.cpp (100%) rename {CMakeProject1 => CCEngineServer}/JSONSerialization.h (100%) rename {CMakeProject1 => CCEngineServer}/LicenseClient.cpp (89%) rename {CMakeProject1 => CCEngineServer}/LicenseClient.h (85%) rename {CMakeProject1 => CCEngineServer}/OSUtils.h (100%) rename {CMakeProject1 => CCEngineServer}/OSUtils_win.cpp (100%) rename {CMakeProject1 => CCEngineServer}/SystemParams.cpp (100%) rename {CMakeProject1 => CCEngineServer}/SystemParams.h (100%) rename {CMakeProject1 => CCEngineServer}/SystemParamsProvider.h (100%) rename {CMakeProject1 => CCEngineServer}/SystemParamsProvider_linux.cpp (100%) rename {CMakeProject1 => CCEngineServer}/SystemParamsProvider_linux.h (100%) rename {CMakeProject1 => CCEngineServer}/SystemParamsProvider_win.cpp (100%) rename {CMakeProject1 => CCEngineServer}/SystemParamsProvider_win.h (100%) rename {CMakeProject1 => CCEngineServer}/conanfile.txt (56%) rename CMakeProject1/CMakeProject1.cpp => CCEngineServer/main.cpp (50%) create mode 100644 CCEngineServer/version.h delete mode 100644 CMakeProject1/CMakeProject1.h diff --git a/CMakeProject1/CCServer.cpp b/CCEngineServer/CCServer.cpp similarity index 100% rename from CMakeProject1/CCServer.cpp rename to CCEngineServer/CCServer.cpp diff --git a/CMakeProject1/CCServer.h b/CCEngineServer/CCServer.h similarity index 100% rename from CMakeProject1/CCServer.h rename to CCEngineServer/CCServer.h diff --git a/CMakeProject1/CMakeLists.txt b/CCEngineServer/CMakeLists.txt similarity index 64% rename from CMakeProject1/CMakeLists.txt rename to CCEngineServer/CMakeLists.txt index 2e89ad5..a7b1289 100644 --- a/CMakeProject1/CMakeLists.txt +++ b/CCEngineServer/CMakeLists.txt @@ -1,4 +1,4 @@ -# CMakeList.txt : CMake project for CMakeProject1, include source and define +# CMakeList.txt : CMake project for CCEngineServer, include source and define # project specific logic here. # cmake_minimum_required (VERSION 3.8) @@ -30,8 +30,19 @@ else(WIN32) endif() # Add source to this project's executable. -add_executable (CMakeProject1 "CCServer.cpp" "CCServer.h" "CryptoUtils.cpp" "CryptoUtils.h" "CMakeProject1.cpp" "CMakeProject1.h" "HashUtils.cpp" "HashUtils.h" "JSONSerialization.cpp" "JSONSerialization.h" "LicenseClient.cpp" "LicenseClient.h" "SystemParams.cpp" "SystemParams.h" "SystemParamsProvider.h" "SystemParamsProvider_win.cpp" "SystemParamsProvider_win.h" "SystemParamsProvider_linux.cpp" "SystemParamsProvider_win.cpp" "OSUtils.h" "OSUtils_win.cpp") +add_executable ( + CCEngineServer + "CCServer.cpp" "CCServer.h" + "CryptoUtils.cpp" "CryptoUtils.h" + "HashUtils.cpp" "HashUtils.h" + "HTTPClient.cpp" "HTTPClient.h" + "JSONSerialization.cpp" "JSONSerialization.h" + "LicenseClient.cpp" "LicenseClient.h" + "SystemParams.cpp" "SystemParams.h" + "SystemParamsProvider.h" "SystemParamsProvider_win.cpp" "SystemParamsProvider_win.h" "SystemParamsProvider_linux.cpp" "SystemParamsProvider_win.cpp" + "OSUtils.h" "OSUtils_win.cpp" + "main.cpp" "version.h") -target_link_libraries(CMakeProject1 ${CONAN_LIBS}) +target_link_libraries(CCEngineServer ${CONAN_LIBS}) # TODO: Add tests and install targets if needed. diff --git a/CMakeProject1/CryptoUtils.cpp b/CCEngineServer/CryptoUtils.cpp similarity index 100% rename from CMakeProject1/CryptoUtils.cpp rename to CCEngineServer/CryptoUtils.cpp diff --git a/CMakeProject1/CryptoUtils.h b/CCEngineServer/CryptoUtils.h similarity index 100% rename from CMakeProject1/CryptoUtils.h rename to CCEngineServer/CryptoUtils.h diff --git a/CCEngineServer/HTTPClient.cpp b/CCEngineServer/HTTPClient.cpp new file mode 100644 index 0000000..51e8345 --- /dev/null +++ b/CCEngineServer/HTTPClient.cpp @@ -0,0 +1,321 @@ +#include "HTTPClient.h" + +struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive- +#include + +#include +#include +#include + +namespace +{ + + static + void dump(const char *text, + FILE *stream, unsigned char *ptr, size_t size) + { + unsigned int width = 0x10; + + fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", + text, (long)size, (long)size); + + fwrite(ptr, 1, size, stream); + fputc('\n', stream); // newline + } + + static + int my_trace(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) + { + const char *text; + (void)handle; /* prevent compiler warning */ + (void)userp; + + switch (type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + } + + dump(text, stderr, (unsigned char *)data, size); + return 0; + } + +static size_t reader(char *ptr, size_t size, size_t nmemb, std::istream *is) +{ + std::streamsize totalRead = 0; + if (*is) + { + is->read(&ptr[totalRead], size * nmemb - totalRead); +// is->read(&ptr[totalRead], 1); + totalRead = is->gcount(); + } + + return static_cast(totalRead); +} + +static size_t writer(char *data, size_t size, size_t nmemb, std::ostream *os) +{ + if (os == NULL) + return 0; + + os->write(data, size*nmemb); + + return size * nmemb; +} + +struct CURLDeleter +{ + void operator() (CURL* ptr) + { + if (ptr) + { + curl_easy_cleanup(ptr); + } + } +}; + +struct curl_slist_deleter +{ + void operator() (curl_slist* ptr) + { + if (ptr) + { + curl_slist_free_all(ptr); + } + } +}; + +struct DownloadSession +{ + char errorBuffer[CURL_ERROR_SIZE] = { 0 }; + std::unique_ptr conn; + std::unique_ptr extraHeaders; +}; + +DownloadSession initCurlRequest(const std::string& url, std::ostream &os) +{ + DownloadSession result; + CURLcode code; + + std::unique_ptr conn(curl_easy_init()); + + if (!conn) + { + throw std::runtime_error("Failed to create CURL connection"); + } + + code = curl_easy_setopt(conn.get(), CURLOPT_ERRORBUFFER, result.errorBuffer); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set error buffer [" << code << "]"; + throw std::runtime_error(oss.str()); + } + + const char* errorBuffer = result.errorBuffer; + code = curl_easy_setopt(conn.get(), CURLOPT_URL, url.c_str()); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set URL [" << errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + code = curl_easy_setopt(conn.get(), CURLOPT_FOLLOWLOCATION, 1L); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set redirect option [" << errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + code = curl_easy_setopt(conn.get(), CURLOPT_MAXREDIRS, 5L); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set maximum number of redirects [" << errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + code = curl_easy_setopt(conn.get(), CURLOPT_WRITEFUNCTION, writer); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set write function [" << errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + code = curl_easy_setopt(conn.get(), CURLOPT_WRITEDATA, &os); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set write data [" << errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + +#ifndef NDEBUG + code = curl_easy_setopt(conn.get(), CURLOPT_DEBUGFUNCTION, my_trace); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set debug function"; + throw std::runtime_error(oss.str()); + } + code = curl_easy_setopt(conn.get(), CURLOPT_VERBOSE, 1); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set verbose mode"; + throw std::runtime_error(oss.str()); + } +#endif // !NDEBUG + + result.conn = std::move(conn); + + return result; +} + +DownloadSession initCurlPostJsonRequest(const std::string& url, std::istream& is, size_t length, std::ostream &os) +{ + DownloadSession result = initCurlRequest(url, os); + CURLcode code; + + auto contentLengthHeader = std::string("Content-Length: ") + std::to_string(length); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Accept: application/json"); + headers = curl_slist_append(headers, "Content-Type: application/json"); + headers = curl_slist_append(headers, contentLengthHeader.c_str()); + headers = curl_slist_append(headers, "Charsets: utf-8"); + result.extraHeaders.reset(headers); + + code = curl_easy_setopt(result.conn.get(), CURLOPT_POST, 1L); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set post option [" << result.errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + code = curl_easy_setopt(result.conn.get(), CURLOPT_HTTPHEADER, result.extraHeaders.get()); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set http headers [" << result.errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + code = curl_easy_setopt(result.conn.get(), CURLOPT_READFUNCTION, reader); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set read function [" << result.errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + code = curl_easy_setopt(result.conn.get(), CURLOPT_READDATA, &is); + if (code != CURLE_OK) + { + std::ostringstream oss; + oss << "Failed to set read data [" << result.errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + + return result; +} + +} // anonymous namespace + +HTTPClient::HTTPClient() +{ + curl_global_init(CURL_GLOBAL_DEFAULT); +} + +void HTTPClient::get(const std::string& url, std::ostream& dstStream) +{ + auto session = initCurlRequest(url, dstStream); + + auto code = curl_easy_perform(session.conn.get()); + + if (code != CURLE_OK) + { + session.conn.release(); + if (code == CURLE_COULDNT_CONNECT) + { + throw CouldNotConnectException(); + } + + std::ostringstream oss; + oss << "Failed to get '" << url << "' [" << session.errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + else + { + long http_code = 0; + curl_easy_getinfo(session.conn.get(), CURLINFO_RESPONSE_CODE, &http_code); + if (http_code >= 400) + { + std::ostringstream oss; + oss << "Failed to get '" << url << "' [HTTP code: " << http_code << "]"; + throw std::runtime_error(oss.str()); + } + } +} + +void HTTPClient::postJson(const std::string& url, std::istream& json, size_t length, std::ostream& dstStream) +{ + auto session = initCurlPostJsonRequest(url, json, length, dstStream); + + auto code = curl_easy_perform(session.conn.get()); + + if (code != CURLE_OK) + { + session.conn.release(); + if (code == CURLE_COULDNT_CONNECT) + { + throw CouldNotConnectException(); + } + std::ostringstream oss; + oss << "Failed to post '" << url << "' [" << session.errorBuffer << "]"; + throw std::runtime_error(oss.str()); + } + else + { + long http_code = 0; + curl_easy_getinfo(session.conn.get(), CURLINFO_RESPONSE_CODE, &http_code); + if (http_code >= 400) + { + std::ostringstream oss; + oss << "Failed to get '" << url << "' [HTTP code: " << http_code << "]"; + throw std::runtime_error(oss.str()); + } + } +} + +void HTTPClient::postJson(const std::string& url, const std::string& json, std::ostream& dstStream) +{ + std::istringstream is(json); + return postJson(url, is, json.size(), dstStream); +} diff --git a/CCEngineServer/HTTPClient.h b/CCEngineServer/HTTPClient.h new file mode 100644 index 0000000..86342ad --- /dev/null +++ b/CCEngineServer/HTTPClient.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +class CouldNotConnectException : public std::exception +{ +public: + CouldNotConnectException() + {} + + virtual ~CouldNotConnectException() throw () {} +}; + +class HTTPClient +{ +public: + HTTPClient(); + +public: + void get(const std::string& url, std::ostream& dstStream); + void postJson(const std::string& url, std::istream& json, size_t length, std::ostream& dstStream); + void postJson(const std::string& url, const std::string& json, std::ostream& dstStream); +}; diff --git a/CMakeProject1/HashUtils.cpp b/CCEngineServer/HashUtils.cpp similarity index 100% rename from CMakeProject1/HashUtils.cpp rename to CCEngineServer/HashUtils.cpp diff --git a/CMakeProject1/HashUtils.h b/CCEngineServer/HashUtils.h similarity index 100% rename from CMakeProject1/HashUtils.h rename to CCEngineServer/HashUtils.h diff --git a/CMakeProject1/JSONSerialization.cpp b/CCEngineServer/JSONSerialization.cpp similarity index 100% rename from CMakeProject1/JSONSerialization.cpp rename to CCEngineServer/JSONSerialization.cpp diff --git a/CMakeProject1/JSONSerialization.h b/CCEngineServer/JSONSerialization.h similarity index 100% rename from CMakeProject1/JSONSerialization.h rename to CCEngineServer/JSONSerialization.h diff --git a/CMakeProject1/LicenseClient.cpp b/CCEngineServer/LicenseClient.cpp similarity index 89% rename from CMakeProject1/LicenseClient.cpp rename to CCEngineServer/LicenseClient.cpp index f01d025..2af40dc 100644 --- a/CMakeProject1/LicenseClient.cpp +++ b/CCEngineServer/LicenseClient.cpp @@ -58,6 +58,7 @@ namespace { static const std::string productId = "cocserver"; +static const std::string serverPath = "https://license.apis.sk/api/v1"; static const uint32_t initializationVectorSize = AES::BLOCKSIZE; static const uint32_t macTagSize = 16; @@ -228,7 +229,15 @@ void serialize(std::ostream& os, const ActivationRequest& a) void deserialize(const pt::ptree& tree, ActivationResponse& a) { - deserialize(tree.get_child("success"), a.success); + auto successNode = tree.get_child_optional("success"); + if (successNode) + { + deserialize(successNode.value(), a.success); + } + else + { + a.success = false; + } auto licenseFileOpt = tree.get_child_optional("licenseFile"); if (licenseFileOpt) { @@ -277,7 +286,7 @@ void LicenseClient::init() loadActivationData(); } -std::string LicenseClient::buildActivationRequest() +std::string LicenseClient::buildOfflineActivationRequest() { PreactivationRequest req{ productId, m_systemParams }; @@ -324,6 +333,74 @@ std::string LicenseClient::buildActivationRequest() std::string("-----END ACTIVATION REQUEST-----\n"); } +bool LicenseClient::tryPreactivate(HTTPClient &httpClient) +{ + PreactivationRequest req{ productId, m_systemParams }; + + std::string jsonReq; + { + std::ostringstream ss1; + serialize(ss1, req); + jsonReq = ss1.str(); + } + + std::string jsonRes; + { + std::ostringstream ss2; + httpClient.postJson(serverPath + "/activate0", jsonReq, ss2); + jsonRes = ss2.str(); + } + + ActivationResponse activationResponse; + pt::ptree root; + std::istringstream ss2(jsonRes); + pt::read_json(ss2, root); + deserialize(root, activationResponse); + if (activationResponse.success) + { + { + const auto& licenseData = activationResponse.licenseFile.value(); + std::ofstream os(m_licenseFile, std::ofstream::binary); + os.write(licenseData.data(), licenseData.size()); + } + return loadActivationData(); + } + return false; +} + +bool LicenseClient::activate(HTTPClient &httpClient, const std::string & licenseNumber) +{ + auto validLicenseKey = validateLicenseKey(licenseNumber); + if (!validLicenseKey) + { + return false; + } + + std::ostringstream ss1; + + ActivationRequest req{ productId, m_systemParams, validLicenseKey.value() }; + serialize(ss1, req); + + std::stringstream ss2; + httpClient.postJson(serverPath + "/activate", ss1.str() , ss2); + + ActivationResponse activationResponse; + pt::ptree root; + pt::read_json(ss2, root); + deserialize(root, activationResponse); + if (activationResponse.success) + { + { + const auto& licenseData = activationResponse.licenseFile.value(); + std::ofstream os(m_licenseFile, std::ofstream::binary); + os.write(licenseData.data(), licenseData.size()); + } + return loadActivationData(); + } + return false; +} + + bool LicenseClient::loadActivationData() { if (fs::is_regular_file(m_licenseFile)) diff --git a/CMakeProject1/LicenseClient.h b/CCEngineServer/LicenseClient.h similarity index 85% rename from CMakeProject1/LicenseClient.h rename to CCEngineServer/LicenseClient.h index e690244..73b9bcf 100644 --- a/CMakeProject1/LicenseClient.h +++ b/CCEngineServer/LicenseClient.h @@ -1,5 +1,6 @@ #pragma once +#include "HTTPClient.h" #include "SystemParamsProvider.h" #include @@ -25,9 +26,11 @@ public: public: void init(); - std::string buildActivationRequest(); + std::string buildOfflineActivationRequest(); bool isActivated() const { return m_activationData.has_value(); } std::optional activationNumber() const { return m_activationData.has_value() ? m_activationData->activationId : std::optional(); } + bool tryPreactivate(HTTPClient &httpClient); + bool activate(HTTPClient &httpClient, const std::string& licenseNumber ); auto licensedModules() { if (!isActivated()) { throw std::runtime_error("Not active"); } return m_activationData->licensedModules; } private: diff --git a/CMakeProject1/OSUtils.h b/CCEngineServer/OSUtils.h similarity index 100% rename from CMakeProject1/OSUtils.h rename to CCEngineServer/OSUtils.h diff --git a/CMakeProject1/OSUtils_win.cpp b/CCEngineServer/OSUtils_win.cpp similarity index 100% rename from CMakeProject1/OSUtils_win.cpp rename to CCEngineServer/OSUtils_win.cpp diff --git a/CMakeProject1/SystemParams.cpp b/CCEngineServer/SystemParams.cpp similarity index 100% rename from CMakeProject1/SystemParams.cpp rename to CCEngineServer/SystemParams.cpp diff --git a/CMakeProject1/SystemParams.h b/CCEngineServer/SystemParams.h similarity index 100% rename from CMakeProject1/SystemParams.h rename to CCEngineServer/SystemParams.h diff --git a/CMakeProject1/SystemParamsProvider.h b/CCEngineServer/SystemParamsProvider.h similarity index 100% rename from CMakeProject1/SystemParamsProvider.h rename to CCEngineServer/SystemParamsProvider.h diff --git a/CMakeProject1/SystemParamsProvider_linux.cpp b/CCEngineServer/SystemParamsProvider_linux.cpp similarity index 100% rename from CMakeProject1/SystemParamsProvider_linux.cpp rename to CCEngineServer/SystemParamsProvider_linux.cpp diff --git a/CMakeProject1/SystemParamsProvider_linux.h b/CCEngineServer/SystemParamsProvider_linux.h similarity index 100% rename from CMakeProject1/SystemParamsProvider_linux.h rename to CCEngineServer/SystemParamsProvider_linux.h diff --git a/CMakeProject1/SystemParamsProvider_win.cpp b/CCEngineServer/SystemParamsProvider_win.cpp similarity index 100% rename from CMakeProject1/SystemParamsProvider_win.cpp rename to CCEngineServer/SystemParamsProvider_win.cpp diff --git a/CMakeProject1/SystemParamsProvider_win.h b/CCEngineServer/SystemParamsProvider_win.h similarity index 100% rename from CMakeProject1/SystemParamsProvider_win.h rename to CCEngineServer/SystemParamsProvider_win.h diff --git a/CMakeProject1/conanfile.txt b/CCEngineServer/conanfile.txt similarity index 56% rename from CMakeProject1/conanfile.txt rename to CCEngineServer/conanfile.txt index 4354a98..dcc4d11 100644 --- a/CMakeProject1/conanfile.txt +++ b/CCEngineServer/conanfile.txt @@ -1,6 +1,7 @@ [requires] -boost/1.76.0 +boost/1.77.0 cryptopp/8.5.0 +libcurl/7.79.1 [generators] cmake @@ -8,3 +9,5 @@ cmake [options] boost:shared=False cryptopp:shared=False +libcurl:shared=False +libcurl:with_ssl=openssl diff --git a/CMakeProject1/CMakeProject1.cpp b/CCEngineServer/main.cpp similarity index 50% rename from CMakeProject1/CMakeProject1.cpp rename to CCEngineServer/main.cpp index 9ef0af1..0694f60 100644 --- a/CMakeProject1/CMakeProject1.cpp +++ b/CCEngineServer/main.cpp @@ -2,6 +2,7 @@ #include "LicenseClient.h" #include "SystemParamsProvider.h" +#include "version.h" #include #include @@ -26,7 +27,7 @@ namespace keywords = boost::log::keywords; volatile bool signalCaught = false; void signalHandler(int signum) { - std::cout << "Interrupt signal (" << signum << ") received.\n"; + BOOST_LOG_TRIVIAL(info) << "Interrupt signal (" << signum << ") received."; signalCaught = true; } @@ -60,6 +61,13 @@ int main(int argc, const char* argv[]) po::options_description generalOptions("General options"); generalOptions.add_options() ("help", "produce help message") + ("version", "print application version") + ("activate_online", "activate online") + ("activate_offline", "start offline activation process") +#ifndef WIN32 + ("set_uid", po::value()->default_value(0), "Switch UID after successfull startup") + ("set_gid", po::value()->default_value(0), "Switch GID after successfull startup") +#endif ("bind_ip", po::value()->default_value("0.0.0.0"), "ip address to listen for connections") ("port", po::value()->default_value(8080), "port") ("data_root", po::value()->default_value("."), "root directory with data") @@ -80,7 +88,14 @@ int main(int argc, const char* argv[]) po::notify(vm); if (vm.count("help")) { - std::cout << generalOptions << "\n"; + std::cout << "CCEngineServer - Catalogue of Currencies serving solution" << std::endl; + std::cout << COPYRIGHT_NOTICE << std::endl << std::endl; + std::cout << generalOptions << std::endl; + return 1; + } + + if (vm.count("version")) { + std::cout << VERSION << std::endl; return 1; } @@ -97,11 +112,82 @@ int main(int argc, const char* argv[]) LicenseClient licenseClient(systemParamsProvider, "license.dat"); licenseClient.init(); +#ifndef WIN32 + auto gidToSet = vm["set_gid"].as(); + if (gidToSet > 0 && setgid(gidToSet) != 0) { + BOOST_LOG_TRIVIAL(error) << "Failed to set group id: " << gidToSet; + return -11; + } + + auto uidToSet = vm["set_uid"].as(); + if (uidToSet > 0 && setuid(uidToSet) != 0) { + BOOST_LOG_TRIVIAL(error) << "Failed to set user id: " << uidToSet; + return -10; + } +#endif + + if (vm.count("activate_online")) { + HTTPClient httpClient; + + try { + if (licenseClient.tryPreactivate(httpClient)) { + std::cout << "Pre-activation successfull. Please go ahead with normal application start" << std::endl; + return 3; + } + } + catch (CouldNotConnectException& e){ + BOOST_LOG_TRIVIAL(error) << "Connection to server failed. Please check your internet" + << "connection.If the problem persists, please contact customer support."; + BOOST_LOG_TRIVIAL(error) << e.what(); + return -5; + } + catch (std::runtime_error &e) { + BOOST_LOG_TRIVIAL(error) << "Pre-activate failed. Please retry and if the problem persists, please contact customer support."; + BOOST_LOG_TRIVIAL(debug) << e.what(); + return -6; + } + BOOST_LOG_TRIVIAL(info) << "Automatic pre-activation failed. Requesting license number..."; + + std::string licenseNumber; + std::cout << "Please enter license number (format XXXX-XXXX-XXXX-XXXX-XXXX-XXXX):" << std::endl; + std::getline(std::cin, licenseNumber); + + std::cout << "Sending activation request to server..." << std::endl; + + try { + if (!licenseClient.activate(httpClient, licenseNumber)) { + std::cerr << "Activation failed" << std::endl; + return -2; + } + } + catch (CouldNotConnectException& e) { + BOOST_LOG_TRIVIAL(error) << "Connection to server failed. Please check your internet" + << "connection.If the problem persists, please contact customer support."; + BOOST_LOG_TRIVIAL(error) << e.what(); + return -3; + } + catch (std::runtime_error& e) { + BOOST_LOG_TRIVIAL(error) << "Activation failed. Please retry and if the problem persists, please contact customer support."; + BOOST_LOG_TRIVIAL(debug) << e.what(); + return -4; + } + + std::cout << "Activation successfull. Please go ahead with normal application start" << std::endl; + return 2; + } + + if (vm.count("activate_offline")) { + BOOST_LOG_TRIVIAL(debug) << "Offline activation was requested"; + std::cout << "Offline activation was requested"; + std::cout << "Copy following activation request and refer to the manual: " << std::endl + << licenseClient.buildOfflineActivationRequest() << std::endl; + + return 3; + } + if (!licenseClient.isActivated()) { - const std::string msg = "Application is not activated. Please contact Catalogue of Currencies support."; - BOOST_LOG_TRIVIAL(error) << msg << " Exiting..."; - std::cout << msg << std::endl; - std::cout << "Activation request: " << std::endl << licenseClient.buildActivationRequest() << std::endl; + BOOST_LOG_TRIVIAL(warning) << "Application is not activated. Please contact customer support."; + BOOST_LOG_TRIVIAL(info) << "Exiting..."; return -2; } diff --git a/CCEngineServer/version.h b/CCEngineServer/version.h new file mode 100644 index 0000000..76e4a00 --- /dev/null +++ b/CCEngineServer/version.h @@ -0,0 +1,2 @@ +#define VERSION "21.45" +#define COPYRIGHT_NOTICE "©2021 Apis spol. s r.o." diff --git a/CMakeLists.txt b/CMakeLists.txt index c87f5f9..6ff5774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,11 @@ if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") set (CMAKE_SYSTEM_VERSION 8.1 CACHE TYPE INTERNAL FORCE) #Force 8.1 SDK, to keep it compatible with win7 endif() -project ("CMakeProject1") +project ("CCEngineServer") IF(WIN32) ADD_DEFINITIONS(/bigobj) ENDIF(WIN32) # Include sub-projects. -add_subdirectory ("CMakeProject1") +add_subdirectory ("CCEngineServer") diff --git a/CMakeProject1/CMakeProject1.h b/CMakeProject1/CMakeProject1.h deleted file mode 100644 index 48103f7..0000000 --- a/CMakeProject1/CMakeProject1.h +++ /dev/null @@ -1,8 +0,0 @@ -// CMakeProject1.h : Include file for standard system include files, -// or project specific include files. - -#pragma once - -#include - -// TODO: Reference additional headers your program requires here.