diff --git a/engine/server/application/CentralServer/src/shared/CentralServer.cpp b/engine/server/application/CentralServer/src/shared/CentralServer.cpp index 8e39542c..949cd705 100755 --- a/engine/server/application/CentralServer/src/shared/CentralServer.cpp +++ b/engine/server/application/CentralServer/src/shared/CentralServer.cpp @@ -126,8 +126,6 @@ #include "webAPI.h" -using namespace StellaBellum; - namespace CentralServerNamespace { bool gs_connectionServersPublic=false; @@ -2941,7 +2939,7 @@ void CentralServer::sendPopulationUpdateToLoginServer() void CentralServer::sendMetricsToWebAPI() { - static const std::string metricsURL(ConfigCentralServer::getMetricsDataURL()); + /*static const std::string metricsURL(ConfigCentralServer::getMetricsDataURL()); if (!metricsURL.empty()) { @@ -2979,7 +2977,7 @@ void CentralServer::sendMetricsToWebAPI() #else api.submit(); #endif - } + }*/ } //----------------------------------------------------------------------- diff --git a/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp b/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp index e30109b2..54d2d0b7 100755 --- a/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp +++ b/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp @@ -56,8 +56,6 @@ #include "webAPI.h" -using namespace StellaBellum; - //----------------------------------------------------------------------- namespace ClientConnectionNamespace { @@ -269,137 +267,91 @@ void ClientConnection::handleGameServerForLoginMessage(uint32 serverId) { * to be validated. Central will reply with a list of permissions. * @see onIdValidated */ -void ClientConnection::handleClientIdMessage(const ClientIdMsg &msg) { - //Only check clients that have not been validated. - if (m_hasBeenValidated) { - return; - } +void ClientConnection::handleClientIdMessage(const ClientIdMsg& msg) +{ + //Only check clients that have not been validated. + if (m_hasBeenValidated) + return; - DEBUG_FATAL(m_hasSelectedCharacter, ("Trying to validate a client who already has a character selected.\n")); - bool result = false; - m_gameBitsToClear = msg.getGameBitsToClear(); + DEBUG_FATAL(m_hasSelectedCharacter, ("Trying to validate a client who already has a character selected.\n")); + bool result = false; + char sessionId[apiSessionIdWidth]; - if (msg.getTokenSize() > 0) { - Archive::ByteStream t(msg.getToken(), msg.getTokenSize()); - Archive::ReadIterator ri(t); - KeyShare::Token token(ri); - char sessionId[apiSessionIdWidth]; + m_gameBitsToClear = msg.getGameBitsToClear(); - if (!ConfigConnectionServer::getValidateStationKey()) { - // get SUID from token - result = ConnectionServer::decryptToken(token, m_suid, m_isSecure, m_accountName); - } else { - result = ConnectionServer::decryptToken(token, sessionId, m_requestedSuid); - } + if(msg.getTokenSize() > 0) + { + Archive::ByteStream t(msg.getToken(), msg.getTokenSize()); + Archive::ReadIterator ri(t); + KeyShare::Token token(ri); - static const std::string sessURL(ConfigConnectionServer::getSessionURL()); + if (!ConfigConnectionServer::getValidateStationKey()) + { + // get SUID from token + result = ConnectionServer::decryptToken(token, m_suid, m_isSecure, m_accountName); + } + else + { + result = ConnectionServer::decryptToken(token, sessionId, m_requestedSuid); + } - if (result || strlen(sessionId) != 0) { - if (ConfigConnectionServer::getValidateStationKey()) { - bool cont = false; - StationId apiSuid = 0; + static const std::string loginTrace("TRACE_LOGIN"); + LOG(loginTrace, ("ClientConnection SUID = %d", m_suid)); - FATAL(sessURL.empty(), ("Session URL is empty in connection server.")); + } + if (result) + { + // verify version + if (ConfigConnectionServer::getValidateClientVersion() && msg.getVersion() != GameNetworkMessage::NetworkVersionId) + { + std::string strSessionId(sessionId, apiSessionIdWidth); + strSessionId += '\0'; - const std::string clientIP(getRemoteAddress()); - const std::string sess(sessionId); + const int bufferSize = 255 + apiSessionIdWidth; + char * buffer = new char[bufferSize]; + snprintf(buffer, bufferSize-1, "network version mismatch: got (ip=[%s], sessionId=[%s], version=[%s]), required (version=[%s])", getRemoteAddress().c_str(), strSessionId.c_str(), msg.getVersion().c_str(), GameNetworkMessage::NetworkVersionId.c_str()); + buffer[bufferSize-1] = '\0'; - FATAL(clientIP.empty(), ("Remote IP is empty")); + ConnectionServer::dropClient(this, std::string(buffer)); + disconnect(); - DEBUG_WARNING(true, ("ConnectionServer::handleClientIdMessage - For ip %s suid is %lu requestedSUID is %lu and session is %s", clientIP.c_str(), m_suid, m_requestedSuid, sess.c_str())); + delete[] buffer; - webAPI api(sessURL); + return; + } - // add our data - api.addJsonData("session_key", sess); - - if (api.submit()) { - bool status = api.getNullableValue("status"); - - if (status) { - std::string apiUser = api.getString("user_name"); - std::string apiIP = api.getString("ip"); - int expired = api.getNullableValue("expired"); - - if (!ConfigConnectionServer::getUseOldSuidGenerator()) { - apiSuid = api.getNullableValue("user_id"); - } else { - if (apiUser.length() > MAX_ACCOUNT_NAME_LENGTH) { - apiUser.resize(MAX_ACCOUNT_NAME_LENGTH); - } - apiSuid = std::hash < std::string > {}(apiUser.c_str()); - } - - if (apiIP == clientIP && expired == 0) { - m_suid = apiSuid; - cont = true; - } - } - } - - if (!cont) { - LOG("ClientDisconnect", ("SUID %d (%d) passed a bad token to the connections erver. Disconnecting.", m_suid, apiSuid)); - disconnect(); - return; - } - } - - static const std::string loginTrace("TRACE_LOGIN"); - LOG(loginTrace, ("ClientConnection SUID = %d", m_suid)); - - //check for duplicate login - ClientConnection *oldConnection = ConnectionServer::getClientConnection(m_suid); - if (oldConnection) { - //There is already someone connected to this cluster with this suid. - LOG("Network", ("SUID %d already logged in, disconnecting client.\n", m_suid)); - - ConnectionServer::dropClient(oldConnection, "Already Connected"); - - disconnect(); - return; - } - - // verify version - if (ConfigConnectionServer::getValidateClientVersion() && - msg.getVersion() != GameNetworkMessage::NetworkVersionId) { - std::string strSessionId(sessionId, apiSessionIdWidth); - strSessionId += '\0'; - - const int bufferSize = 255 + apiSessionIdWidth; - char *buffer = new char[bufferSize]; - snprintf(buffer, bufferSize - - 1, "network version mismatch: got (ip=[%s], sessionId=[%s], version=[%s]), required (version=[%s])", getRemoteAddress().c_str(), strSessionId.c_str(), msg.getVersion().c_str(), GameNetworkMessage::NetworkVersionId.c_str()); - buffer[bufferSize - 1] = '\0'; - - ConnectionServer::dropClient(this, std::string(buffer)); - disconnect(); - - delete[] buffer; - - return; - } - - // test mode only - if (!m_suid && !ConfigConnectionServer::getValidateStationKey()) { - WARNING(true, ("Generating suid from username. This is not safe or secure.")); - - m_suid = atoi(m_accountName.c_str()); - - if (m_suid == 0) { - m_suid = std::hash < std::string > {}(m_accountName.c_str()); - } - } - - onValidateClient(m_suid, m_accountName, m_isSecure, nullptr, ConfigConnectionServer::getDefaultGameFeatures(), ConfigConnectionServer::getDefaultSubscriptionFeatures(), 0, 0, 0, 0, ConfigConnectionServer::getFakeBuddyPoints()); - } - } else { - WARNING(true, ("SUID %d passed a bad token to the connections server (cache issue or hacker?). Disconnecting.", m_suid)); - - // They sent us a token that was no good -- either a hack attempt, or - // possibly it was just too old. - LOG("ClientDisconnect", ("SUID %d passed a bad token to the connections server (cache issue or hacker?). Disconnecting.", m_suid)); - disconnect(); - } + if (ConfigConnectionServer::getValidateStationKey()) + { + SessionApiClient * session = ConnectionServer::getSessionApiClient(); + NOT_NULL(session); + if(session) + { + session->validateClient(this, sessionId); + } + else + { + ConnectionServer::dropClient(this, "SessionApiClient is not available!"); + disconnect(); + } + } + else + { + m_suid = atoi(m_accountName.c_str()); + if (m_suid == 0) + { + std::hash h; + m_suid = h(m_accountName.c_str()); + } + onValidateClient(m_suid, m_accountName, m_isSecure, nullptr, ConfigConnectionServer::getDefaultGameFeatures(), ConfigConnectionServer::getDefaultSubscriptionFeatures(), 0, 0, 0, 0, ConfigConnectionServer::getFakeBuddyPoints()); + } + } + else + { + // They sent us a token that was no good -- either a hack attempt, or + // possibly it was just too old. + LOG("ClientDisconnect", ("SUID %d passed a bad token to the connections erver. Disconnecting.", m_suid)); + disconnect(); + } } //----------------------------------------------------------------------- diff --git a/engine/server/application/LoginServer/src/shared/ClientConnection.cpp b/engine/server/application/LoginServer/src/shared/ClientConnection.cpp index d955e5eb..2bffc108 100755 --- a/engine/server/application/LoginServer/src/shared/ClientConnection.cpp +++ b/engine/server/application/LoginServer/src/shared/ClientConnection.cpp @@ -23,8 +23,6 @@ #include "webAPI.h" -using namespace StellaBellum; - //----------------------------------------------------------------------- ClientConnection::ClientConnection(UdpConnectionMT *u, TcpClient *t) @@ -150,127 +148,64 @@ void ClientConnection::onReceive(const Archive::ByteStream &message) { //----------------------------------------------------------------------- // originally was used to validate station API credentials, now uses our custom api -void ClientConnection::validateClient(const std::string &id, const std::string &key) { - bool authOK = false; - bool testMode = false; - static const std::string authURL(ConfigLoginServer::getExternalAuthUrl()); +void ClientConnection::validateClient(const std::string & id, const std::string & key) +{ + // to avoid having to re-type this stupid var all over the place + // ideally we wouldn't copy this here, but it would be a huge pain + const std::string trimmedId = trim(id); + const std::string trimmedKey = trim(key); - std::string uname; - std::string parentAccount; - std::string sessionID; + // and to avoid funny business with atoi and casing + // make it a separate var than the one we send the auth server + std::string lcaseId; + lcaseId.resize(trimmedId.size()); - StationId user_id; - StationId parent_id; - std::unordered_map childAccounts; + std::transform(trimmedId.begin(),trimmedId.end(),lcaseId.begin(),::tolower); - if (!authURL.empty()) { - // create the object - webAPI api(authURL); + StationId suid = atoi(lcaseId.c_str()); + int authOK = 0; - // add our data - api.addJsonData("user_name", id); - api.addJsonData("user_password", key); - api.addJsonData("ip", getRemoteAddress()); + if (suid == 0) + { + std::hash h; + suid = h(lcaseId.c_str()); //lint !e603 // Symbol 'h' not initialized (it's a functor) + } + + LOG("LoginClientConnection", ("validateClient() for stationId (%lu) at IP (%s), id (%s)", m_stationId, getRemoteAddress().c_str(), lcaseId.c_str())); - if (api.submit()) { - bool status = api.getNullableValue("status"); - uname = api.getString("username"); - sessionID = api.getString("session_key"); + std::string authURL(ConfigLoginServer::getExternalAuthUrl()); - if (status && !sessionID.empty() && !uname.empty()) { - authOK = true; + if (!authURL.empty()) + { + std::ostringstream postBuf; + postBuf << "user_name=" << trimmedId << "&user_password=" << trimmedKey << "&stationID=" << suid << "&ip=" << getRemoteAddress(); - parentAccount = api.getString("mainAccount"); - childAccounts = api.getStringMap("subAccounts"); + std::string response = webAPI::simplePost(authURL, std::string(postBuf.str()), ""); - if (!ConfigLoginServer::getUseOldSuidGenerator()) { - user_id = static_cast(api.getNullableValue("user_id")); - parent_id = static_cast(api.getNullableValue("parent_id")); - } else { - if (parentAccount.length() > MAX_ACCOUNT_NAME_LENGTH) { - parentAccount.resize(MAX_ACCOUNT_NAME_LENGTH); - } + if (response == "success") + { + authOK = 1; + } + else + { + ErrorMessage err("Login Failed", response); + this->send(err, true); + } + + } + else + { + authOK = 1; + } - if (uname.length() > MAX_ACCOUNT_NAME_LENGTH) { - uname.resize(MAX_ACCOUNT_NAME_LENGTH); - } - - parent_id = std::hash < std::string > {}(parentAccount.c_str()); - user_id = std::hash < std::string > {}(uname.c_str()); - } - } else { - std::string msg(api.getString("message")); - if (msg.empty()) { - msg = "Invalid username or password."; - } - - ErrorMessage err("Login Failed", msg); - this->send(err, true); - } - } else { - ErrorMessage err("Login Failed", "Could not connect to remote."); - this->send(err, true); - } - } else { - // test mode - authOK = true; - testMode = true; - uname = id; - - if (uname.length() > MAX_ACCOUNT_NAME_LENGTH) { - uname.resize(MAX_ACCOUNT_NAME_LENGTH); - } - - user_id = std::hash < std::string > {}(uname.c_str()); - } - - if (authOK) { - m_stationId = user_id; - - if (!testMode) { - REPORT_LOG(true, ("Client connected. Username: %s (%i) \n", uname.c_str(), user_id)); - - if (!parentAccount.empty()) { - if (parentAccount != uname) { - REPORT_LOG(true, ("\t%s's parent is %s (%i) \n", uname.c_str(), parentAccount.c_str(), parent_id)); - } - } else { - parentAccount = "(Empty Parent!) " + uname; - } - - for (auto i : childAccounts) { - StationId child_id = static_cast(i.first); - std::string child(i.second); - - if (!child.empty() && i.first > 0) { - if (ConfigLoginServer::getUseOldSuidGenerator()) { - if (child.length() > MAX_ACCOUNT_NAME_LENGTH) { - child.resize(MAX_ACCOUNT_NAME_LENGTH); - } - - child_id = std::hash < std::string > {}(child.c_str()); - } - - REPORT_LOG((parent_id != - child_id), ("\tchild of %s (%i) is %s (%i) \n", parentAccount.c_str(), parent_id, child.c_str(), child_id)); - - // insert all related accounts, if not already there, into the db - if (parent_id != child_id) { - DatabaseConnection::getInstance().upsertAccountRelationship(parent_id, child_id); - } - } else { - WARNING(true, ("Login API returned empty child account(s).")); - } - } - - LoginServer::getInstance().onValidateClient(m_stationId, uname, this, true, sessionID.c_str(), 0xFFFFFFFF, 0xFFFFFFFF); - } else { - LoginServer::getInstance().onValidateClient(m_stationId, uname, this, true, nullptr, 0xFFFFFFFF, 0xFFFFFFFF); - } - LOG("LoginClientConnection", ("validateClient() for stationId (%i) at IP (%s), id (%s)", user_id, getRemoteAddress().c_str(), uname.c_str())); - } + if (authOK) + { + LoginServer::getInstance().onValidateClient(suid, lcaseId, this, true, NULL, 0xFFFFFFFF, 0xFFFFFFFF); + } + // else this case will never be reached, noop } + // ---------------------------------------------------------------------------- /** diff --git a/external/3rd/library/webAPI/webAPI.cpp b/external/3rd/library/webAPI/webAPI.cpp index ab1cc028..b9637b03 100644 --- a/external/3rd/library/webAPI/webAPI.cpp +++ b/external/3rd/library/webAPI/webAPI.cpp @@ -1,207 +1,123 @@ /* - * Version: 1.75 - * - * This code is just a simple wrapper around nlohmann's wonderful json lib - * (https://github.com/nlohmann/json) and libcurl. While originally included directly, - * we have come to realize that we may require web API functionality elsewhere in the future. - * - * As such, and in an effort to keep the code clean, we've broken it out into this simple little - * namespace/lib that is easy to include. Just make sure to link against curl when including, and - * make all the cmake modifications required to properly use it. - * - * (c) DarthArgus - * based on the original prototype by parz1val - * - * License: LGPL, don't be a dick please - */ +This code is just a simple wrapper around nlohmann's wonderful json lib +(https://github.com/nlohmann/json) and libcurl. While originally included directly, +we have come to realize that we may require web API functionality elsewhere in the future. + +As such, and in an effort to keep the code clean, we've broken it out into this simple little +namespace/lib that is easy to include. Just make sure to link against curl when including, and +make all the cmake modifications required to properly use it. + +(c) stellabellum/swgilluminati (combined crews), written by DA with help from DC +based on the original prototype by parz1val + +License: what's a license? we're a bunch of dirty pirates! +*/ #include "webAPI.h" -using namespace StellaBellum; +using namespace std; -webAPI::webAPI(std::string endpoint, std::string userAgent) : uri(endpoint), userAgent(userAgent), statusCode(0) {} - -webAPI::~webAPI() { - requestData.clear(); - responseData.clear(); -} - -bool webAPI::setEndpoint(const std::string endpoint) { - uri = endpoint; - - return true; -} - -std::string webAPI::getRaw() { - return sResponse; -} - -bool webAPI::setData(std::string &data) { - if (!data.empty()) { - sRequest = data; - - return true; - } - - return false; -} - -std::string webAPI::getString(const std::string &slot) { - if (!responseData.empty() && !slot.empty() && responseData.count(slot) && !responseData[slot].is_null()) { - return responseData[slot].get(); - } - - return std::string(""); -} - -std::unordered_map webAPI::getStringMap(const std::string &slot) { - std::unordered_map ret = std::unordered_map(); - - if (!responseData.empty() && !slot.empty() && responseData.count(slot) && !responseData[slot].is_null()) { - - nlohmann::json j = responseData[slot]; - - for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) { - int k = std::stoi(it.key()); - std::string val = it.value(); - - ret.insert({k, val}); - } - } - - return ret; -} - -bool webAPI::submit(const int &reqType, const int &getPost, const int &respType) { - if (reqType == DTYPE::JSON) // json request - { - if (!requestData.empty()) { - // serialize our data into sRequest - sRequest = requestData.dump(); - - // clear our the object for next time - requestData.clear(); - } - } - - if (fetch(getPost, respType) && !(sResponse.empty())) { - return true; - } - - sResponse.clear(); - - return false; -} - -bool webAPI::fetch(const int &getPost, const int &mimeType) // 0 for json 1 for string +// if status == success, returns "success", or slotName's contents if specified... +// otherwise returns the "message" if no success +string webAPI::simplePost(string endpoint, string data, string slotName) { - bool fetchStatus = false; + // declare our output and go ahead and attempt to get data from remote + nlohmann::json response = request(endpoint, data, 1); + string output; - if (!uri.empty()) //data is allowed to be an empty string if we're doing a normal GET - { - CURL *curl = curl_easy_init(); // start up curl + // if we got data back... + if (response.count("status") && response["status"].get() == "success") + { + // use custom slot if specified (not "") + if (!(slotName.empty()) && response.count(slotName)) + { + output = response[slotName].get(); + } + else + { + output = "success"; + } + } + else //default message is an error, the other end always assumes "success" or the specified slot + { + if (response.count("message")) + { + output = response["message"].get(); + } + else + { + output = "Message not provided by remote."; + } + } - if (curl) { - std::string readBuffer = ""; // container for the remote response - struct curl_slist *slist = nullptr; + return output; +} - // set the content type - if (mimeType == DTYPE::JSON) { - slist = curl_slist_append(slist, "Accept: application/json"); - slist = curl_slist_append(slist, "Content-Type: application/json"); - } else { - slist = curl_slist_append(slist, "Content-Type: application/x-www-form-urlencoded"); - } +// this can be broken out to separate the json bits later if we need raw or other http type requests +// all it does is fetch via get or post, and if the status is 200 returns the json, else error json +nlohmann::json webAPI::request(string endpoint, string data, int reqType) +{ + nlohmann::json response; - slist = curl_slist_append(slist, "charsets: utf-8"); + if (!endpoint.empty()) //data is allowed to be an empty string if we're doing a normal GET + { + CURL *curl = curl_easy_init(); // start up curl - CURLcode res = curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str()); - res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); // place the data into readBuffer using writeCallback - res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); // specify readBuffer as the container for data - res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); - - switch (getPost) { - case HTTP::GET: - res = curl_easy_setopt(curl, CURLOPT_URL, std::string(uri + "?" + sRequest).c_str()); - break; - case HTTP::POST: - res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, sRequest.c_str()); - res = curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); - break; - // want to do a put, or whatever other type? feel free to add here - } - - // I suggest leaving VERIFYPEER = 0 because system SSL stores tend to be outdated - //if (uri.find(vxENCRYPT("stellabellum").decrypt()) != std::string::npos) { - // the public one will verify but since this is pinned we don't care about the CA - // to grab/generate, see https://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html - // under the PUBLIC KEY EXTRACTION heading - res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - - // if you want to pin to your own cert or cloudflares, learn how and use the below - // res = curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY, vxENCRYPT("sha256//YOURKEYHERE").decrypt()); - //} - - if (res == CURLE_OK) { - res = curl_easy_perform(curl); // make the request! - } - - if (res == CURLE_OK) { - char *contentType; - - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode); //get status code - curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &contentType); // get response mime type - - std::string conType(contentType); - - if (statusCode == 200 && !(readBuffer.empty())) // check it all out and parse + if (curl) { - sResponse = readBuffer; - if (conType == "application/json") { - fetchStatus = processJSON(); - } else { - responseData.clear(); - fetchStatus = true; - } - } - } + string readBuffer; // container for the remote response + long http_code = 0; // we get this after performing the get or post - curl_slist_free_all(slist); - curl_easy_cleanup(curl); // always wipe our butt - } - } + curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str()); // endpoint is always specified by caller + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); // place the data into readBuffer using writeCallback + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); // specify readBuffer as the container for data - if (!fetchStatus) { - sResponse.clear(); - responseData.clear(); - } + if (reqType == 1) + { + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); + } - return fetchStatus; + CURLcode res = curl_easy_perform(curl); // make the request! + + curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); //get status code + + if (res == CURLE_OK && http_code == 200 && !(readBuffer.empty())) // check it all out and parse + { + try { + response = nlohmann::json::parse(readBuffer); + } catch (string e) { + response["message"] = e; + response["status"] = "failure"; + } catch (...) { + response["message"] = "JSON parse error for endpoint."; + response["status"] = "failure"; + } + } + else + { + response["message"] = "Error fetching data from remote."; + response["status"] = "failure"; + } + curl_easy_cleanup(curl); // always wipe our butt + } + else //default err messages below + { + response["message"] = "Failed to initialize cURL."; + response["status"] = "failure"; + } + } + else + { + response["message"] = "Invalid endpoint URL."; + response["status"] = "failure"; + } + + return response; } // This is used by curl to grab the response and put it into a var -size_t webAPI::writeCallback(void *contents, size_t size, size_t nmemb, void *userp) { - ((std::string *) userp)->append((char *) contents, size * nmemb); - return size * nmemb; -} - -bool webAPI::processJSON() { - if (!(sResponse.empty())) // check it all out and parse - { - try { - responseData = nlohmann::json::parse(sResponse); - return true; - } catch (std::string &e) { - responseData["message"] = e; - responseData["status"] = "failure"; - } catch (...) { - responseData["message"] = "JSON parse error for endpoint."; - responseData["status"] = "failure"; - } - } else { - responseData["message"] = "Error fetching data from remote."; - responseData["status"] = "failure"; - } - - return false; +size_t webAPI::writeCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + ((string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; } diff --git a/external/3rd/library/webAPI/webAPI.h b/external/3rd/library/webAPI/webAPI.h index c45f99aa..51e60a2c 100644 --- a/external/3rd/library/webAPI/webAPI.h +++ b/external/3rd/library/webAPI/webAPI.h @@ -1,122 +1,35 @@ /* - * Version: 1.75 - * - * This code is just a simple wrapper around nlohmann's wonderful json lib - * (https://github.com/nlohmann/json) and libcurl. While originally included directly, - * we have come to realize that we may require web API functionality elsewhere in the future. - * - * As such, and in an effort to keep the code clean, we've broken it out into this simple little - * namespace/lib that is easy to include. Just make sure to link against curl when including, and - * make all the cmake modifications required to properly use it. - * - * (c) DarthArgus - * based on the original prototype by parz1val - * - * License: LGPL, don't be a dick please - */ +This code is just a simple wrapper around nlohmann's wonderful json lib +(https://github.com/nlohmann/json) and libcurl. While originally included directly, +we have come to realize that we may require web API functionality elsewhere in the future. + +As such, and in an effort to keep the code clean, we've broken it out into this simple little +namespace/lib that is easy to include. Just make sure to link against curl when including, and +make all the cmake modifications required to properly use it. + +(c) stellabellum/swgilluminati (combined crews), written by DA with help from DC +based on the original prototype by parz1val + +License: what's a license? we're a bunch of dirty pirates! +*/ #ifndef webAPI_H #define webAPI_H #include "json.hpp" - -#ifdef WIN32 -#include -#else - -#include #include -#endif +namespace webAPI +{ + using namespace std; + + string simplePost(string endpoint, string data, string slotName); + //std::string simpleGet(char* endpoint, char* data); + //nlohmann::json post(char* endpoint, char* data); + //nlohmann::json get(char* endpoint, char* data); + + nlohmann::json request(string endpoint, string data, int reqType); // 1 for post, 0 for get + size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp); +}; -#include "../libLeff/libLeff.h" - -namespace StellaBellum { - enum HTTP { - GET = 0, POST = 1 - }; - enum DTYPE { - JSON = 0, RAW = 1 - }; - - class webAPI { - public: - // useragent - std::string userAgent; - - // constructor - can setup with the endpoint from the start - webAPI(std::string endpoint, std::string userAgent = "StellaBellum webAPI"); - - ~webAPI(); - - // submits the request - bool - submit(const int &reqType = DTYPE::JSON, const int &getPost = HTTP::POST, const int &respType = DTYPE::JSON); - - // set the endpoint after object creation...or change the target if needed - bool setEndpoint(const std::string endpoint); - - // get raw response - std::string getRaw(); - - // set a standard request string - bool setData(std::string &data); // all or nothing - - // get a string from a given slot - std::string getString(const std::string &slot); - - // get a vector of strings from a given slot - std::unordered_map getStringMap(const std::string &slot); - - // set json key and value for request - template bool addJsonData(const std::string &key, const T &value) { - if (!key.empty() && - responseData.count(key) == 0) // only alow one of a given key for now, unless we support nesting later - { - requestData[key] = value; - return true; - } - - return false; - } - - // get json response slot - template T getNullableValue(const std::string &slot) { - if (!responseData.empty() && !slot.empty() && responseData.count(slot)) { - return responseData[slot].get(); - } - - return 0; - } - - private: - // json request data - object is serialized before sending, used with above setter template - nlohmann::json requestData; - - // json response, stored so we can use the getter template above - nlohmann::json responseData; - - // raw response - std::string sResponse; - - // raw request string - std::string sRequest; - - // API endpoint - std::string uri; - - // fetcher - returns raw response direct from remote - bool fetch(const int &getPost = HTTP::POST, const int &mimeType = DTYPE::JSON); - - // cURL writeback callback - static size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp); - - // json processor - string to json - bool processJSON(); - - protected: - // http response code (200, 404, etc) - long statusCode; - }; -} #endif