mirror of
https://github.com/EQEmu/Server.git
synced 2026-03-01 21:42:26 +00:00
Async eqemu login credential lookup
This commit is contained in:
parent
880de837d9
commit
6a64d845c2
114
common/event/task_scheduler.h
Normal file
114
common/event/task_scheduler.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <queue>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
namespace EQ
|
||||||
|
{
|
||||||
|
namespace Event
|
||||||
|
{
|
||||||
|
class TaskScheduler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const int DefaultThreadCount = 4;
|
||||||
|
|
||||||
|
TaskScheduler() : _running(false)
|
||||||
|
{
|
||||||
|
Start(DefaultThreadCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskScheduler(size_t threads) : _running(false)
|
||||||
|
{
|
||||||
|
Start(threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
~TaskScheduler() {
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start(size_t threads) {
|
||||||
|
if (true == _running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_running = true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < threads; ++i) {
|
||||||
|
_threads.push_back(std::thread(std::bind(&TaskScheduler::ProcessWork, this)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop() {
|
||||||
|
if (false == _running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_lock);
|
||||||
|
_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cv.notify_all();
|
||||||
|
|
||||||
|
for (auto &t : _threads) {
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Fn, typename... Args>
|
||||||
|
auto Enqueue(Fn&& fn, Args&&... args) -> std::future<typename std::result_of<Fn(Args...)>::type> {
|
||||||
|
using return_type = typename std::result_of<Fn(Args...)>::type;
|
||||||
|
|
||||||
|
auto task = std::make_shared<std::packaged_task<return_type()>>(
|
||||||
|
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::future<return_type> res = task->get_future();
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_lock);
|
||||||
|
|
||||||
|
if (false == _running) {
|
||||||
|
throw std::runtime_error("Enqueue on stopped scheduler.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_tasks.emplace([task]() { (*task)(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
_cv.notify_one();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ProcessWork() {
|
||||||
|
for (;;) {
|
||||||
|
std::function<void()> work;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_lock);
|
||||||
|
_cv.wait(lock, [this] { return !_running || !_tasks.empty(); });
|
||||||
|
|
||||||
|
if (false == _running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
work = std::move(_tasks.front());
|
||||||
|
_tasks.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
work();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _running = true;
|
||||||
|
std::vector<std::thread> _threads;
|
||||||
|
std::mutex _lock;
|
||||||
|
std::condition_variable _cv;
|
||||||
|
std::queue<std::function<void()>> _tasks;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,8 +20,12 @@
|
|||||||
|
|
||||||
#include "account_management.h"
|
#include "account_management.h"
|
||||||
#include "login_server.h"
|
#include "login_server.h"
|
||||||
|
#include "../common/event/task_scheduler.h"
|
||||||
|
#include "../common/event/event_loop.h"
|
||||||
|
#include "../common/net/dns.h"
|
||||||
|
|
||||||
extern LoginServer server;
|
extern LoginServer server;
|
||||||
|
EQ::Event::TaskScheduler task_runner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param username
|
* @param username
|
||||||
@ -238,3 +242,100 @@ bool AccountManagement::UpdateLoginserverUserCredentials(
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AccountManagement::CheckExternalLoginserverUserCredentials(const std::string &in_account_username, const std::string &in_account_password)
|
||||||
|
{
|
||||||
|
auto res = task_runner.Enqueue([&]() -> bool {
|
||||||
|
bool running = true;
|
||||||
|
bool ret = false;
|
||||||
|
EQ::Net::DaybreakConnectionManager mgr;
|
||||||
|
std::shared_ptr<EQ::Net::DaybreakConnection> c;
|
||||||
|
|
||||||
|
mgr.OnNewConnection([&](std::shared_ptr<EQ::Net::DaybreakConnection> connection) {
|
||||||
|
c = connection;
|
||||||
|
});
|
||||||
|
|
||||||
|
mgr.OnConnectionStateChange([&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) {
|
||||||
|
if (EQ::Net::StatusConnected == to) {
|
||||||
|
EQ::Net::DynamicPacket p;
|
||||||
|
p.PutUInt16(0, 1); //OP_SessionReady
|
||||||
|
p.PutUInt32(2, 2);
|
||||||
|
c->QueuePacket(p);
|
||||||
|
}
|
||||||
|
else if (EQ::Net::StatusDisconnected == to) {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mgr.OnPacketRecv([&](std::shared_ptr<EQ::Net::DaybreakConnection> conn, const EQ::Net::Packet &p) {
|
||||||
|
auto opcode = p.GetUInt16(0);
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x0017: //OP_ChatMessage
|
||||||
|
{
|
||||||
|
size_t buffer_len = in_account_username.length() + in_account_password.length() + 2;
|
||||||
|
std::unique_ptr<char[]> buffer(new char[buffer_len]);
|
||||||
|
|
||||||
|
strcpy(&buffer[0], in_account_username.c_str());
|
||||||
|
strcpy(&buffer[in_account_username.length() + 1], in_account_password.c_str());
|
||||||
|
|
||||||
|
size_t encrypted_len = buffer_len;
|
||||||
|
|
||||||
|
if (encrypted_len % 8 > 0) {
|
||||||
|
encrypted_len = ((encrypted_len / 8) + 1) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQ::Net::DynamicPacket p;
|
||||||
|
p.Resize(12 + encrypted_len);
|
||||||
|
p.PutUInt16(0, 2); //OP_Login
|
||||||
|
p.PutUInt32(2, 3);
|
||||||
|
|
||||||
|
eqcrypt_block(&buffer[0], buffer_len, (char*)p.Data() + 12, true);
|
||||||
|
c->QueuePacket(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x0018:
|
||||||
|
{
|
||||||
|
auto encrypt_size = p.Length() - 12;
|
||||||
|
if (encrypt_size % 8 > 0) {
|
||||||
|
encrypt_size = (encrypt_size / 8) * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<char[]> decrypted(new char[encrypt_size]);
|
||||||
|
|
||||||
|
eqcrypt_block((char*)p.Data() + 12, encrypt_size, &decrypted[0], false);
|
||||||
|
|
||||||
|
EQ::Net::StaticPacket sp(&decrypted[0], encrypt_size);
|
||||||
|
auto response_error = sp.GetUInt16(1);
|
||||||
|
|
||||||
|
if (response_error > 101) {
|
||||||
|
ret = false;
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = true;
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
EQ::Net::DNSLookup("login.eqemulator.net", 5999, false, [&](const std::string &addr) {
|
||||||
|
if (addr == "") {
|
||||||
|
ret = false;
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr.Connect(addr, 5999);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto &loop = EQ::EventLoop::Get();
|
||||||
|
while (true == running) {
|
||||||
|
loop.Process();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.get();
|
||||||
|
}
|
||||||
|
|||||||
@ -70,6 +70,16 @@ public:
|
|||||||
const std::string &in_account_password,
|
const std::string &in_account_password,
|
||||||
const std::string &source_loginserver = "local"
|
const std::string &source_loginserver = "local"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param in_account_username
|
||||||
|
* @param in_account_password
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static bool CheckExternalLoginserverUserCredentials(
|
||||||
|
const std::string &in_account_username,
|
||||||
|
const std::string &in_account_password
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -51,6 +51,7 @@ namespace LoginserverCommandHandler {
|
|||||||
* Register commands
|
* Register commands
|
||||||
*/
|
*/
|
||||||
function_map["login-user:check-credentials"] = &LoginserverCommandHandler::CheckLoginserverUserCredentials;
|
function_map["login-user:check-credentials"] = &LoginserverCommandHandler::CheckLoginserverUserCredentials;
|
||||||
|
function_map["login-user:check-external-credentials"] = &LoginserverCommandHandler::CheckExternalLoginserverUserCredentials;
|
||||||
function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount;
|
function_map["login-user:create"] = &LoginserverCommandHandler::CreateLocalLoginserverAccount;
|
||||||
function_map["login-user:update-credentials"] = &LoginserverCommandHandler::UpdateLoginserverUserCredentials;
|
function_map["login-user:update-credentials"] = &LoginserverCommandHandler::UpdateLoginserverUserCredentials;
|
||||||
function_map["web-api-token:create"] = &LoginserverCommandHandler::CreateLoginserverApiToken;
|
function_map["web-api-token:create"] = &LoginserverCommandHandler::CreateLoginserverApiToken;
|
||||||
@ -203,10 +204,12 @@ namespace LoginserverCommandHandler {
|
|||||||
|
|
||||||
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||||
|
|
||||||
AccountManagement::CheckLoginserverUserCredentials(
|
auto res = AccountManagement::CheckLoginserverUserCredentials(
|
||||||
cmd("--username").str(),
|
cmd("--username").str(),
|
||||||
cmd("--password").str()
|
cmd("--password").str()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
LogInfo("Credentials were {0}", res == true ? "accepted" : "not accepted");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -236,4 +239,34 @@ namespace LoginserverCommandHandler {
|
|||||||
cmd("--password").str()
|
cmd("--password").str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @param cmd
|
||||||
|
* @param description
|
||||||
|
*/
|
||||||
|
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||||
|
{
|
||||||
|
description = "Check user external login credentials";
|
||||||
|
|
||||||
|
std::vector<std::string> arguments = {
|
||||||
|
"--username",
|
||||||
|
"--password"
|
||||||
|
};
|
||||||
|
std::vector<std::string> options = {};
|
||||||
|
|
||||||
|
if (cmd[{"-h", "--help"}]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
|
||||||
|
|
||||||
|
auto res = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||||
|
cmd("--username").str(),
|
||||||
|
cmd("--password").str()
|
||||||
|
);
|
||||||
|
|
||||||
|
LogInfo("Credentials were {0}", res == true ? "accepted" : "not accepted");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ namespace LoginserverCommandHandler {
|
|||||||
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description);
|
void CreateLoginserverWorldAdminAccount(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
void CheckLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
void UpdateLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
|
void CheckExternalLoginserverUserCredentials(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -158,6 +158,36 @@ namespace LoginserverWebserver {
|
|||||||
LoginserverWebserver::SendResponse(response, res);
|
LoginserverWebserver::SendResponse(response, res);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
api.Post(
|
||||||
|
"/account/credentials/validate/external", [](const httplib::Request &request, httplib::Response &res) {
|
||||||
|
LoginserverWebserver::TokenManager::AuthCanRead(request, res);
|
||||||
|
Json::Value request_body = LoginserverWebserver::ParseRequestBody(request);
|
||||||
|
std::string username = request_body.get("username", "").asString();
|
||||||
|
std::string password = request_body.get("password", "").asString();
|
||||||
|
|
||||||
|
Json::Value response;
|
||||||
|
if (username.empty() || password.empty()) {
|
||||||
|
response["error"] = "Username or password not set";
|
||||||
|
LoginserverWebserver::SendResponse(response, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool credentials_valid = AccountManagement::CheckExternalLoginserverUserCredentials(
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
);
|
||||||
|
|
||||||
|
if (credentials_valid) {
|
||||||
|
response["message"] = "Credentials valid!";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
response["error"] = "Credentials invalid!";
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginserverWebserver::SendResponse(response, res);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -351,4 +381,4 @@ namespace LoginserverWebserver {
|
|||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user