implement advanced permissions system
This commit is contained in:
parent
704366a2a0
commit
d4c52e9b65
@ -25,9 +25,9 @@ SOURCES += src/advertiser.cpp \
|
|||||||
src/aoclient.cpp \
|
src/aoclient.cpp \
|
||||||
src/aopacket.cpp \
|
src/aopacket.cpp \
|
||||||
src/area_data.cpp \
|
src/area_data.cpp \
|
||||||
src/ban_manager.cpp \
|
|
||||||
src/commands.cpp \
|
src/commands.cpp \
|
||||||
src/config_manager.cpp \
|
src/config_manager.cpp \
|
||||||
|
src/db_manager.cpp \
|
||||||
src/icchatpacket.cpp \
|
src/icchatpacket.cpp \
|
||||||
src/main.cpp \
|
src/main.cpp \
|
||||||
src/packets.cpp \
|
src/packets.cpp \
|
||||||
@ -40,8 +40,8 @@ HEADERS += include/advertiser.h \
|
|||||||
include/aoclient.h \
|
include/aoclient.h \
|
||||||
include/aopacket.h \
|
include/aopacket.h \
|
||||||
include/area_data.h \
|
include/area_data.h \
|
||||||
include/ban_manager.h \
|
|
||||||
include/config_manager.h \
|
include/config_manager.h \
|
||||||
|
include/db_manager.h \
|
||||||
include/icchatpacket.h \
|
include/icchatpacket.h \
|
||||||
include/server.h \
|
include/server.h \
|
||||||
include/ws_client.h \
|
include/ws_client.h \
|
||||||
|
@ -7,7 +7,6 @@ hostname=$H
|
|||||||
language=en
|
language=en
|
||||||
max_message_size=256
|
max_message_size=256
|
||||||
max_players=100
|
max_players=100
|
||||||
modpass=password
|
|
||||||
ms_ip=master.aceattorneyonline.com
|
ms_ip=master.aceattorneyonline.com
|
||||||
ms_port=27016
|
ms_port=27016
|
||||||
multiclient_limit=16
|
multiclient_limit=16
|
||||||
@ -16,7 +15,5 @@ server_description=This is a placeholder server description. Tell the world of A
|
|||||||
server_name=An Unnamed Server
|
server_name=An Unnamed Server
|
||||||
webao_enable=true
|
webao_enable=true
|
||||||
webao_port=27017
|
webao_port=27017
|
||||||
|
auth=simple
|
||||||
[Moderators]
|
modpass=changeme
|
||||||
; Make sure you change this before running your server!
|
|
||||||
password_change_me=user_change_me
|
|
@ -22,12 +22,14 @@
|
|||||||
#include "include/server.h"
|
#include "include/server.h"
|
||||||
#include "include/icchatpacket.h"
|
#include "include/icchatpacket.h"
|
||||||
#include "include/area_data.h"
|
#include "include/area_data.h"
|
||||||
|
#include "include/db_manager.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
class Server;
|
class Server;
|
||||||
|
|
||||||
@ -48,8 +50,16 @@ class AOClient : public QObject {
|
|||||||
int current_area;
|
int current_area;
|
||||||
QString current_char;
|
QString current_char;
|
||||||
bool authenticated = false;
|
bool authenticated = false;
|
||||||
|
QString moderator_name = "";
|
||||||
QString ooc_name = "";
|
QString ooc_name = "";
|
||||||
|
|
||||||
|
enum ACLFlags {
|
||||||
|
NONE = 0ULL,
|
||||||
|
KICK = 1ULL << 0,
|
||||||
|
BAN = 1ULL << 1,
|
||||||
|
SUPER = ~0ULL
|
||||||
|
};
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clientDisconnected();
|
void clientDisconnected();
|
||||||
void clientData();
|
void clientData();
|
||||||
@ -74,6 +84,7 @@ class AOClient : public QObject {
|
|||||||
void arup(ARUPType type, bool broadcast);
|
void arup(ARUPType type, bool broadcast);
|
||||||
void fullArup();
|
void fullArup();
|
||||||
void sendServerMessage(QString message);
|
void sendServerMessage(QString message);
|
||||||
|
bool checkAuth(unsigned long long acl_mask);
|
||||||
|
|
||||||
// Packet headers
|
// Packet headers
|
||||||
void pktDefault(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
void pktDefault(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
||||||
@ -94,26 +105,27 @@ class AOClient : public QObject {
|
|||||||
void pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
void pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPacket packet);
|
||||||
|
|
||||||
struct PacketInfo {
|
struct PacketInfo {
|
||||||
|
unsigned long long acl_mask;
|
||||||
int minArgs;
|
int minArgs;
|
||||||
void (AOClient::*action)(AreaData*, int, QStringList, AOPacket);
|
void (AOClient::*action)(AreaData*, int, QStringList, AOPacket);
|
||||||
};
|
};
|
||||||
|
|
||||||
const QMap<QString, PacketInfo> packets {
|
const QMap<QString, PacketInfo> packets {
|
||||||
{"HI", {1, &AOClient::pktHardwareId}},
|
{"HI", {ACLFlags::NONE, 1, &AOClient::pktHardwareId}},
|
||||||
{"ID", {2, &AOClient::pktSoftwareId}},
|
{"ID", {ACLFlags::NONE, 2, &AOClient::pktSoftwareId}},
|
||||||
{"askchaa", {0, &AOClient::pktBeginLoad}},
|
{"askchaa", {ACLFlags::NONE, 0, &AOClient::pktBeginLoad}},
|
||||||
{"RC", {0, &AOClient::pktRequestChars}},
|
{"RC", {ACLFlags::NONE, 0, &AOClient::pktRequestChars}},
|
||||||
{"RM", {0, &AOClient::pktRequestMusic}},
|
{"RM", {ACLFlags::NONE, 0, &AOClient::pktRequestMusic}},
|
||||||
{"RD", {0, &AOClient::pktLoadingDone}},
|
{"RD", {ACLFlags::NONE, 0, &AOClient::pktLoadingDone}},
|
||||||
{"PW", {1, &AOClient::pktCharPassword}},
|
{"PW", {ACLFlags::NONE, 1, &AOClient::pktCharPassword}},
|
||||||
{"CC", {3, &AOClient::pktSelectChar}},
|
{"CC", {ACLFlags::NONE, 3, &AOClient::pktSelectChar}},
|
||||||
{"MS", {1, &AOClient::pktIcChat}}, // TODO: doublecheck
|
{"MS", {ACLFlags::NONE, 1, &AOClient::pktIcChat}}, // TODO: doublecheck
|
||||||
{"CT", {2, &AOClient::pktOocChat}},
|
{"CT", {ACLFlags::NONE, 2, &AOClient::pktOocChat}},
|
||||||
{"CH", {1, &AOClient::pktPing}},
|
{"CH", {ACLFlags::NONE, 1, &AOClient::pktPing}},
|
||||||
{"MC", {2, &AOClient::pktChangeMusic}},
|
{"MC", {ACLFlags::NONE, 2, &AOClient::pktChangeMusic}},
|
||||||
{"RT", {1, &AOClient::pktWtCe}},
|
{"RT", {ACLFlags::NONE, 1, &AOClient::pktWtCe}},
|
||||||
{"HP", {2, &AOClient::pktHpBar}},
|
{"HP", {ACLFlags::NONE, 2, &AOClient::pktHpBar}},
|
||||||
{"WSIP", {1, &AOClient::pktWebSocketIp}}
|
{"WSIP", {ACLFlags::NONE, 1, &AOClient::pktWebSocketIp}}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
@ -123,22 +135,29 @@ class AOClient : public QObject {
|
|||||||
void cmdGetArea(int argc, QStringList argv);
|
void cmdGetArea(int argc, QStringList argv);
|
||||||
void cmdBan(int argc, QStringList argv);
|
void cmdBan(int argc, QStringList argv);
|
||||||
void cmdKick(int argc, QStringList argv);
|
void cmdKick(int argc, QStringList argv);
|
||||||
|
void cmdChangeAuth(int argc, QStringList argv);
|
||||||
|
void cmdSetRootPass(int argc, QStringList argv);
|
||||||
|
|
||||||
// Command helper functions
|
// Command helper functions
|
||||||
QStringList buildAreaList(int area_idx);
|
QStringList buildAreaList(int area_idx);
|
||||||
|
|
||||||
|
// Command function global variables
|
||||||
|
bool change_auth_started = false;
|
||||||
|
|
||||||
struct CommandInfo {
|
struct CommandInfo {
|
||||||
bool privileged;
|
unsigned long long acl_mask;
|
||||||
int minArgs;
|
int minArgs;
|
||||||
void (AOClient::*action)(int, QStringList);
|
void (AOClient::*action)(int, QStringList);
|
||||||
};
|
};
|
||||||
|
|
||||||
const QMap<QString, CommandInfo> commands {
|
const QMap<QString, CommandInfo> commands {
|
||||||
{"login", {false, 1, &AOClient::cmdLogin}},
|
{"login", {ACLFlags::NONE, 1, &AOClient::cmdLogin}},
|
||||||
{"getareas", {false, 0 , &AOClient::cmdGetAreas}},
|
{"getareas", {ACLFlags::NONE, 0 , &AOClient::cmdGetAreas}},
|
||||||
{"getarea", {false, 0, &AOClient::cmdGetArea}},
|
{"getarea", {ACLFlags::NONE, 0, &AOClient::cmdGetArea}},
|
||||||
{"ban", {true, 2, &AOClient::cmdBan}},
|
{"ban", {ACLFlags::BAN, 2, &AOClient::cmdBan}},
|
||||||
{"kick", {true, 2, &AOClient::cmdKick}}
|
{"kick", {ACLFlags::KICK, 2, &AOClient::cmdKick}},
|
||||||
|
{"changeauth", {ACLFlags::SUPER, 0, &AOClient::cmdChangeAuth}},
|
||||||
|
{"rootpass", {ACLFlags::SUPER, 1, &AOClient::cmdSetRootPass}}
|
||||||
};
|
};
|
||||||
|
|
||||||
QString partial_packet;
|
QString partial_packet;
|
||||||
|
@ -18,18 +18,21 @@
|
|||||||
#ifndef BAN_MANAGER_H
|
#ifndef BAN_MANAGER_H
|
||||||
#define BAN_MANAGER_H
|
#define BAN_MANAGER_H
|
||||||
|
|
||||||
|
#include "include/aoclient.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
#include <QMessageAuthenticationCode>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QSqlDatabase>
|
#include <QSqlDatabase>
|
||||||
#include <QSqlDriver>
|
#include <QSqlDriver>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
|
|
||||||
class BanManager{
|
class DBManager{
|
||||||
public:
|
public:
|
||||||
BanManager();
|
DBManager();
|
||||||
~BanManager();
|
~DBManager();
|
||||||
|
|
||||||
bool isIPBanned(QHostAddress ip);
|
bool isIPBanned(QHostAddress ip);
|
||||||
bool isHDIDBanned(QString hdid);
|
bool isHDIDBanned(QString hdid);
|
||||||
@ -39,8 +42,16 @@ public:
|
|||||||
|
|
||||||
void addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason);
|
void addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason);
|
||||||
|
|
||||||
|
void createUser(QString username, QString salt, QString password, unsigned long long acl);
|
||||||
|
unsigned long long getACL(QString moderator_name);
|
||||||
|
bool authenticate(QString username, QString password);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString DRIVER;
|
const QString DRIVER;
|
||||||
|
const QString CONN_NAME;
|
||||||
|
|
||||||
|
void openDB();
|
||||||
|
|
||||||
QSqlDatabase db;
|
QSqlDatabase db;
|
||||||
};
|
};
|
||||||
|
|
@ -22,7 +22,7 @@
|
|||||||
#include "include/aopacket.h"
|
#include "include/aopacket.h"
|
||||||
#include "include/area_data.h"
|
#include "include/area_data.h"
|
||||||
#include "include/ws_proxy.h"
|
#include "include/ws_proxy.h"
|
||||||
#include "include/ban_manager.h"
|
#include "include/db_manager.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@ -34,6 +34,7 @@
|
|||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
|
||||||
class AOClient;
|
class AOClient;
|
||||||
|
class DBManager;
|
||||||
|
|
||||||
class Server : public QObject {
|
class Server : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -55,7 +56,7 @@ class Server : public QObject {
|
|||||||
QVector<AreaData*> areas;
|
QVector<AreaData*> areas;
|
||||||
QStringList area_names;
|
QStringList area_names;
|
||||||
QStringList music_list;
|
QStringList music_list;
|
||||||
BanManager* ban_manager;
|
DBManager* db_manager;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
@ -73,7 +73,12 @@ void AOClient::handlePacket(AOPacket packet)
|
|||||||
// TODO: like everything here should send a signal
|
// TODO: like everything here should send a signal
|
||||||
// qDebug() << "Received packet:" << packet.header << ":" << packet.contents;
|
// qDebug() << "Received packet:" << packet.header << ":" << packet.contents;
|
||||||
AreaData* area = server->areas[current_area];
|
AreaData* area = server->areas[current_area];
|
||||||
PacketInfo info = packets.value(packet.header, {0, &AOClient::pktDefault});
|
PacketInfo info = packets.value(packet.header, {false, 0, &AOClient::pktDefault});
|
||||||
|
|
||||||
|
if (!checkAuth(info.acl_mask)) {
|
||||||
|
qDebug() << "Unauthenticated client" << getIpid() << "attempted to use privileged packet" << packet.header;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (packet.contents.length() < info.minArgs) {
|
if (packet.contents.length() < info.minArgs) {
|
||||||
qDebug() << "Invalid packet args length. Minimum is" << info.minArgs << "but only" << packet.contents.length() << "were given.";
|
qDebug() << "Invalid packet args length. Minimum is" << info.minArgs << "but only" << packet.contents.length() << "were given.";
|
||||||
@ -122,7 +127,7 @@ void AOClient::handleCommand(QString command, int argc, QStringList argv)
|
|||||||
{
|
{
|
||||||
CommandInfo info = commands.value(command, {false, -1, &AOClient::cmdDefault});
|
CommandInfo info = commands.value(command, {false, -1, &AOClient::cmdDefault});
|
||||||
|
|
||||||
if (info.privileged && !authenticated) {
|
if (!checkAuth(info.acl_mask)) {
|
||||||
sendServerMessage("You do not have permission to use that command.");
|
sendServerMessage("You do not have permission to use that command.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -210,6 +215,30 @@ void AOClient::sendServerMessage(QString message)
|
|||||||
sendPacket("CT", {"Server", message, "1"});
|
sendPacket("CT", {"Server", message, "1"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AOClient::checkAuth(unsigned long long acl_mask)
|
||||||
|
{
|
||||||
|
if (acl_mask != ACLFlags::NONE) {
|
||||||
|
if (!authenticated) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSettings settings("config/config.ini", QSettings::IniFormat);
|
||||||
|
settings.beginGroup("Options");
|
||||||
|
QString auth_type = settings.value("auth", "simple").toString();
|
||||||
|
qDebug() << "auth type" << auth_type;
|
||||||
|
if (auth_type == "advanced") {
|
||||||
|
unsigned long long user_acl = server->db_manager->getACL(moderator_name);
|
||||||
|
qDebug() << "checking with advanced auth";
|
||||||
|
qDebug() << "got acl" << QString::number(user_acl, 16).toUpper() << "for user" << moderator_name;
|
||||||
|
return (user_acl & acl_mask) != 0;
|
||||||
|
}
|
||||||
|
else if (auth_type == "simple") {
|
||||||
|
return authenticated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QString AOClient::getIpid() { return ipid; }
|
QString AOClient::getIpid() { return ipid; }
|
||||||
|
|
||||||
AOClient::~AOClient() {
|
AOClient::~AOClient() {
|
||||||
|
@ -29,14 +29,34 @@ void AOClient::cmdLogin(int argc, QStringList argv)
|
|||||||
{
|
{
|
||||||
QSettings config("config/config.ini", QSettings::IniFormat);
|
QSettings config("config/config.ini", QSettings::IniFormat);
|
||||||
config.beginGroup("Options");
|
config.beginGroup("Options");
|
||||||
QString modpass = config.value("modpass", "default").toString();;
|
QString modpass = config.value("modpass", "default").toString();
|
||||||
|
QString auth_type = config.value("auth", "simple").toString();
|
||||||
|
|
||||||
// TODO: tell the user if no modpass is set
|
// TODO: tell the user if no modpass is set
|
||||||
if(argv[0] == modpass) {
|
if (auth_type == "simple") {
|
||||||
sendServerMessage("Logged in as a moderator."); // This string has to be exactly this, because it is hardcoded in the client
|
if(argv[0] == modpass) {
|
||||||
authenticated = true;
|
sendServerMessage("Logged in as a moderator."); // This string has to be exactly this, because it is hardcoded in the client
|
||||||
} else {
|
authenticated = true;
|
||||||
sendServerMessage("Incorrect password.");
|
} else {
|
||||||
return;
|
sendServerMessage("Incorrect password.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (argc < 2) {
|
||||||
|
sendServerMessage("You must specify a username and a password");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString username = argv[0];
|
||||||
|
QString password = argv[1];
|
||||||
|
if (server->db_manager->authenticate(username, password)) {
|
||||||
|
moderator_name = username;
|
||||||
|
authenticated = true;
|
||||||
|
sendServerMessage("Logged in as " + username);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendServerMessage("Incorrect password.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +97,7 @@ void AOClient::cmdBan(int argc, QStringList argv)
|
|||||||
if (!ban_logged) {
|
if (!ban_logged) {
|
||||||
ip = client->remote_ip;
|
ip = client->remote_ip;
|
||||||
hdid = client->hwid;
|
hdid = client->hwid;
|
||||||
server->ban_manager->addBan(target_ipid, ip, hdid, time, reason);
|
server->db_manager->addBan(target_ipid, ip, hdid, time, reason);
|
||||||
sendServerMessage("Banned user with ipid " + target_ipid + " for reason: " + reason);
|
sendServerMessage("Banned user with ipid " + target_ipid + " for reason: " + reason);
|
||||||
ban_logged = true;
|
ban_logged = true;
|
||||||
}
|
}
|
||||||
@ -116,6 +136,35 @@ void AOClient::cmdKick(int argc, QStringList argv)
|
|||||||
sendServerMessage("User with ipid not found!");
|
sendServerMessage("User with ipid not found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdChangeAuth(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
QSettings settings("config/config.ini", QSettings::IniFormat);
|
||||||
|
settings.beginGroup("Options");
|
||||||
|
QString auth_type = settings.value("auth", "simple").toString();
|
||||||
|
|
||||||
|
if (auth_type == "simple") {
|
||||||
|
change_auth_started = true;
|
||||||
|
sendServerMessage("WARNING!\nThis command will change how logging in as a moderator works.\nOnly proceed if you know what you are doing\nUse the command /rootpass to set the password for your root account.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AOClient::cmdSetRootPass(int argc, QStringList argv)
|
||||||
|
{
|
||||||
|
if (!change_auth_started)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sendServerMessage("Changing auth type and setting root password.\nLogin again with /login root [password]");
|
||||||
|
authenticated = false;
|
||||||
|
QSettings settings("config/config.ini", QSettings::IniFormat);
|
||||||
|
settings.beginGroup("Options");
|
||||||
|
settings.setValue("auth", "advanced");
|
||||||
|
|
||||||
|
quint64 salt_number = QRandomGenerator::system()->generate64();
|
||||||
|
QString salt = QStringLiteral("%1").arg(salt_number, 16, 16, QLatin1Char('0'));
|
||||||
|
|
||||||
|
server->db_manager->createUser("root", salt, argv[0], ACLFlags::SUPER);
|
||||||
|
}
|
||||||
|
|
||||||
QStringList AOClient::buildAreaList(int area_idx)
|
QStringList AOClient::buildAreaList(int area_idx)
|
||||||
{
|
{
|
||||||
QStringList entries;
|
QStringList entries;
|
||||||
|
@ -15,19 +15,20 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License //
|
// You should have received a copy of the GNU Affero General Public License //
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
#include "include/ban_manager.h"
|
#include "include/db_manager.h"
|
||||||
|
|
||||||
BanManager::BanManager() :
|
DBManager::DBManager() :
|
||||||
DRIVER("QSQLITE")
|
DRIVER("QSQLITE")
|
||||||
{
|
{
|
||||||
db = QSqlDatabase::addDatabase(DRIVER);
|
db = QSqlDatabase::addDatabase(DRIVER);
|
||||||
db.setDatabaseName("config/bans.db");
|
db.setDatabaseName("config/akashi.db");
|
||||||
if (!db.open())
|
if (!db.open())
|
||||||
qCritical() << "Database Error:" << db.lastError();
|
qCritical() << "Database Error:" << db.lastError();
|
||||||
QSqlQuery create_table_query("CREATE TABLE IF NOT EXISTS bans ('ID' INTEGER, 'IPID' TEXT, 'HDID' TEXT, 'IP' TEXT, 'TIME' INTEGER, 'REASON' TEXT, PRIMARY KEY('ID' AUTOINCREMENT));");
|
QSqlQuery create_ban_table("CREATE TABLE IF NOT EXISTS bans ('ID' INTEGER, 'IPID' TEXT, 'HDID' TEXT, 'IP' TEXT, 'TIME' INTEGER, 'REASON' TEXT, PRIMARY KEY('ID' AUTOINCREMENT))");
|
||||||
|
QSqlQuery create_user_table("CREATE TABLE IF NOT EXISTS users ('ID' INTEGER, 'USERNAME' TEXT, 'SALT' TEXT, 'PASSWORD' TEXT, 'ACL' TEXT, PRIMARY KEY('ID' AUTOINCREMENT))");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BanManager::isIPBanned(QHostAddress ip)
|
bool DBManager::isIPBanned(QHostAddress ip)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT ID FROM BANS WHERE IP = ?");
|
query.prepare("SELECT ID FROM BANS WHERE IP = ?");
|
||||||
@ -36,7 +37,7 @@ bool BanManager::isIPBanned(QHostAddress ip)
|
|||||||
return query.first();
|
return query.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BanManager::isHDIDBanned(QString hdid)
|
bool DBManager::isHDIDBanned(QString hdid)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT ID FROM BANS WHERE HDID = ?");
|
query.prepare("SELECT ID FROM BANS WHERE HDID = ?");
|
||||||
@ -45,7 +46,7 @@ bool BanManager::isHDIDBanned(QString hdid)
|
|||||||
return query.first();
|
return query.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BanManager::getBanReason(QHostAddress ip)
|
QString DBManager::getBanReason(QHostAddress ip)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT REASON FROM BANS WHERE IP = ?");
|
query.prepare("SELECT REASON FROM BANS WHERE IP = ?");
|
||||||
@ -59,7 +60,7 @@ QString BanManager::getBanReason(QHostAddress ip)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BanManager::getBanReason(QString hdid)
|
QString DBManager::getBanReason(QString hdid)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("SELECT REASON FROM BANS WHERE HDID = ?");
|
query.prepare("SELECT REASON FROM BANS WHERE HDID = ?");
|
||||||
@ -73,7 +74,7 @@ QString BanManager::getBanReason(QString hdid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BanManager::addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason)
|
void DBManager::addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare("INSERT INTO BANS(IPID, HDID, IP, TIME, REASON) VALUES(?, ?, ?, ?, ?)");
|
query.prepare("INSERT INTO BANS(IPID, HDID, IP, TIME, REASON) VALUES(?, ?, ?, ?, ?)");
|
||||||
@ -86,7 +87,66 @@ void BanManager::addBan(QString ipid, QHostAddress ip, QString hdid, unsigned lo
|
|||||||
qDebug() << "SQL Error:" << query.lastError().text();
|
qDebug() << "SQL Error:" << query.lastError().text();
|
||||||
}
|
}
|
||||||
|
|
||||||
BanManager::~BanManager()
|
void DBManager::createUser(QString username, QString salt, QString password, unsigned long long acl)
|
||||||
|
{
|
||||||
|
QSqlQuery query;
|
||||||
|
|
||||||
|
QString salted_password;
|
||||||
|
QMessageAuthenticationCode hmac(QCryptographicHash::Sha256);
|
||||||
|
hmac.setKey(salt.toUtf8());
|
||||||
|
hmac.addData(password.toUtf8());
|
||||||
|
salted_password = hmac.result().toHex();
|
||||||
|
|
||||||
|
query.prepare("INSERT INTO users(USERNAME, SALT, PASSWORD, ACL) VALUES(?, ?, ?, ?)");
|
||||||
|
query.addBindValue(username);
|
||||||
|
query.addBindValue(salt);
|
||||||
|
query.addBindValue(salted_password);
|
||||||
|
query.addBindValue(acl);
|
||||||
|
query.exec();
|
||||||
|
|
||||||
|
qDebug() << "Created user" << username << "with password" << password << "and salted with value" << salt << ": stored as" << salted_password;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long DBManager::getACL(QString moderator_name)
|
||||||
|
{
|
||||||
|
if (moderator_name == "")
|
||||||
|
return AOClient::ACLFlags::NONE;
|
||||||
|
QSqlQuery query("SELECT ACL FROM users WHERE USERNAME = ?");
|
||||||
|
query.addBindValue(moderator_name);
|
||||||
|
query.exec();
|
||||||
|
if (!query.first())
|
||||||
|
return AOClient::ACLFlags::NONE;
|
||||||
|
return query.value(0).toULongLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DBManager::authenticate(QString username, QString password)
|
||||||
|
{
|
||||||
|
QSqlQuery query_salt("SELECT SALT FROM users WHERE USERNAME = ?");
|
||||||
|
query_salt.addBindValue(username);
|
||||||
|
query_salt.exec();
|
||||||
|
if (!query_salt.first())
|
||||||
|
return false;
|
||||||
|
QString salt = query_salt.value(0).toString();
|
||||||
|
|
||||||
|
QString salted_password;
|
||||||
|
QMessageAuthenticationCode hmac(QCryptographicHash::Sha256);
|
||||||
|
hmac.setKey(salt.toUtf8());
|
||||||
|
hmac.addData(password.toUtf8());
|
||||||
|
salted_password = hmac.result().toHex();
|
||||||
|
|
||||||
|
QSqlQuery query_pass("SELECT PASSWORD FROM users WHERE SALT = ?");
|
||||||
|
query_pass.addBindValue(salt);
|
||||||
|
query_pass.exec();
|
||||||
|
if (!query_pass.first())
|
||||||
|
return false;
|
||||||
|
QString stored_pass = query_pass.value(0).toString();
|
||||||
|
|
||||||
|
qDebug() << "Found DB entry Salt:" << salt << "Stored Password:" << stored_pass << "Calculated Password:" << salted_password;
|
||||||
|
|
||||||
|
return salted_password == stored_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBManager::~DBManager()
|
||||||
{
|
{
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
@ -26,8 +26,8 @@ void AOClient::pktDefault(AreaData* area, int argc, QStringList argv, AOPacket p
|
|||||||
void AOClient::pktHardwareId(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
void AOClient::pktHardwareId(AreaData* area, int argc, QStringList argv, AOPacket packet)
|
||||||
{
|
{
|
||||||
setHwid(argv[0]);
|
setHwid(argv[0]);
|
||||||
if(server->ban_manager->isHDIDBanned(getHwid())) {
|
if(server->db_manager->isHDIDBanned(getHwid())) {
|
||||||
sendPacket("BD", {server->ban_manager->getBanReason(getHwid())});
|
sendPacket("BD", {server->db_manager->getBanReason(getHwid())});
|
||||||
socket->close();
|
socket->close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket p
|
|||||||
QString command = cmd_argv[0].trimmed().toLower();
|
QString command = cmd_argv[0].trimmed().toLower();
|
||||||
command = command.right(command.length() - 1);
|
command = command.right(command.length() - 1);
|
||||||
cmd_argv.removeFirst();
|
cmd_argv.removeFirst();
|
||||||
int cmd_argc = argv.length();
|
int cmd_argc = cmd_argv.length();
|
||||||
handleCommand(command, cmd_argc, cmd_argv);
|
handleCommand(command, cmd_argc, cmd_argv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -209,8 +209,8 @@ void AOClient::pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPack
|
|||||||
// Special packet to set remote IP from the webao proxy
|
// Special packet to set remote IP from the webao proxy
|
||||||
// Only valid if from a local ip
|
// Only valid if from a local ip
|
||||||
if (remote_ip.isLoopback()) {
|
if (remote_ip.isLoopback()) {
|
||||||
if(server->ban_manager->isIPBanned(QHostAddress(argv[0]))) {
|
if(server->db_manager->isIPBanned(QHostAddress(argv[0]))) {
|
||||||
sendPacket("BD", {server->ban_manager->getBanReason(QHostAddress(argv[0]))});
|
sendPacket("BD", {server->db_manager->getBanReason(QHostAddress(argv[0]))});
|
||||||
socket->close();
|
socket->close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ Server::Server(int p_port, int p_ws_port, QObject* parent) : QObject(parent)
|
|||||||
|
|
||||||
player_count = 0;
|
player_count = 0;
|
||||||
|
|
||||||
ban_manager = new BanManager();
|
db_manager = new DBManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::start()
|
void Server::start()
|
||||||
@ -79,8 +79,8 @@ void Server::clientConnected()
|
|||||||
{
|
{
|
||||||
QTcpSocket* socket = server->nextPendingConnection();
|
QTcpSocket* socket = server->nextPendingConnection();
|
||||||
AOClient* client = new AOClient(this, socket, this);
|
AOClient* client = new AOClient(this, socket, this);
|
||||||
if (ban_manager->isIPBanned(socket->peerAddress())) {
|
if (db_manager->isIPBanned(socket->peerAddress())) {
|
||||||
AOPacket ban_reason("BD", {ban_manager->getBanReason(socket->peerAddress())});
|
AOPacket ban_reason("BD", {db_manager->getBanReason(socket->peerAddress())});
|
||||||
socket->write(ban_reason.toUtf8());
|
socket->write(ban_reason.toUtf8());
|
||||||
socket->flush();
|
socket->flush();
|
||||||
client->deleteLater();
|
client->deleteLater();
|
||||||
@ -149,4 +149,6 @@ Server::~Server()
|
|||||||
}
|
}
|
||||||
server->deleteLater();
|
server->deleteLater();
|
||||||
proxy->deleteLater();
|
proxy->deleteLater();
|
||||||
|
|
||||||
|
delete db_manager;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user