mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Add standalone web api server, cli handler, authorization, commands
This commit is contained in:
parent
7d71163fa0
commit
78d8b909be
@ -122,6 +122,7 @@ SET(common_headers
|
|||||||
crash.h
|
crash.h
|
||||||
crc16.h
|
crc16.h
|
||||||
crc32.h
|
crc32.h
|
||||||
|
cli/argh.h
|
||||||
data_verification.h
|
data_verification.h
|
||||||
database.h
|
database.h
|
||||||
dbcore.h
|
dbcore.h
|
||||||
@ -156,6 +157,7 @@ SET(common_headers
|
|||||||
global_define.h
|
global_define.h
|
||||||
guild_base.h
|
guild_base.h
|
||||||
guilds.h
|
guilds.h
|
||||||
|
http/httplib.h
|
||||||
inventory_profile.h
|
inventory_profile.h
|
||||||
inventory_slot.h
|
inventory_slot.h
|
||||||
ipc_mutex.h
|
ipc_mutex.h
|
||||||
|
|||||||
434
common/cli/argh.h
Normal file
434
common/cli/argh.h
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace argh
|
||||||
|
{
|
||||||
|
// Terminology:
|
||||||
|
// A command line is composed of 2 types of args:
|
||||||
|
// 1. Positional args, i.e. free standing values
|
||||||
|
// 2. Options: args beginning with '-'. We identify two kinds:
|
||||||
|
// 2.1: Flags: boolean options => (exist ? true : false)
|
||||||
|
// 2.2: Parameters: a name followed by a non-option value
|
||||||
|
|
||||||
|
#if !defined(__GNUC__) || (__GNUC__ >= 5)
|
||||||
|
using string_stream = std::istringstream;
|
||||||
|
#else
|
||||||
|
// Until GCC 5, istringstream did not have a move constructor.
|
||||||
|
// stringstream_proxy is used instead, as a workaround.
|
||||||
|
class stringstream_proxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
stringstream_proxy() = default;
|
||||||
|
|
||||||
|
// Construct with a value.
|
||||||
|
stringstream_proxy(std::string const& value) :
|
||||||
|
stream_(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
stringstream_proxy(const stringstream_proxy& other) :
|
||||||
|
stream_(other.stream_.str())
|
||||||
|
{
|
||||||
|
stream_.setstate(other.stream_.rdstate());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setstate(std::ios_base::iostate state) { stream_.setstate(state); }
|
||||||
|
|
||||||
|
// Stream out the value of the parameter.
|
||||||
|
// If the conversion was not possible, the stream will enter the fail state,
|
||||||
|
// and operator bool will return false.
|
||||||
|
template<typename T>
|
||||||
|
stringstream_proxy& operator >> (T& thing)
|
||||||
|
{
|
||||||
|
stream_ >> thing;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the string value.
|
||||||
|
std::string str() const { return stream_.str(); }
|
||||||
|
|
||||||
|
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
|
||||||
|
|
||||||
|
// Check the state of the stream.
|
||||||
|
// False when the most recent stream operation failed
|
||||||
|
operator bool() const { return !!stream_; }
|
||||||
|
|
||||||
|
~stringstream_proxy() = default;
|
||||||
|
private:
|
||||||
|
std::istringstream stream_;
|
||||||
|
};
|
||||||
|
using string_stream = stringstream_proxy;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Mode { PREFER_FLAG_FOR_UNREG_OPTION = 1 << 0,
|
||||||
|
PREFER_PARAM_FOR_UNREG_OPTION = 1 << 1,
|
||||||
|
NO_SPLIT_ON_EQUALSIGN = 1 << 2,
|
||||||
|
SINGLE_DASH_IS_MULTIFLAG = 1 << 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
parser() = default;
|
||||||
|
|
||||||
|
parser(std::initializer_list<char const* const> pre_reg_names)
|
||||||
|
{ add_params(pre_reg_names); }
|
||||||
|
|
||||||
|
parser(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||||
|
{ parse(argv, mode); }
|
||||||
|
|
||||||
|
parser(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||||
|
{ parse(argc, argv, mode); }
|
||||||
|
|
||||||
|
void add_param(std::string const& name);
|
||||||
|
void add_params(std::initializer_list<char const* const> init_list);
|
||||||
|
|
||||||
|
void parse(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||||
|
void parse(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||||
|
|
||||||
|
std::multiset<std::string> const& flags() const { return flags_; }
|
||||||
|
std::map<std::string, std::string> const& params() const { return params_; }
|
||||||
|
std::vector<std::string> const& pos_args() const { return pos_args_; }
|
||||||
|
|
||||||
|
// begin() and end() for using range-for over positional args.
|
||||||
|
std::vector<std::string>::const_iterator begin() const { return pos_args_.cbegin(); }
|
||||||
|
std::vector<std::string>::const_iterator end() const { return pos_args_.cend(); }
|
||||||
|
size_t size() const { return pos_args_.size(); }
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Accessors
|
||||||
|
|
||||||
|
// flag (boolean) accessors: return true if the flag appeared, otherwise false.
|
||||||
|
bool operator[](std::string const& name) const;
|
||||||
|
|
||||||
|
// multiple flag (boolean) accessors: return true if at least one of the flag appeared, otherwise false.
|
||||||
|
bool operator[](std::initializer_list<char const* const> init_list) const;
|
||||||
|
|
||||||
|
// returns positional arg string by order. Like argv[] but without the options
|
||||||
|
std::string const& operator[](size_t ind) const;
|
||||||
|
|
||||||
|
// returns a std::istream that can be used to convert a positional arg to a typed value.
|
||||||
|
string_stream operator()(size_t ind) const;
|
||||||
|
|
||||||
|
// same as above, but with a default value in case the arg is missing (index out of range).
|
||||||
|
template<typename T>
|
||||||
|
string_stream operator()(size_t ind, T&& def_val) const;
|
||||||
|
|
||||||
|
// parameter accessors, give a name get an std::istream that can be used to convert to a typed value.
|
||||||
|
// call .str() on result to get as string
|
||||||
|
string_stream operator()(std::string const& name) const;
|
||||||
|
|
||||||
|
// accessor for a parameter with multiple names, give a list of names, get an std::istream that can be used to convert to a typed value.
|
||||||
|
// call .str() on result to get as string
|
||||||
|
// returns the first value in the list to be found.
|
||||||
|
string_stream operator()(std::initializer_list<char const* const> init_list) const;
|
||||||
|
|
||||||
|
// same as above, but with a default value in case the param was missing.
|
||||||
|
// Non-string def_val types must have an operator<<() (output stream operator)
|
||||||
|
// If T only has an input stream operator, pass the string version of the type as in "3" instead of 3.
|
||||||
|
template<typename T>
|
||||||
|
string_stream operator()(std::string const& name, T&& def_val) const;
|
||||||
|
|
||||||
|
// same as above but for a list of names. returns the first value to be found.
|
||||||
|
template<typename T>
|
||||||
|
string_stream operator()(std::initializer_list<char const* const> init_list, T&& def_val) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
string_stream bad_stream() const;
|
||||||
|
std::string trim_leading_dashes(std::string const& name) const;
|
||||||
|
bool is_number(std::string const& arg) const;
|
||||||
|
bool is_option(std::string const& arg) const;
|
||||||
|
bool got_flag(std::string const& name) const;
|
||||||
|
bool is_param(std::string const& name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> args_;
|
||||||
|
std::map<std::string, std::string> params_;
|
||||||
|
std::vector<std::string> pos_args_;
|
||||||
|
std::multiset<std::string> flags_;
|
||||||
|
std::set<std::string> registeredParams_;
|
||||||
|
std::string empty_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline void parser::parse(const char * const argv[], int mode)
|
||||||
|
{
|
||||||
|
int argc = 0;
|
||||||
|
for (auto argvp = argv; *argvp; ++argc, ++argvp);
|
||||||
|
parse(argc, argv, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline void parser::parse(int argc, const char* const argv[], int mode /*= PREFER_FLAG_FOR_UNREG_OPTION*/)
|
||||||
|
{
|
||||||
|
// convert to strings
|
||||||
|
args_.resize(argc);
|
||||||
|
std::transform(argv, argv + argc, args_.begin(), [](const char* const arg) { return arg; });
|
||||||
|
|
||||||
|
// parse line
|
||||||
|
for (auto i = 0u; i < args_.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!is_option(args_[i]))
|
||||||
|
{
|
||||||
|
pos_args_.emplace_back(args_[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto name = trim_leading_dashes(args_[i]);
|
||||||
|
|
||||||
|
if (!(mode & NO_SPLIT_ON_EQUALSIGN))
|
||||||
|
{
|
||||||
|
auto equalPos = name.find('=');
|
||||||
|
if (equalPos != std::string::npos)
|
||||||
|
{
|
||||||
|
params_.insert({ name.substr(0, equalPos), name.substr(equalPos + 1) });
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the option is unregistered and should be a multi-flag
|
||||||
|
if (1 == (args_[i].size() - name.size()) && // single dash
|
||||||
|
argh::parser::SINGLE_DASH_IS_MULTIFLAG & mode && // multi-flag mode
|
||||||
|
!is_param(name)) // unregistered
|
||||||
|
{
|
||||||
|
std::string keep_param;
|
||||||
|
|
||||||
|
if (!name.empty() && is_param(std::string(1ul, name.back()))) // last char is param
|
||||||
|
{
|
||||||
|
keep_param += name.back();
|
||||||
|
name.resize(name.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& c : name)
|
||||||
|
{
|
||||||
|
flags_.emplace(std::string{ c });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keep_param.empty())
|
||||||
|
{
|
||||||
|
name = keep_param;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue; // do not consider other options for this arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// any potential option will get as its value the next arg, unless that arg is an option too
|
||||||
|
// in that case it will be determined a flag.
|
||||||
|
if (i == args_.size() - 1 || is_option(args_[i + 1]))
|
||||||
|
{
|
||||||
|
flags_.emplace(name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if 'name' is a pre-registered option, then the next arg cannot be a free parameter to it is skipped
|
||||||
|
// otherwise we have 2 modes:
|
||||||
|
// PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.
|
||||||
|
// The following value (the next arg) will be a free parameter.
|
||||||
|
//
|
||||||
|
// PREFER_PARAM_FOR_UNREG_OPTION: a non-registered 'name' is determined a parameter, the next arg
|
||||||
|
// will be the value of that option.
|
||||||
|
|
||||||
|
assert(!(mode & argh::parser::PREFER_FLAG_FOR_UNREG_OPTION)
|
||||||
|
|| !(mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION));
|
||||||
|
|
||||||
|
bool preferParam = mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION;
|
||||||
|
|
||||||
|
if (is_param(name) || preferParam)
|
||||||
|
{
|
||||||
|
params_.insert({ name, args_[i + 1] });
|
||||||
|
++i; // skip next value, it is not a free parameter
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags_.emplace(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline string_stream parser::bad_stream() const
|
||||||
|
{
|
||||||
|
string_stream bad;
|
||||||
|
bad.setstate(std::ios_base::failbit);
|
||||||
|
return bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool parser::is_number(std::string const& arg) const
|
||||||
|
{
|
||||||
|
// inefficient but simple way to determine if a string is a number (which can start with a '-')
|
||||||
|
std::istringstream istr(arg);
|
||||||
|
double number;
|
||||||
|
istr >> number;
|
||||||
|
return !(istr.fail() || istr.bad());
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool parser::is_option(std::string const& arg) const
|
||||||
|
{
|
||||||
|
assert(0 != arg.size());
|
||||||
|
if (is_number(arg))
|
||||||
|
return false;
|
||||||
|
return '-' == arg[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline std::string parser::trim_leading_dashes(std::string const& name) const
|
||||||
|
{
|
||||||
|
auto pos = name.find_first_not_of('-');
|
||||||
|
return std::string::npos != pos ? name.substr(pos) : name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool argh::parser::got_flag(std::string const& name) const
|
||||||
|
{
|
||||||
|
return flags_.end() != flags_.find(trim_leading_dashes(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool argh::parser::is_param(std::string const& name) const
|
||||||
|
{
|
||||||
|
return registeredParams_.count(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool parser::operator[](std::string const& name) const
|
||||||
|
{
|
||||||
|
return got_flag(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool parser::operator[](std::initializer_list<char const* const> init_list) const
|
||||||
|
{
|
||||||
|
return std::any_of(init_list.begin(), init_list.end(), [&](char const* const name) { return got_flag(name); });
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline std::string const& parser::operator[](size_t ind) const
|
||||||
|
{
|
||||||
|
if (ind < pos_args_.size())
|
||||||
|
return pos_args_[ind];
|
||||||
|
return empty_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline string_stream parser::operator()(std::string const& name) const
|
||||||
|
{
|
||||||
|
auto optIt = params_.find(trim_leading_dashes(name));
|
||||||
|
if (params_.end() != optIt)
|
||||||
|
return string_stream(optIt->second);
|
||||||
|
return bad_stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline string_stream parser::operator()(std::initializer_list<char const* const> init_list) const
|
||||||
|
{
|
||||||
|
for (auto& name : init_list)
|
||||||
|
{
|
||||||
|
auto optIt = params_.find(trim_leading_dashes(name));
|
||||||
|
if (params_.end() != optIt)
|
||||||
|
return string_stream(optIt->second);
|
||||||
|
}
|
||||||
|
return bad_stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
string_stream parser::operator()(std::string const& name, T&& def_val) const
|
||||||
|
{
|
||||||
|
auto optIt = params_.find(trim_leading_dashes(name));
|
||||||
|
if (params_.end() != optIt)
|
||||||
|
return string_stream(optIt->second);
|
||||||
|
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||||
|
ostr << def_val;
|
||||||
|
return string_stream(ostr.str()); // use default
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// same as above but for a list of names. returns the first value to be found.
|
||||||
|
template<typename T>
|
||||||
|
string_stream parser::operator()(std::initializer_list<char const* const> init_list, T&& def_val) const
|
||||||
|
{
|
||||||
|
for (auto& name : init_list)
|
||||||
|
{
|
||||||
|
auto optIt = params_.find(trim_leading_dashes(name));
|
||||||
|
if (params_.end() != optIt)
|
||||||
|
return string_stream(optIt->second);
|
||||||
|
}
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||||
|
ostr << def_val;
|
||||||
|
return string_stream(ostr.str()); // use default
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline string_stream parser::operator()(size_t ind) const
|
||||||
|
{
|
||||||
|
if (pos_args_.size() <= ind)
|
||||||
|
return bad_stream();
|
||||||
|
|
||||||
|
return string_stream(pos_args_[ind]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
string_stream parser::operator()(size_t ind, T&& def_val) const
|
||||||
|
{
|
||||||
|
if (pos_args_.size() <= ind)
|
||||||
|
{
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||||
|
ostr << def_val;
|
||||||
|
return string_stream(ostr.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return string_stream(pos_args_[ind]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline void parser::add_param(std::string const& name)
|
||||||
|
{
|
||||||
|
registeredParams_.insert(trim_leading_dashes(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline void parser::add_params(std::initializer_list<char const* const> init_list)
|
||||||
|
{
|
||||||
|
for (auto& name : init_list)
|
||||||
|
registeredParams_.insert(trim_leading_dashes(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -193,7 +193,6 @@ namespace Logs {
|
|||||||
OutF(LogSys, Logs::General, Logs::Error, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
OutF(LogSys, Logs::General, Logs::Error, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#define LogWarning(message, ...) do {\
|
#define LogWarning(message, ...) do {\
|
||||||
if (LogSys.log_settings[Logs::Warning].is_category_enabled == 1)\
|
if (LogSys.log_settings[Logs::Warning].is_category_enabled == 1)\
|
||||||
OutF(LogSys, Logs::General, Logs::Warning, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
OutF(LogSys, Logs::General, Logs::Warning, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
|||||||
2694
common/http/httplib.h
Normal file
2694
common/http/httplib.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -12,16 +12,18 @@ EQ::JsonConfigFile::JsonConfigFile(const Json::Value &value)
|
|||||||
EQ::JsonConfigFile::~JsonConfigFile() = default;
|
EQ::JsonConfigFile::~JsonConfigFile() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param filename
|
* @param file_name
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
EQ::JsonConfigFile EQ::JsonConfigFile::Load(const std::string &filename)
|
EQ::JsonConfigFile EQ::JsonConfigFile::Load(
|
||||||
|
const std::string &file_name
|
||||||
|
)
|
||||||
{
|
{
|
||||||
JsonConfigFile ret;
|
JsonConfigFile ret;
|
||||||
ret.m_root = Json::Value();
|
ret.m_root = Json::Value();
|
||||||
|
|
||||||
std::ifstream ifs;
|
std::ifstream ifs;
|
||||||
ifs.open(filename, std::ifstream::in);
|
ifs.open(file_name, std::ifstream::in);
|
||||||
|
|
||||||
if (!ifs.good()) {
|
if (!ifs.good()) {
|
||||||
return ret;
|
return ret;
|
||||||
@ -37,6 +39,31 @@ EQ::JsonConfigFile EQ::JsonConfigFile::Load(const std::string &filename)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param file_name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
void EQ::JsonConfigFile::Save(
|
||||||
|
const std::string &file_name
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::ofstream opened_config_file;
|
||||||
|
opened_config_file.open(file_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grab and build config contents
|
||||||
|
*/
|
||||||
|
Json::StreamWriterBuilder write_builder;
|
||||||
|
write_builder["indentation"] = " ";
|
||||||
|
std::string document = Json::writeString(write_builder, m_root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write current contents and close
|
||||||
|
*/
|
||||||
|
opened_config_file << document;
|
||||||
|
opened_config_file.close();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param title
|
* @param title
|
||||||
* @param parameter
|
* @param parameter
|
||||||
|
|||||||
@ -11,7 +11,8 @@ namespace EQ
|
|||||||
JsonConfigFile(const Json::Value &value);
|
JsonConfigFile(const Json::Value &value);
|
||||||
~JsonConfigFile();
|
~JsonConfigFile();
|
||||||
|
|
||||||
static JsonConfigFile Load(const std::string &filename);
|
static JsonConfigFile Load(const std::string &file_name);
|
||||||
|
void Save(const std::string &file_name);
|
||||||
|
|
||||||
std::string GetVariableString(const std::string &title, const std::string ¶meter, const std::string &default_value);
|
std::string GetVariableString(const std::string &title, const std::string ¶meter, const std::string &default_value);
|
||||||
int GetVariableInt(const std::string &title, const std::string ¶meter, const int default_value);
|
int GetVariableInt(const std::string &title, const std::string ¶meter, const int default_value);
|
||||||
|
|||||||
@ -5,6 +5,8 @@ SET(eqlogin_sources
|
|||||||
client_manager.cpp
|
client_manager.cpp
|
||||||
database.cpp
|
database.cpp
|
||||||
encryption.cpp
|
encryption.cpp
|
||||||
|
loginserver_command_handler.cpp
|
||||||
|
loginserver_webserver.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
server_manager.cpp
|
server_manager.cpp
|
||||||
world_server.cpp
|
world_server.cpp
|
||||||
@ -15,6 +17,8 @@ SET(eqlogin_headers
|
|||||||
client_manager.h
|
client_manager.h
|
||||||
database.h
|
database.h
|
||||||
encryption.h
|
encryption.h
|
||||||
|
loginserver_command_handler.h
|
||||||
|
loginserver_webserver.h
|
||||||
login_server.h
|
login_server.h
|
||||||
login_structures.h
|
login_structures.h
|
||||||
options.h
|
options.h
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "login_server.h"
|
#include "login_server.h"
|
||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
|
#include "../common/util/uuid.h"
|
||||||
|
|
||||||
extern LoginServer server;
|
extern LoginServer server;
|
||||||
|
|
||||||
@ -463,7 +464,11 @@ void Database::UpdateWorldRegistration(unsigned int id, std::string long_name, s
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool Database::CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id)
|
bool Database::CreateWorldRegistration(
|
||||||
|
std::string long_name,
|
||||||
|
std::string short_name,
|
||||||
|
unsigned int &id
|
||||||
|
)
|
||||||
{
|
{
|
||||||
auto query = fmt::format(
|
auto query = fmt::format(
|
||||||
"SELECT ifnull(max(ServerID),0) + 1 FROM {0}",
|
"SELECT ifnull(max(ServerID),0) + 1 FROM {0}",
|
||||||
@ -504,6 +509,44 @@ bool Database::CreateWorldRegistration(std::string long_name, std::string short_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param long_name
|
||||||
|
* @param short_name
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
std::string Database::CreateLoginserverApiToken(
|
||||||
|
bool write_mode,
|
||||||
|
bool read_mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::string token = EQ::Util::UUID::Generate().ToString();
|
||||||
|
auto query = fmt::format(
|
||||||
|
"INSERT INTO loginserver_api_tokens (token, can_write, can_read, created_at) VALUES ('{0}', {1}, {2}, NOW())",
|
||||||
|
token,
|
||||||
|
(write_mode ? "1" : "0"),
|
||||||
|
(read_mode ? "1" : "0")
|
||||||
|
);
|
||||||
|
|
||||||
|
auto results = QueryDatabase(query);
|
||||||
|
if (!results.Success()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param long_name
|
||||||
|
* @param short_name
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
MySQLRequestResult Database::GetLoginserverApiTokens()
|
||||||
|
{
|
||||||
|
return QueryDatabase("SELECT token, can_write, can_read FROM loginserver_api_tokens");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param log_settings
|
* @param log_settings
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -128,6 +128,15 @@ public:
|
|||||||
void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
|
void UpdateWorldRegistration(unsigned int id, std::string long_name, std::string ip_address);
|
||||||
bool CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id);
|
bool CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id);
|
||||||
void LoadLogSettings(EQEmuLogSys::LogSettings *log_settings);
|
void LoadLogSettings(EQEmuLogSys::LogSettings *log_settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param write_mode
|
||||||
|
* @param read_mode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
std::string CreateLoginserverApiToken(bool write_mode, bool read_mode);
|
||||||
|
MySQLRequestResult GetLoginserverApiTokens();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string user, pass, host, port, name;
|
std::string user, pass, host, port, name;
|
||||||
MYSQL *database;
|
MYSQL *database;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#include <utility>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EQEmulator: Everquest Server Emulator
|
* EQEmulator: Everquest Server Emulator
|
||||||
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||||
@ -28,6 +30,7 @@
|
|||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "server_manager.h"
|
#include "server_manager.h"
|
||||||
#include "client_manager.h"
|
#include "client_manager.h"
|
||||||
|
#include "loginserver_webserver.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login server struct, contains every variable for the server that needs to exist outside the scope of main()
|
* Login server struct, contains every variable for the server that needs to exist outside the scope of main()
|
||||||
@ -35,10 +38,13 @@
|
|||||||
struct LoginServer
|
struct LoginServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LoginServer() : db(nullptr), server_manager(nullptr) { }
|
LoginServer() : db(nullptr), server_manager(nullptr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
EQ::JsonConfigFile config;
|
EQ::JsonConfigFile config;
|
||||||
Database *db;
|
Database *db;
|
||||||
|
LoginserverWebserver::TokenManager *token_manager{};
|
||||||
Options options;
|
Options options;
|
||||||
ServerManager *server_manager;
|
ServerManager *server_manager;
|
||||||
ClientManager *client_manager{};
|
ClientManager *client_manager{};
|
||||||
|
|||||||
142
loginserver/loginserver_command_handler.cpp
Normal file
142
loginserver/loginserver_command_handler.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/**
|
||||||
|
* EQEmulator: Everquest Server Emulator
|
||||||
|
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||||
|
* are required to give you total support for your newly bought product;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <random>
|
||||||
|
#include "loginserver_command_handler.h"
|
||||||
|
#include "../common/util/uuid.h"
|
||||||
|
#include "login_server.h"
|
||||||
|
#include "loginserver_webserver.h"
|
||||||
|
|
||||||
|
extern LoginServer server;
|
||||||
|
|
||||||
|
namespace LoginserverCommandHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cmd
|
||||||
|
*/
|
||||||
|
void DisplayDebug(argh::parser &cmd)
|
||||||
|
{
|
||||||
|
if (cmd[{"-d", "--debug"}]) {
|
||||||
|
std::cout << "Positional args:\n";
|
||||||
|
for (auto &pos_arg : cmd)
|
||||||
|
std::cout << '\t' << pos_arg << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Positional args:\n";
|
||||||
|
for (auto &pos_arg : cmd.pos_args())
|
||||||
|
std::cout << '\t' << pos_arg << std::endl;
|
||||||
|
|
||||||
|
std::cout << "\nFlags:\n";
|
||||||
|
for (auto &flag : cmd.flags())
|
||||||
|
std::cout << '\t' << flag << std::endl;
|
||||||
|
|
||||||
|
std::cout << "\nParameters:\n";
|
||||||
|
for (auto ¶m : cmd.params())
|
||||||
|
std::cout << '\t' << param.first << " : " << param.second << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
*/
|
||||||
|
void CommandHandler(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc == 1) { return; }
|
||||||
|
|
||||||
|
argh::parser cmd;
|
||||||
|
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
|
||||||
|
|
||||||
|
LoginserverCommandHandler::DisplayDebug(cmd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare command mapping
|
||||||
|
*/
|
||||||
|
std::map<std::string, void (*)(int argc, char **argv, argh::parser &cmd)> function_map;
|
||||||
|
function_map["create-loginserver-api-token"] = &LoginserverCommandHandler::CreateLoginserverApiToken;
|
||||||
|
function_map["list-loginserver-api-tokens"] = &LoginserverCommandHandler::ListLoginserverApiTokens;
|
||||||
|
|
||||||
|
std::map<std::string, void (*)(int argc, char **argv, argh::parser &cmd)>::const_iterator it = function_map.begin();
|
||||||
|
std::map<std::string, void (*)(int argc, char **argv, argh::parser &cmd)>::const_iterator end = function_map.end();
|
||||||
|
|
||||||
|
bool ran_command = false;
|
||||||
|
while (it != end) {
|
||||||
|
if (it->first == argv[1]) {
|
||||||
|
(it->second)(argc, argv, cmd);
|
||||||
|
ran_command = true;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd[{"-h", "--help"}] || !ran_command) {
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "###########################################################" << std::endl;
|
||||||
|
std::cout << "# Loginserver CLI Menu" << std::endl;
|
||||||
|
std::cout << "###########################################################" << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << "> create-loginserver-api-token --write --read" << std::endl;
|
||||||
|
std::cout << "> list-loginserver-api-tokens" << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @param cmd
|
||||||
|
*/
|
||||||
|
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd)
|
||||||
|
{
|
||||||
|
bool can_read = cmd[{"-r", "--read"}];
|
||||||
|
bool can_write = cmd[{"-w", "--write"}];
|
||||||
|
|
||||||
|
if (!can_read || !can_write) {
|
||||||
|
LogInfo("[{0}] --read or --write must be set or both!", __func__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string token = server.db->CreateLoginserverApiToken(can_write, can_read);
|
||||||
|
if (!token.empty()) {
|
||||||
|
LogInfo("[{0}] Created Loginserver API token [{1}]", __func__, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @param cmd
|
||||||
|
*/
|
||||||
|
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd)
|
||||||
|
{
|
||||||
|
for (auto it = server.token_manager->loaded_api_tokens.begin();
|
||||||
|
it != server.token_manager->loaded_api_tokens.end();
|
||||||
|
++it) {
|
||||||
|
LogInfo(
|
||||||
|
"token [{0}] can_write [{1}] can_read [{2}]",
|
||||||
|
it->second.token,
|
||||||
|
it->second.can_write,
|
||||||
|
it->second.can_read
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
loginserver/loginserver_command_handler.h
Normal file
34
loginserver/loginserver_command_handler.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* EQEmulator: Everquest Server Emulator
|
||||||
|
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||||
|
* are required to give you total support for your newly bought product;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "iostream"
|
||||||
|
#include "../common/cli/argh.h"
|
||||||
|
|
||||||
|
#ifndef EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||||
|
#define EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||||
|
|
||||||
|
namespace LoginserverCommandHandler {
|
||||||
|
void CommandHandler(int argc, char **argv);
|
||||||
|
void CreateLoginserverApiToken(int argc, char **argv, argh::parser &cmd);
|
||||||
|
void ListLoginserverApiTokens(int argc, char **argv, argh::parser &cmd);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EQEMU_LOGINSERVER_COMMAND_HANDLER_H
|
||||||
243
loginserver/loginserver_webserver.cpp
Normal file
243
loginserver/loginserver_webserver.cpp
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/**
|
||||||
|
* EQEmulator: Everquest Server Emulator
|
||||||
|
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||||
|
* are required to give you total support for your newly bought product;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "loginserver_webserver.h"
|
||||||
|
#include "server_manager.h"
|
||||||
|
#include "login_server.h"
|
||||||
|
#include "../common/json/json.h"
|
||||||
|
#include "../common/string_util.h"
|
||||||
|
|
||||||
|
extern LoginServer server;
|
||||||
|
|
||||||
|
namespace LoginserverWebserver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param api
|
||||||
|
*/
|
||||||
|
void RegisterRoutes(httplib::Server &api)
|
||||||
|
{
|
||||||
|
server.token_manager = new LoginserverWebserver::TokenManager;
|
||||||
|
server.token_manager->LoadApiTokens();
|
||||||
|
|
||||||
|
api.Get(
|
||||||
|
"/servers/list", [](const httplib::Request &request, httplib::Response &res) {
|
||||||
|
|
||||||
|
LoginserverWebserver::TokenManager::AuthCanRead(request, res);
|
||||||
|
|
||||||
|
Json::Value response;
|
||||||
|
auto iter = server.server_manager->getWorldServers().begin();
|
||||||
|
while (iter != server.server_manager->getWorldServers().end()) {
|
||||||
|
Json::Value row;
|
||||||
|
row["server_long_name"] = (*iter)->GetLongName();
|
||||||
|
row["server_short_name"] = (*iter)->GetLongName();
|
||||||
|
row["server_list_id"] = (*iter)->GetServerListID();
|
||||||
|
row["server_status"] = (*iter)->GetStatus();
|
||||||
|
row["zones_booted"] = (*iter)->GetZonesBooted();
|
||||||
|
row["local_ip"] = (*iter)->GetLocalIP();
|
||||||
|
row["remote_ip"] = (*iter)->GetRemoteIP();
|
||||||
|
row["players_online"] = (*iter)->GetPlayersOnline();
|
||||||
|
response.append(row);
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginserverWebserver::SendResponse(response, res);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param payload
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
void SendResponse(const Json::Value &payload, httplib::Response &res)
|
||||||
|
{
|
||||||
|
if (res.get_header_value("response_set") == "true") {
|
||||||
|
res.set_header("response_set", "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream response_payload;
|
||||||
|
|
||||||
|
if (payload.empty()) {
|
||||||
|
Json::Value response;
|
||||||
|
response["message"] = "There were no results found";
|
||||||
|
response_payload << response;
|
||||||
|
res.set_content(response_payload.str(), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response_payload << payload;
|
||||||
|
res.set_content(response_payload.str(), "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param request
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
void LoginserverWebserver::TokenManager::AuthCanRead(const httplib::Request &request, httplib::Response &res)
|
||||||
|
{
|
||||||
|
LoginserverWebserver::TokenManager::token_data
|
||||||
|
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||||
|
|
||||||
|
if (!user_token.can_read) {
|
||||||
|
Json::Value response;
|
||||||
|
std::stringstream response_payload;
|
||||||
|
response["message"] = "Authorization token is either invalid or cannot read!";
|
||||||
|
response_payload << response;
|
||||||
|
res.set_content(response_payload.str(), "application/json");
|
||||||
|
res.set_header("response_set", "true");
|
||||||
|
|
||||||
|
LogWarning(
|
||||||
|
"AuthCanRead access failure | token [{0}] remote_address [{1}] user_agent [{2}]",
|
||||||
|
user_token.token,
|
||||||
|
user_token.remote_address,
|
||||||
|
user_token.user_agent
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param request
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
void LoginserverWebserver::TokenManager::AuthCanWrite(const httplib::Request &request, httplib::Response &res)
|
||||||
|
{
|
||||||
|
LoginserverWebserver::TokenManager::token_data
|
||||||
|
user_token = LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(request);
|
||||||
|
|
||||||
|
if (!user_token.can_write) {
|
||||||
|
Json::Value response;
|
||||||
|
std::stringstream response_payload;
|
||||||
|
response["message"] = "Authorization token is either invalid or cannot write!";
|
||||||
|
response_payload << response;
|
||||||
|
res.set_content(response_payload.str(), "application/json");
|
||||||
|
res.set_header("response_set", "true");
|
||||||
|
|
||||||
|
LogWarning(
|
||||||
|
"AuthCanWrite access failure | token [{0}] remote_address [{1}] user_agent [{2}]",
|
||||||
|
user_token.token,
|
||||||
|
user_token.remote_address,
|
||||||
|
user_token.user_agent
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
LoginserverWebserver::TokenManager::token_data
|
||||||
|
LoginserverWebserver::TokenManager::CheckApiAuthorizationHeaders(
|
||||||
|
const httplib::Request &request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::string authorization_key;
|
||||||
|
|
||||||
|
LoginserverWebserver::TokenManager::token_data user_token{};
|
||||||
|
|
||||||
|
for (const auto &header : request.headers) {
|
||||||
|
auto header_key = header.first;
|
||||||
|
auto header_value = header.second;
|
||||||
|
if (header_key == "Authorization") {
|
||||||
|
authorization_key = header.second;
|
||||||
|
find_replace(authorization_key, "Bearer: ", "");
|
||||||
|
if (LoginserverWebserver::TokenManager::TokenExists(authorization_key)) {
|
||||||
|
user_token = server.token_manager->GetToken(authorization_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_key == "REMOTE_ADDR") {
|
||||||
|
user_token.remote_address = header.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_key == "User-Agent") {
|
||||||
|
user_token.user_agent = header.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDebug(
|
||||||
|
"Authentication Request | remote_address [{0}] user_agent [{1}] authorization_key [{2}]",
|
||||||
|
user_token.remote_address,
|
||||||
|
user_token.user_agent,
|
||||||
|
authorization_key
|
||||||
|
);
|
||||||
|
|
||||||
|
return user_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads API Tokens
|
||||||
|
*/
|
||||||
|
void TokenManager::LoadApiTokens()
|
||||||
|
{
|
||||||
|
auto results = server.db->GetLoginserverApiTokens();
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
LoginserverWebserver::TokenManager::token_data token_data;
|
||||||
|
token_data.token = row[0];
|
||||||
|
token_data.can_write = std::stoi(row[1]) > 0;
|
||||||
|
token_data.can_read = std::stoi(row[2]) > 0;
|
||||||
|
|
||||||
|
LogDebug(
|
||||||
|
"Inserting api token to internal list [{0}] write {1} read {2}",
|
||||||
|
token_data.token,
|
||||||
|
token_data.can_read,
|
||||||
|
token_data.can_write
|
||||||
|
);
|
||||||
|
|
||||||
|
server.token_manager->loaded_api_tokens.insert(
|
||||||
|
std::make_pair(
|
||||||
|
token_data.token,
|
||||||
|
token_data
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param token
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool TokenManager::TokenExists(const std::string &token)
|
||||||
|
{
|
||||||
|
auto it = server.token_manager->loaded_api_tokens.find(token);
|
||||||
|
|
||||||
|
return !(it == server.token_manager->loaded_api_tokens.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param token
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
LoginserverWebserver::TokenManager::token_data TokenManager::GetToken(
|
||||||
|
const std::string &token
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto iter = server.token_manager->loaded_api_tokens.find(token);
|
||||||
|
if (iter != server.token_manager->loaded_api_tokens.end()) {
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
57
loginserver/loginserver_webserver.h
Normal file
57
loginserver/loginserver_webserver.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* EQEmulator: Everquest Server Emulator
|
||||||
|
* Copyright (C) 2001-2019 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; version 2 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||||
|
* are required to give you total support for your newly bought product;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EQEMU_LOGINSERVER_WEBSERVER_H
|
||||||
|
#define EQEMU_LOGINSERVER_WEBSERVER_H
|
||||||
|
|
||||||
|
#include "../common/http/httplib.h"
|
||||||
|
#include "../common/json/json.h"
|
||||||
|
#include "../common/types.h"
|
||||||
|
|
||||||
|
namespace LoginserverWebserver {
|
||||||
|
|
||||||
|
class TokenManager {
|
||||||
|
|
||||||
|
public:
|
||||||
|
TokenManager() = default;
|
||||||
|
|
||||||
|
struct token_data {
|
||||||
|
std::string token;
|
||||||
|
bool can_read;
|
||||||
|
bool can_write;
|
||||||
|
std::string user_agent;
|
||||||
|
std::string remote_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, token_data> loaded_api_tokens{};
|
||||||
|
|
||||||
|
void LoadApiTokens();
|
||||||
|
static bool TokenExists(const std::string &token);
|
||||||
|
token_data GetToken(const std::string &token);
|
||||||
|
static token_data CheckApiAuthorizationHeaders(const httplib::Request &request);
|
||||||
|
static void AuthCanRead(const httplib::Request &request, httplib::Response &res);
|
||||||
|
static void AuthCanWrite(const httplib::Request &request, httplib::Response &res);
|
||||||
|
};
|
||||||
|
|
||||||
|
void RegisterRoutes(httplib::Server &api);
|
||||||
|
void SendResponse(const Json::Value &payload, httplib::Response &res);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_LOGINSERVER_WEBSERVER_H
|
||||||
@ -26,7 +26,10 @@
|
|||||||
#include "../common/platform.h"
|
#include "../common/platform.h"
|
||||||
#include "../common/crash.h"
|
#include "../common/crash.h"
|
||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
|
#include "../common/http/httplib.h"
|
||||||
#include "login_server.h"
|
#include "login_server.h"
|
||||||
|
#include "loginserver_webserver.h"
|
||||||
|
#include "loginserver_command_handler.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -40,7 +43,7 @@ void CatchSignal(int sig_num)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
RegisterExecutablePlatform(ExePlatformLogin);
|
RegisterExecutablePlatform(ExePlatformLogin);
|
||||||
set_exception_handler();
|
set_exception_handler();
|
||||||
@ -176,25 +179,46 @@ int main()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
LogInfo("Server Started");
|
LogInfo("Server Started");
|
||||||
|
|
||||||
if (LogSys.log_settings[Logs::Login_Server].log_to_console == 1) {
|
if (LogSys.log_settings[Logs::Login_Server].log_to_console == 1) {
|
||||||
LogInfo("Loginserver logging set to level [1] for more debugging, enable detail [3]");
|
LogInfo("Loginserver logging set to level [1] for more debugging, enable detail [3]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web API
|
||||||
|
*/
|
||||||
|
httplib::Server api;
|
||||||
|
int web_api_port = server.config.GetVariableInt("web_api", "port", 6000);
|
||||||
|
bool web_api_enabled = server.config.GetVariableBool("web_api", "enabled", true);
|
||||||
|
if (web_api_enabled) {
|
||||||
|
api.bind("0.0.0.0", web_api_port);
|
||||||
|
LogInfo("Webserver API now listening on port [{0}]", web_api_port);
|
||||||
|
LoginserverWebserver::RegisterRoutes(api);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginserverCommandHandler::CommandHandler(argc, argv);
|
||||||
|
|
||||||
while (run_server) {
|
while (run_server) {
|
||||||
Timer::SetCurrentTime();
|
Timer::SetCurrentTime();
|
||||||
server.client_manager->Process();
|
server.client_manager->Process();
|
||||||
EQ::EventLoop::Get().Process();
|
EQ::EventLoop::Get().Process();
|
||||||
Sleep(50);
|
|
||||||
|
if (web_api_enabled) {
|
||||||
|
api.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sleep(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogInfo("Server Shutdown");
|
LogInfo("Server Shutdown");
|
||||||
|
|
||||||
LogInfo("Client Manager Shutdown");
|
LogInfo("Client Manager Shutdown");
|
||||||
delete server.client_manager;
|
delete server.client_manager;
|
||||||
|
|
||||||
LogInfo("Server Manager Shutdown");
|
LogInfo("Server Manager Shutdown");
|
||||||
delete server.server_manager;
|
delete server.server_manager;
|
||||||
|
|
||||||
LogInfo("Database System Shutdown");
|
LogInfo("Database System Shutdown");
|
||||||
delete server.db;
|
delete server.db;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,6 @@ public:
|
|||||||
dump_in_packets(false),
|
dump_in_packets(false),
|
||||||
dump_out_packets(false),
|
dump_out_packets(false),
|
||||||
encryption_mode(5),
|
encryption_mode(5),
|
||||||
local_network("127.0.0.1"),
|
|
||||||
reject_duplicate_servers(false),
|
reject_duplicate_servers(false),
|
||||||
allow_password_login(true),
|
allow_password_login(true),
|
||||||
allow_token_login(false),
|
allow_token_login(false),
|
||||||
@ -187,7 +186,6 @@ private:
|
|||||||
bool auto_link_accounts;
|
bool auto_link_accounts;
|
||||||
bool update_insecure_passwords;
|
bool update_insecure_passwords;
|
||||||
int encryption_mode;
|
int encryption_mode;
|
||||||
std::string local_network;
|
|
||||||
std::string account_table;
|
std::string account_table;
|
||||||
std::string world_registration_table;
|
std::string world_registration_table;
|
||||||
std::string world_admin_registration_table;
|
std::string world_admin_registration_table;
|
||||||
|
|||||||
@ -332,3 +332,11 @@ void ServerManager::DestroyServerByName(
|
|||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
const std::list<std::unique_ptr<WorldServer>> &ServerManager::getWorldServers() const
|
||||||
|
{
|
||||||
|
return world_servers;
|
||||||
|
}
|
||||||
|
|||||||
@ -86,6 +86,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
void DestroyServerByName(std::string server_long_name, std::string server_short_name, WorldServer *ignore = nullptr);
|
void DestroyServerByName(std::string server_long_name, std::string server_short_name, WorldServer *ignore = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
const std::list<std::unique_ptr<WorldServer>> &getWorldServers() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,6 +105,7 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
std::unique_ptr<EQ::Net::ServertalkServer> server_connection;
|
||||||
std::list<std::unique_ptr<WorldServer>> world_servers;
|
std::list<std::unique_ptr<WorldServer>> world_servers;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user