This commit is contained in:
in1tiate 2021-03-14 12:13:13 -05:00
commit 535c05f3e2
7 changed files with 206 additions and 32 deletions

View File

@ -10,4 +10,8 @@ Requires Qt >= 5.10, and Qt websockets
make
```
Copyright © scatterflower 2021
Copyright © scatterflower 2020-2021
Copyright © Salanto 2021
Copyright © in1tiate 2021

View File

@ -42,10 +42,9 @@ class AOClient : public QObject {
AOClient(Server* p_server, QTcpSocket* p_socket, QObject* parent = nullptr, int user_id = 0);
~AOClient();
QString getHwid();
QString getIpid();
Server* getServer();
void setHwid(QString p_hwid);
QString getIpid();
void calculateIpid();
int id;
@ -59,6 +58,7 @@ class AOClient : public QObject {
QString ooc_name = "";
QString showname = "";
bool global_enabled = true;
bool is_muted = false;
struct ClientVersion {
QString string;
int release = -1;
@ -79,6 +79,7 @@ class AOClient : public QObject {
{"MOTD", 1ULL << 7},
{"ANNOUNCE", 1ULL << 8},
{"MODCHAT", 1ULL << 9},
{"MUTE", 1ULL << 10},
{"SUPER", ~0ULL}
};
@ -221,6 +222,8 @@ class AOClient : public QObject {
void cmdAnnounce(int argc, QStringList argv);
void cmdM(int argc, QStringList argv);
void cmdGM(int argc, QStringList argv);
void cmdMute(int argc, QStringList argv);
void cmdUnmute(int argc, QStringList argv);
// Casing/RP
void cmdPlay(int argc, QStringList argv);
void cmdNeed(int argc, QStringList argv);
@ -245,6 +248,7 @@ class AOClient : public QObject {
QStringList buildAreaList(int area_idx);
int genRand(int min, int max);
void diceThrower(int argc, QStringList argv, RollType Type);
long long parseTime(QString input);
// Command function global variables
bool change_auth_started = false;
@ -309,7 +313,9 @@ class AOClient : public QObject {
{"motd", {ACLFlags.value("NONE"), 0, &AOClient::cmdMOTD}},
{"announce", {ACLFlags.value("ANNOUNCE"), 1, &AOClient::cmdAnnounce}},
{"m", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdM}},
{"gm", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdGM}}
{"gm", {ACLFlags.value("MODCHAT"), 1, &AOClient::cmdGM}},
{"mute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdMute}},
{"unmute", {ACLFlags.value("MUTE"), 1, &AOClient::cmdUnmute}}
};
QString partial_packet;

View File

@ -19,6 +19,7 @@
#define BAN_MANAGER_H
#include <QDebug>
#include <QDateTime>
#include <QHostAddress>
#include <QMessageAuthenticationCode>
#include <QString>
@ -37,8 +38,10 @@ public:
QString getBanReason(QHostAddress ip);
QString getBanReason(QString hdid);
long long getBanDuration(QString hdid);
long long getBanDuration(QHostAddress hdid);
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, long long duration);
bool createUser(QString username, QString salt, QString password, unsigned long long acl);
unsigned long long getACL(QString moderator_name);

View File

@ -28,6 +28,7 @@ AOClient::AOClient(Server* p_server, QTcpSocket* p_socket, QObject* parent, int
current_area = 0;
current_char = "";
remote_ip = p_socket->peerAddress();
calculateIpid();
is_partial = false;
last_wtce_time = 0;
last_message = "";
@ -274,22 +275,17 @@ void AOClient::sendPacket(QString header)
sendPacket(AOPacket(header, {}));
}
QString AOClient::getHwid() { return hwid; }
void AOClient::setHwid(QString p_hwid)
void AOClient::calculateIpid()
{
// TODO: add support for longer hwids?
// TODO: add support for longer ipids?
// This reduces the (fairly high) chance of
// birthday paradox issues arising. However,
// typing more than 8 characters might be a
// bit cumbersome.
hwid = p_hwid;
QCryptographicHash hash(
QCryptographicHash::Md5); // Don't need security, just
// hashing for uniqueness
QString concat_ip_id = remote_ip.toString() + p_hwid;
hash.addData(concat_ip_id.toUtf8());
QCryptographicHash hash(QCryptographicHash::Md5); // Don't need security, just hashing for uniqueness
hash.addData(remote_ip.toString().toUtf8());
ipid = hash.result().toHex().right(8); // Use the last 8 characters (4 bytes)
}

View File

@ -89,11 +89,47 @@ void AOClient::cmdGetArea(int argc, QStringList argv)
void AOClient::cmdBan(int argc, QStringList argv)
{
QString args_str = argv[1];
if (argc > 2) {
for (int i = 2; i < argc; i++)
args_str += " " + argv[i];
}
QRegularExpression quoteMatcher("['\"](.+?)[\"']");
QRegularExpressionMatchIterator matches = quoteMatcher.globalMatch(args_str);
QList<QString> unquoted_args;
while (matches.hasNext()) {
QRegularExpressionMatch match = matches.next();
unquoted_args.append(match.captured(1));
}
QString reason;
QString duration = "perma";
if (unquoted_args.length() < 1) {
sendServerMessage("Invalid syntax. Usage:\n/ban <ipid> \"<reason>\" \"<duration>\"");
return;
}
reason = unquoted_args.at(0);
if (unquoted_args.length() > 1)
duration = unquoted_args.at(1);
long long duration_seconds = 0;
if (duration == "perma")
duration_seconds = -2;
else
duration_seconds = parseTime(duration);
if (duration_seconds == -1) {
sendServerMessage("Invalid time format. Format example: 1h30m");
return;
}
QString target_ipid = argv[0];
QHostAddress ip;
QString hdid;
unsigned long time = QDateTime::currentDateTime().toTime_t();
QString reason = argv[1];
unsigned long time = QDateTime::currentDateTime().toSecsSinceEpoch();
bool ban_logged = false;
int kick_counter = 0;
@ -107,7 +143,7 @@ void AOClient::cmdBan(int argc, QStringList argv)
if (!ban_logged) {
ip = client->remote_ip;
hdid = client->hwid;
server->db_manager->addBan(target_ipid, ip, hdid, time, reason);
server->db_manager->addBan(target_ipid, ip, hdid, time, reason, duration_seconds);
sendServerMessage("Banned user with ipid " + target_ipid + " for reason: " + reason);
ban_logged = true;
}
@ -903,6 +939,38 @@ void AOClient::cmdGM(int argc, QStringList argv)
}
}
void AOClient::cmdMute(int argc, QStringList argv)
{
bool conv_ok = false;
int uid = argv[0].toInt(&conv_ok);
if (!conv_ok) {
sendServerMessage("Invalid user ID.");
return;
}
if (server->getClientByID(uid)->is_muted)
sendServerMessage("That player is already muted!");
else
sendServerMessage("Muted player.");
server->getClientByID(uid)->is_muted = true;
}
void AOClient::cmdUnmute(int argc, QStringList argv)
{
bool conv_ok = false;
int uid = argv[0].toInt(&conv_ok);
if (!conv_ok) {
sendServerMessage("Invalid user ID.");
return;
}
if (!server->getClientByID(uid)->is_muted)
sendServerMessage("That player is already unmuted!");
else
sendServerMessage("Unmuted player.");
server->getClientByID(uid)->is_muted = false;
}
QStringList AOClient::buildAreaList(int area_idx)
{
QStringList entries;
@ -1019,3 +1087,45 @@ QString AOClient::getAreaTimer(int area_idx, QTimer* timer)
}
}
long long AOClient::parseTime(QString input)
{
QRegularExpression regex("(?:(?:(?<year>.*?)y)*(?:(?<week>.*?)w)*(?:(?<day>.*?)d)*(?:(?<hr>.*?)h)*(?:(?<min>.*?)m)*(?:(?<sec>.*?)s)*)");
QRegularExpressionMatch match = regex.match(input);
QString str_year, str_week, str_hour, str_day, str_minute, str_second;
int year, week, day, hour, minute, second;
str_year = match.captured("year");
str_week = match.captured("week");
str_day = match.captured("day");
str_hour = match.captured("hr");
str_minute = match.captured("min");
str_second = match.captured("sec");
bool is_well_formed = false;
QString concat_str(str_year + str_week + str_day + str_hour + str_minute + str_second);
concat_str.toInt(&is_well_formed);
if (!is_well_formed) {
return -1;
}
year = str_year.toInt();
week = str_week.toInt();
day = str_day.toInt();
hour = str_hour.toInt();
minute = str_minute.toInt();
second = str_second.toInt();
long long total = 0;
total += 31622400 * year;
total += 604800 * week;
total += 86400 * day;
total += 3600 * hour;
total += 60 * minute;
total += second;
if (total < 0)
return -1;
return total;
}

View File

@ -24,32 +24,52 @@ DBManager::DBManager() :
db.setDatabaseName("config/akashi.db");
if (!db.open())
qCritical() << "Database Error:" << db.lastError();
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_ban_table("CREATE TABLE IF NOT EXISTS bans ('ID' INTEGER, 'IPID' TEXT, 'HDID' TEXT, 'IP' TEXT, 'TIME' INTEGER, 'REASON' TEXT, 'DURATION' INTEGER, 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 DBManager::isIPBanned(QHostAddress ip)
{
QSqlQuery query;
query.prepare("SELECT ID FROM BANS WHERE IP = ?");
query.prepare("SELECT TIME FROM BANS WHERE IP = ? ORDER BY TIME DESC");
query.addBindValue(ip.toString());
query.exec();
return query.first();
if (query.first()) {
long long duration = getBanDuration(ip);
long long ban_time = query.value(0).toLongLong();
if (duration == -2)
return true;
long long current_time = QDateTime::currentDateTime().toSecsSinceEpoch();
if (ban_time + duration > current_time)
return true;
else return false;
}
else return false;
}
bool DBManager::isHDIDBanned(QString hdid)
{
QSqlQuery query;
query.prepare("SELECT ID FROM BANS WHERE HDID = ?");
query.prepare("SELECT TIME FROM BANS WHERE HDID = ? ORDER BY TIME DESC");
query.addBindValue(hdid);
query.exec();
return query.first();
if (query.first()) {
long long duration = getBanDuration(hdid);
long long ban_time = query.value(0).toLongLong();
if (duration == -2)
return true;
long long current_time = QDateTime::currentDateTime().toSecsSinceEpoch();
if (ban_time + duration > current_time)
return true;
else return false;
}
else return false;
}
QString DBManager::getBanReason(QHostAddress ip)
{
QSqlQuery query;
query.prepare("SELECT REASON FROM BANS WHERE IP = ?");
query.prepare("SELECT REASON FROM BANS WHERE IP = ? ORDER BY TIME DESC");
query.addBindValue(ip.toString());
query.exec();
if (query.first()) {
@ -63,7 +83,7 @@ QString DBManager::getBanReason(QHostAddress ip)
QString DBManager::getBanReason(QString hdid)
{
QSqlQuery query;
query.prepare("SELECT REASON FROM BANS WHERE HDID = ?");
query.prepare("SELECT REASON FROM BANS WHERE HDID = ? ORDER BY TIME DESC");
query.addBindValue(hdid);
query.exec();
if (query.first()) {
@ -74,15 +94,44 @@ QString DBManager::getBanReason(QString hdid)
}
}
void DBManager::addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason)
long long DBManager::getBanDuration(QString hdid)
{
QSqlQuery query;
query.prepare("INSERT INTO BANS(IPID, HDID, IP, TIME, REASON) VALUES(?, ?, ?, ?, ?)");
query.prepare("SELECT DURATION FROM BANS WHERE HDID = ? ORDER BY TIME DESC");
query.addBindValue(hdid);
query.exec();
if (query.first()) {
return query.value(0).toLongLong();
}
else {
return -1;
}
}
long long DBManager::getBanDuration(QHostAddress ip)
{
QSqlQuery query;
query.prepare("SELECT DURATION FROM BANS WHERE IP = ? ORDER BY TIME DESC");
query.addBindValue(ip.toString());
query.exec();
if (query.first()) {
return query.value(0).toLongLong();
}
else {
return -1;
}
}
void DBManager::addBan(QString ipid, QHostAddress ip, QString hdid, unsigned long time, QString reason, long long duration)
{
QSqlQuery query;
query.prepare("INSERT INTO BANS(IPID, HDID, IP, TIME, REASON, DURATION) VALUES(?, ?, ?, ?, ?, ?)");
query.addBindValue(ipid);
query.addBindValue(hdid);
query.addBindValue(ip.toString());
query.addBindValue(QString::number(time));
query.addBindValue(reason);
query.addBindValue(duration);
if (!query.exec())
qDebug() << "SQL Error:" << query.lastError().text();
}

View File

@ -26,9 +26,9 @@ void AOClient::pktDefault(AreaData* area, int argc, QStringList argv, AOPacket p
void AOClient::pktHardwareId(AreaData* area, int argc, QStringList argv, AOPacket packet)
{
setHwid(argv[0]);
if(server->db_manager->isHDIDBanned(getHwid())) {
sendPacket("BD", {server->db_manager->getBanReason(getHwid())});
hwid = argv[0];
if(server->db_manager->isHDIDBanned(hwid)) {
sendPacket("BD", {server->db_manager->getBanReason(hwid)});
socket->close();
return;
}
@ -88,7 +88,7 @@ void AOClient::pktRequestMusic(AreaData* area, int argc, QStringList argv, AOPac
void AOClient::pktLoadingDone(AreaData* area, int argc, QStringList argv, AOPacket packet)
{
if (getHwid() == "") {
if (hwid == "") {
// No early connecting!
socket->close();
return;
@ -154,6 +154,11 @@ void AOClient::pktSelectChar(AreaData* area, int argc, QStringList argv, AOPacke
void AOClient::pktIcChat(AreaData* area, int argc, QStringList argv, AOPacket packet)
{
if (is_muted) {
sendServerMessage("You cannot speak while muted.");
return;
}
AOPacket validated_packet = validateIcPacket(packet);
if (validated_packet.header == "INVALID")
return;
@ -266,6 +271,7 @@ void AOClient::pktWebSocketIp(AreaData* area, int argc, QStringList argv, AOPack
qDebug() << "ws ip set to" << argv[0];
#endif
remote_ip = QHostAddress(argv[0]);
calculateIpid();
}
}