mirror of
https://github.com/SWG-Source/src.git
synced 2026-01-17 00:04:25 -05:00
Added additional JSON web api for metrics, added support for old auth and json-based auth via new useJsonWebApi cfg setting.
This commit is contained in:
@@ -124,7 +124,7 @@
|
||||
|
||||
#include "sharedFoundation/CrcConstexpr.hpp"
|
||||
|
||||
#include "webAPI.h"
|
||||
#include "jsonWebAPI.h"
|
||||
|
||||
namespace CentralServerNamespace
|
||||
{
|
||||
|
||||
@@ -128,7 +128,7 @@ void ConfigCentralServer::install(void)
|
||||
KEY_BOOL (requestDbSaveOnPlanetServerCrash, true);
|
||||
KEY_INT (maxTimeToWaitForPlanetServerStartSeconds, 5*60); // seconds
|
||||
KEY_STRING (metricsDataURL, "");
|
||||
KEY_INT (webUpdateIntervalSeconds, 0);
|
||||
KEY_INT (webUpdateIntervalSeconds, 5);
|
||||
|
||||
int index = 0;
|
||||
char const * result = 0;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "sharedFoundation/CrcConstexpr.hpp"
|
||||
|
||||
#include "webAPI.h"
|
||||
#include "jsonWebAPI.h"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@@ -150,64 +151,91 @@ 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)
|
||||
{
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
// 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());
|
||||
// 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());
|
||||
std::transform(trimmedId.begin(),trimmedId.end(),lcaseId.begin(),::tolower);
|
||||
|
||||
std::transform(trimmedId.begin(),trimmedId.end(),lcaseId.begin(),::tolower);
|
||||
// make sure username isn't too long
|
||||
if (lcaseId.length() > MAX_ACCOUNT_NAME_LENGTH) {
|
||||
ErrorMessage err("Login Failed", "Account name is too long!");
|
||||
this->send(err, true);
|
||||
return;
|
||||
}
|
||||
|
||||
StationId suid = atoi(lcaseId.c_str());
|
||||
int authOK = 0;
|
||||
// hash username into station id
|
||||
StationId suid = atoi(lcaseId.c_str());
|
||||
if (suid == 0)
|
||||
{
|
||||
std::hash<std::string> h;
|
||||
suid = h(lcaseId.c_str()); //lint !e603 // Symbol 'h' not initialized (it's a functor)
|
||||
}
|
||||
|
||||
if (suid == 0)
|
||||
{
|
||||
std::hash<std::string> 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()));
|
||||
LOG("LoginClientConnection", ("validateClient() for stationId (%lu) at IP (%s), id (%s)", m_stationId, getRemoteAddress().c_str(), lcaseId.c_str()));
|
||||
|
||||
std::string authURL(ConfigLoginServer::getExternalAuthUrl());
|
||||
int authOK = 0;
|
||||
std::string authURL(ConfigLoginServer::getExternalAuthUrl());
|
||||
if (!authURL.empty())
|
||||
{
|
||||
if(ConfigLoginServer::getUseJsonWebApi())
|
||||
{
|
||||
StellaBellum::webAPI api(authURL);
|
||||
|
||||
if (!authURL.empty())
|
||||
{
|
||||
StellaBellum::webAPI api(authURL);
|
||||
|
||||
api.addJsonData<std::string>("user_name", trimmedId);
|
||||
api.addJsonData<std::string>("user_password", trimmedKey);
|
||||
api.addJsonData<std::string>("ip", getRemoteAddress());
|
||||
|
||||
if (api.submit()) {
|
||||
std::string msg(api.getString("message"));
|
||||
|
||||
if(msg == "success") {
|
||||
authOK = 1;
|
||||
} else {
|
||||
ErrorMessage err("Login Message", msg);
|
||||
this->send(err, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorMessage err("Login Failed", "request failed");
|
||||
this->send(err, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
authOK = 1;
|
||||
}
|
||||
api.addJsonData<std::string>("user_name", trimmedId);
|
||||
api.addJsonData<std::string>("user_password", trimmedKey);
|
||||
api.addJsonData<long>("stationID", suid);
|
||||
api.addJsonData<std::string>("ip", getRemoteAddress());
|
||||
|
||||
if (authOK)
|
||||
{
|
||||
LoginServer::getInstance().onValidateClient(suid, lcaseId, this, true, NULL, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
}
|
||||
// else this case will never be reached, noop
|
||||
if (api.submit())
|
||||
{
|
||||
std::string msg(api.getString("message"));
|
||||
|
||||
if(msg == "success") {
|
||||
authOK = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage err("Login Message", msg);
|
||||
this->send(err, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage err("Login Failed", "request failed");
|
||||
this->send(err, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream postBuf;
|
||||
postBuf << "user_name=" << trimmedId << "&user_password=" << trimmedKey << "&stationID=" << suid << "&ip=" << getRemoteAddress();
|
||||
std::string response = webAPI::simplePost(authURL, std::string(postBuf.str()), "");
|
||||
|
||||
if (response == "success") {
|
||||
authOK = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage err("Login Failed", response);
|
||||
this->send(err, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
authOK = 1;
|
||||
}
|
||||
|
||||
if (authOK)
|
||||
{
|
||||
LoginServer::getInstance().onValidateClient(suid, lcaseId, this, true, NULL, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ void ConfigLoginServer::install(void)
|
||||
KEY_INT (populationLightThresholdPercent, 8);
|
||||
KEY_INT (csToolPort, 0); // use 10666 if you want to turn the tool on
|
||||
KEY_BOOL(requireSecureLoginForCsTool, true);
|
||||
KEY_BOOL(useJsonWebApi, false);
|
||||
KEY_BOOL(useExternalAuth, false);
|
||||
KEY_STRING(externalAuthURL, "");
|
||||
KEY_BOOL(useOldSuidGenerator, false);
|
||||
|
||||
@@ -66,11 +66,11 @@ class ConfigLoginServer
|
||||
int csToolPort;
|
||||
|
||||
bool requireSecureLoginForCsTool;
|
||||
bool useExternalAuth;
|
||||
|
||||
|
||||
bool useOldSuidGenerator;
|
||||
bool useExternalAuth;
|
||||
bool useJsonWebApi;
|
||||
const char * externalAuthURL;
|
||||
|
||||
bool useOldSuidGenerator;
|
||||
};
|
||||
|
||||
static const uint16 getCentralServicePort();
|
||||
@@ -135,8 +135,9 @@ class ConfigLoginServer
|
||||
static int getPopulationLightThresholdPercent();
|
||||
|
||||
static bool getUseExternalAuth();
|
||||
static bool getUseJsonWebApi();
|
||||
static const char * getExternalAuthUrl();
|
||||
static bool getUseOldSuidGenerator();
|
||||
static bool getUseOldSuidGenerator();
|
||||
|
||||
// has character creation for this cluster been disabled through config option
|
||||
static bool isCharacterCreationDisabled(std::string const & cluster);
|
||||
@@ -486,6 +487,11 @@ inline const int ConfigLoginServer::getCSToolPort()
|
||||
return data->csToolPort;
|
||||
}
|
||||
|
||||
inline bool ConfigLoginServer::getUseJsonWebApi()
|
||||
{
|
||||
return data->useJsonWebApi;
|
||||
}
|
||||
|
||||
inline bool ConfigLoginServer::getUseExternalAuth()
|
||||
{
|
||||
return data->useExternalAuth;
|
||||
|
||||
2
external/3rd/library/webAPI/CMakeLists.txt
vendored
Normal file → Executable file
2
external/3rd/library/webAPI/CMakeLists.txt
vendored
Normal file → Executable file
@@ -5,6 +5,8 @@ project(webAPI)
|
||||
add_library(webAPI
|
||||
webAPI.h
|
||||
webAPI.cpp
|
||||
jsonWebAPI.h
|
||||
jsonWebAPI.cpp
|
||||
json.hpp
|
||||
)
|
||||
|
||||
|
||||
207
external/3rd/library/webAPI/jsonWebAPI.cpp
vendored
Executable file
207
external/3rd/library/webAPI/jsonWebAPI.cpp
vendored
Executable file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "jsonWebAPI.h"
|
||||
|
||||
using namespace StellaBellum;
|
||||
|
||||
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<std::string>();
|
||||
}
|
||||
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
std::unordered_map<int, std::string> webAPI::getStringMap(const std::string &slot) {
|
||||
std::unordered_map<int, std::string> ret = std::unordered_map<int, std::string>();
|
||||
|
||||
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
|
||||
{
|
||||
bool fetchStatus = false;
|
||||
|
||||
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 (curl) {
|
||||
std::string readBuffer = ""; // container for the remote response
|
||||
struct curl_slist *slist = nullptr;
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
slist = curl_slist_append(slist, "charsets: utf-8");
|
||||
|
||||
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
|
||||
{
|
||||
sResponse = readBuffer;
|
||||
if (conType.find("application/json") != std::string::npos) {
|
||||
fetchStatus = processJSON();
|
||||
} else {
|
||||
responseData.clear();
|
||||
fetchStatus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curl_slist_free_all(slist);
|
||||
curl_easy_cleanup(curl); // always wipe our butt
|
||||
}
|
||||
}
|
||||
|
||||
if (!fetchStatus) {
|
||||
sResponse.clear();
|
||||
responseData.clear();
|
||||
}
|
||||
|
||||
return fetchStatus;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
122
external/3rd/library/webAPI/jsonWebAPI.h
vendored
Executable file
122
external/3rd/library/webAPI/jsonWebAPI.h
vendored
Executable file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef jsonWebAPI_H
|
||||
#define jsonWebAPI_H
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <curl.h>
|
||||
#else
|
||||
|
||||
#include <unordered_map>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#endif
|
||||
|
||||
#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<int, std::string> getStringMap(const std::string &slot);
|
||||
|
||||
// set json key and value for request
|
||||
template<typename T> 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<typename T> T getNullableValue(const std::string &slot) {
|
||||
if (!responseData.empty() && !slot.empty() && responseData.count(slot)) {
|
||||
return responseData[slot].get<T>();
|
||||
}
|
||||
|
||||
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
|
||||
292
external/3rd/library/webAPI/webAPI.cpp
vendored
Normal file → Executable file
292
external/3rd/library/webAPI/webAPI.cpp
vendored
Normal file → Executable file
@@ -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<std::string>();
|
||||
}
|
||||
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
std::unordered_map<int, std::string> webAPI::getStringMap(const std::string &slot) {
|
||||
std::unordered_map<int, std::string> ret = std::unordered_map<int, std::string>();
|
||||
|
||||
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<std::string>() == "success")
|
||||
{
|
||||
// use custom slot if specified (not "")
|
||||
if (!(slotName.empty()) && response.count(slotName))
|
||||
{
|
||||
output = response[slotName].get<std::string>();
|
||||
}
|
||||
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<std::string>();
|
||||
}
|
||||
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.find("application/json") != std::string::npos) {
|
||||
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;
|
||||
size_t webAPI::writeCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
((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;
|
||||
}
|
||||
139
external/3rd/library/webAPI/webAPI.h
vendored
Normal file → Executable file
139
external/3rd/library/webAPI/webAPI.h
vendored
Normal file → Executable file
@@ -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 <curl.h>
|
||||
#else
|
||||
|
||||
#include <unordered_map>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#endif
|
||||
|
||||
#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<int, std::string> getStringMap(const std::string &slot);
|
||||
|
||||
// set json key and value for request
|
||||
template<typename T> 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<typename T> T getNullableValue(const std::string &slot) {
|
||||
if (!responseData.empty() && !slot.empty() && responseData.count(slot)) {
|
||||
return responseData[slot].get<T>();
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
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);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
19
game/server/database/sqlnet.log
Normal file
19
game/server/database/sqlnet.log
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
***********************************************************************
|
||||
Fatal NI connect error 12537, connecting to:
|
||||
(DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=XE)(CID=(PROGRAM=sqlplus@swgvm)(HOST=swgvm)(USER=swg)))(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.50)(PORT=1521)))
|
||||
|
||||
VERSION INFORMATION:
|
||||
TNS for Linux: Version 10.2.0.4.0 - Production
|
||||
TCP/IP NT Protocol Adapter for Linux: Version 10.2.0.4.0 - Production
|
||||
Time: 13-MAR-2019 03:01:43
|
||||
Tracing not turned on.
|
||||
Tns error struct:
|
||||
ns main err code: 12537
|
||||
TNS-12537: Message 12537 not found; No message file for product=network, facility=TNS
|
||||
ns secondary err code: 12560
|
||||
nt main err code: 507
|
||||
TNS-00507: Message 507 not found; No message file for product=network, facility=TNS
|
||||
nt secondary err code: 0
|
||||
nt OS err code: 0
|
||||
Reference in New Issue
Block a user