Add ability to ban by client id
This commit is contained in:
parent
26e63a9a3a
commit
b102a05a36
17 changed files with 114 additions and 24 deletions
|
@ -33,7 +33,7 @@ ServerInfo_User LocalServer_DatabaseInterface::getUserData(const QString &name,
|
|||
return result;
|
||||
}
|
||||
|
||||
AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_ProtocolHandler * /* handler */, const QString & /* user */, const QString & /* password */, QString & /* reasonStr */, int & /* secondsLeft */)
|
||||
AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_ProtocolHandler * /* handler */, const QString & /* user */, const QString & /* password */, const QString & /* clientId */, QString & /* reasonStr */, int & /* secondsLeft */)
|
||||
{
|
||||
return UnknownUser;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ protected:
|
|||
ServerInfo_User getUserData(const QString &name, bool withId = false);
|
||||
public:
|
||||
LocalServer_DatabaseInterface(LocalServer *_localServer);
|
||||
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft);
|
||||
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, const QString &clientId, QString &reasonStr, int &secondsLeft);
|
||||
int getNextGameId() { return localServer->getNextLocalGameId(); }
|
||||
int getNextReplayId() { return -1; }
|
||||
int getActiveUserCount() { return 0; }
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "pb/server_message.pb.h"
|
||||
#include "pb/event_server_identification.pb.h"
|
||||
#include "settingscache.h"
|
||||
#include "main.h"
|
||||
|
||||
static const unsigned int protocolVersion = 14;
|
||||
|
||||
|
@ -78,6 +79,7 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica
|
|||
cmdRegister.set_gender((ServerInfo_User_Gender) gender);
|
||||
cmdRegister.set_country(country.toStdString());
|
||||
cmdRegister.set_real_name(realName.toStdString());
|
||||
cmdRegister.set_clientid(settingsCache->getClientID().toStdString());
|
||||
|
||||
PendingCommand *pend = prepareSessionCommand(cmdRegister);
|
||||
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(registerResponse(Response)));
|
||||
|
|
|
@ -99,6 +99,7 @@ void UserContextMenu::banUser_dialogFinished()
|
|||
cmd.set_minutes(dlg->getMinutes());
|
||||
cmd.set_reason(dlg->getReason().toStdString());
|
||||
cmd.set_visible_reason(dlg->getVisibleReason().toStdString());
|
||||
cmd.set_clientid(dlg->getBanId().toStdString());
|
||||
|
||||
client->sendCommand(client->prepareModeratorCommand(cmd));
|
||||
}
|
||||
|
|
|
@ -36,11 +36,19 @@ BanDialog::BanDialog(const ServerInfo_User &info, QWidget *parent)
|
|||
ipBanCheckBox = new QCheckBox(tr("ban &IP address"));
|
||||
ipBanCheckBox->setChecked(true);
|
||||
ipBanEdit = new QLineEdit(QString::fromStdString(info.address()));
|
||||
idBanCheckBox = new QCheckBox(tr("ban client I&D"));
|
||||
idBanCheckBox->setChecked(true);
|
||||
idBanEdit = new QLineEdit(QString::fromStdString(info.clientid()));
|
||||
if (QString::fromStdString(info.clientid()).isEmpty())
|
||||
idBanCheckBox->setChecked(false);
|
||||
|
||||
QGridLayout *banTypeGrid = new QGridLayout;
|
||||
banTypeGrid->addWidget(nameBanCheckBox, 0, 0);
|
||||
banTypeGrid->addWidget(nameBanEdit, 0, 1);
|
||||
banTypeGrid->addWidget(ipBanCheckBox, 1, 0);
|
||||
banTypeGrid->addWidget(ipBanEdit, 1, 1);
|
||||
banTypeGrid->addWidget(idBanCheckBox, 2, 0);
|
||||
banTypeGrid->addWidget(idBanEdit, 2, 1);
|
||||
QGroupBox *banTypeGroupBox = new QGroupBox(tr("Ban type"));
|
||||
banTypeGroupBox->setLayout(banTypeGrid);
|
||||
|
||||
|
@ -110,8 +118,8 @@ BanDialog::BanDialog(const ServerInfo_User &info, QWidget *parent)
|
|||
|
||||
void BanDialog::okClicked()
|
||||
{
|
||||
if (!nameBanCheckBox->isChecked() && !ipBanCheckBox->isChecked()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("You have to select a name-based or IP-based ban, or both."));
|
||||
if (!nameBanCheckBox->isChecked() && !ipBanCheckBox->isChecked() && !idBanCheckBox->isChecked()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("You have to select a name-based, IP-based, clientId based, or some combination of the three to place a ban."));
|
||||
return;
|
||||
}
|
||||
accept();
|
||||
|
@ -127,6 +135,11 @@ void BanDialog::enableTemporaryEdits(bool enabled)
|
|||
minutesEdit->setEnabled(enabled);
|
||||
}
|
||||
|
||||
QString BanDialog::getBanId() const
|
||||
{
|
||||
return idBanCheckBox->isChecked() ? idBanEdit->text() : QString();
|
||||
}
|
||||
|
||||
QString BanDialog::getBanName() const
|
||||
{
|
||||
return nameBanCheckBox->isChecked() ? nameBanEdit->text() : QString();
|
||||
|
|
|
@ -24,8 +24,8 @@ class BanDialog : public QDialog {
|
|||
Q_OBJECT
|
||||
private:
|
||||
QLabel *daysLabel, *hoursLabel, *minutesLabel;
|
||||
QCheckBox *nameBanCheckBox, *ipBanCheckBox;
|
||||
QLineEdit *nameBanEdit, *ipBanEdit;
|
||||
QCheckBox *nameBanCheckBox, *ipBanCheckBox, *idBanCheckBox;
|
||||
QLineEdit *nameBanEdit, *ipBanEdit, *idBanEdit;
|
||||
QSpinBox *daysEdit, *hoursEdit, *minutesEdit;
|
||||
QRadioButton *permanentRadio, *temporaryRadio;
|
||||
QPlainTextEdit *reasonEdit, *visibleReasonEdit;
|
||||
|
@ -36,6 +36,7 @@ public:
|
|||
BanDialog(const ServerInfo_User &info, QWidget *parent = 0);
|
||||
QString getBanName() const;
|
||||
QString getBanIP() const;
|
||||
QString getBanId() const;
|
||||
int getMinutes() const;
|
||||
QString getReason() const;
|
||||
QString getVisibleReason() const;
|
||||
|
|
|
@ -14,4 +14,5 @@ message Command_BanFromServer {
|
|||
optional uint32 minutes = 3;
|
||||
optional string reason = 4;
|
||||
optional string visible_reason = 5;
|
||||
optional string clientid = 6;
|
||||
}
|
||||
|
|
|
@ -23,4 +23,5 @@ message ServerInfo_User {
|
|||
optional uint64 session_id = 10;
|
||||
optional uint64 accountage_secs = 11;
|
||||
optional string email = 12;
|
||||
optional string clientid = 13;
|
||||
}
|
||||
|
|
|
@ -119,6 +119,7 @@ message Command_Register {
|
|||
// Country code of the user. 2 letter ISO format
|
||||
optional string country = 5;
|
||||
optional string real_name = 6;
|
||||
optional string clientid = 7;
|
||||
}
|
||||
|
||||
// User wants to activate an account
|
||||
|
|
|
@ -112,7 +112,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
|
|||
|
||||
QWriteLocker locker(&clientsLock);
|
||||
|
||||
AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft);
|
||||
AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, clientid, reasonStr, secondsLeft);
|
||||
if (authState == NotLoggedIn || authState == UserIsBanned || authState == UsernameInvalid || authState == UserIsInactive)
|
||||
return authState;
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ public:
|
|||
Server_DatabaseInterface(QObject *parent = 0)
|
||||
: QObject(parent) { }
|
||||
|
||||
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0;
|
||||
virtual bool checkUserIsBanned(const QString & /* ipAddress */, const QString & /* userName */, QString & /* banReason */, int & /* banSecondsRemaining */) { return false; }
|
||||
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, const QString &clientId, QString &reasonStr, int &secondsLeft) = 0;
|
||||
virtual bool checkUserIsBanned(const QString & /* ipAddress */, const QString & /* userName */, const QString & /* clientId */, QString & /* banReason */, int & /* banSecondsRemaining */) { return false; }
|
||||
virtual bool activeUserExists(const QString & /* user */) { return false; }
|
||||
virtual bool userExists(const QString & /* user */) { return false; }
|
||||
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString & /* name */) { return QMap<QString, ServerInfo_User>(); }
|
||||
|
|
|
@ -36,6 +36,7 @@ ServerInfo_User &ServerInfo_User_Container::copyUserInfo(ServerInfo_User &result
|
|||
if (!sessionInfo) {
|
||||
result.clear_session_id();
|
||||
result.clear_address();
|
||||
result.clear_clientid();
|
||||
}
|
||||
if (!internalInfo)
|
||||
{
|
||||
|
|
5
servatrice/migrations/servatrice_0004_to_0005.sql
Normal file
5
servatrice/migrations/servatrice_0004_to_0005.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
-- Servatrice db migration from version 4 to version 5
|
||||
|
||||
alter table cockatrice_bans add clientid varchar(15) not null;
|
||||
|
||||
UPDATE cockatrice_schema_version SET version=5 WHERE version=4;
|
|
@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_schema_version` (
|
|||
PRIMARY KEY (`version`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
INSERT INTO cockatrice_schema_version VALUES(4);
|
||||
INSERT INTO cockatrice_schema_version VALUES(5);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `cockatrice_decklist_files` (
|
||||
`id` int(7) unsigned zerofill NOT NULL auto_increment,
|
||||
|
@ -132,6 +132,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_bans` (
|
|||
`minutes` int(6) NOT NULL,
|
||||
`reason` text NOT NULL,
|
||||
`visible_reason` text NOT NULL,
|
||||
`clientid` varchar(15) NOT NULL,
|
||||
PRIMARY KEY (`user_name`,`time_from`),
|
||||
KEY `time_from` (`time_from`,`ip_address`),
|
||||
KEY `ip_address` (`ip_address`)
|
||||
|
|
|
@ -229,7 +229,7 @@ QChar Servatrice_DatabaseInterface::getGenderChar(ServerInfo_User_Gender const &
|
|||
}
|
||||
}
|
||||
|
||||
AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &banSecondsLeft)
|
||||
AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, const QString &clientId, QString &reasonStr, int &banSecondsLeft)
|
||||
{
|
||||
switch (server->getAuthenticationMethod()) {
|
||||
case Servatrice::AuthenticationNone: return UnknownUser;
|
||||
|
@ -247,7 +247,7 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
|
|||
if (!usernameIsValid(user, reasonStr))
|
||||
return UsernameInvalid;
|
||||
|
||||
if (checkUserIsBanned(handler->getAddress(), user, reasonStr, banSecondsLeft))
|
||||
if (checkUserIsBanned(handler->getAddress(), user, clientId, reasonStr, banSecondsLeft))
|
||||
return UserIsBanned;
|
||||
|
||||
QSqlQuery *passwordQuery = prepareQuery("select password_sha512, active from {prefix}_users where name = :name");
|
||||
|
@ -280,7 +280,7 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot
|
|||
return UnknownUser;
|
||||
}
|
||||
|
||||
bool Servatrice_DatabaseInterface::checkUserIsBanned(const QString &ipAddress, const QString &userName, QString &banReason, int &banSecondsRemaining)
|
||||
bool Servatrice_DatabaseInterface::checkUserIsBanned(const QString &ipAddress, const QString &userName, const QString &clientId, QString &banReason, int &banSecondsRemaining)
|
||||
{
|
||||
if (server->getAuthenticationMethod() != Servatrice::AuthenticationSql)
|
||||
return false;
|
||||
|
@ -291,11 +291,48 @@ bool Servatrice_DatabaseInterface::checkUserIsBanned(const QString &ipAddress, c
|
|||
}
|
||||
|
||||
return
|
||||
checkUserIsIpBanned(ipAddress, banReason, banSecondsRemaining)
|
||||
|| checkUserIsNameBanned(userName, banReason, banSecondsRemaining);
|
||||
checkUserIsIpBanned(ipAddress, banReason, banSecondsRemaining) || checkUserIsNameBanned(userName, banReason, banSecondsRemaining) || checkUserIsIdBanned(clientId, banReason, banSecondsRemaining);
|
||||
|
||||
}
|
||||
|
||||
bool Servatrice_DatabaseInterface::checkUserIsIdBanned(const QString &clientId, QString &banReason, int &banSecondsRemaining)
|
||||
{
|
||||
if (clientId.isEmpty())
|
||||
return false;
|
||||
|
||||
QSqlQuery *idBanQuery = prepareQuery(
|
||||
"select"
|
||||
" timestampdiff(second, now(), date_add(b.time_from, interval b.minutes minute)),"
|
||||
" b.minutes <=> 0,"
|
||||
" b.visible_reason"
|
||||
" from {prefix}_bans b"
|
||||
" where"
|
||||
" b.time_from = (select max(c.time_from)"
|
||||
" from {prefix}_bans c"
|
||||
" where c.clientid = :id)"
|
||||
" and b.clientid = :id2");
|
||||
|
||||
idBanQuery->bindValue(":id", clientId);
|
||||
idBanQuery->bindValue(":id2", clientId);
|
||||
if (!execSqlQuery(idBanQuery)) {
|
||||
qDebug() << "Id ban check failed: SQL error." << idBanQuery->lastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idBanQuery->next()) {
|
||||
const int secondsLeft = idBanQuery->value(0).toInt();
|
||||
const bool permanentBan = idBanQuery->value(1).toInt();
|
||||
if ((secondsLeft > 0) || permanentBan) {
|
||||
banReason = idBanQuery->value(2).toString();
|
||||
banSecondsRemaining = permanentBan ? 0 : secondsLeft;
|
||||
qDebug() << "User is banned by client id" << clientId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Servatrice_DatabaseInterface::checkUserIsNameBanned(const QString &userName, QString &banReason, int &banSecondsRemaining)
|
||||
{
|
||||
QSqlQuery *nameBanQuery = prepareQuery("select timestampdiff(second, now(), date_add(b.time_from, interval b.minutes minute)), b.minutes <=> 0, b.visible_reason from {prefix}_bans b where b.time_from = (select max(c.time_from) from {prefix}_bans c where c.user_name = :name2) and b.user_name = :name1");
|
||||
|
@ -477,6 +514,10 @@ ServerInfo_User Servatrice_DatabaseInterface::evalUserQueryResult(const QSqlQuer
|
|||
const QString email = query->value(8).toString();
|
||||
if (!email.isEmpty())
|
||||
result.set_email(email.toStdString());
|
||||
|
||||
const QString clientid = query->value(9).toString();
|
||||
if (!clientid.isEmpty())
|
||||
result.set_clientid(clientid.toStdString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -491,7 +532,7 @@ ServerInfo_User Servatrice_DatabaseInterface::getUserData(const QString &name, b
|
|||
if (!checkSql())
|
||||
return result;
|
||||
|
||||
QSqlQuery *query = prepareQuery("select id, name, admin, country, gender, realname, avatar_bmp, registrationDate, email from {prefix}_users where name = :name and active = 1");
|
||||
QSqlQuery *query = prepareQuery("select id, name, admin, country, gender, realname, avatar_bmp, registrationDate, email, clientid from {prefix}_users where name = :name and active = 1");
|
||||
query->bindValue(":name", name);
|
||||
if (!execSqlQuery(query))
|
||||
return result;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "server.h"
|
||||
#include "server_database_interface.h"
|
||||
|
||||
#define DATABASE_SCHEMA_VERSION 4
|
||||
#define DATABASE_SCHEMA_VERSION 5
|
||||
|
||||
class Servatrice;
|
||||
|
||||
|
@ -22,13 +22,14 @@ private:
|
|||
Servatrice *server;
|
||||
ServerInfo_User evalUserQueryResult(const QSqlQuery *query, bool complete, bool withId = false);
|
||||
/** Must be called after checkSql and server is known to be in auth mode. */
|
||||
bool checkUserIsIdBanned(const QString &clientId, QString &banReason, int &banSecondsRemaining);
|
||||
/** Must be called after checkSql and server is known to be in auth mode. */
|
||||
bool checkUserIsIpBanned(const QString &ipAddress, QString &banReason, int &banSecondsRemaining);
|
||||
/** Must be called after checkSql and server is known to be in auth mode. */
|
||||
bool checkUserIsNameBanned(QString const &userName, QString &banReason, int &banSecondsRemaining);
|
||||
|
||||
protected:
|
||||
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user,
|
||||
const QString &password, QString &reasonStr, int &secondsLeft);
|
||||
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, const QString &clientId, QString &reasonStr, int &secondsLeft);
|
||||
|
||||
public slots:
|
||||
void initDatabase(const QSqlDatabase &_sqlDatabase);
|
||||
|
@ -66,7 +67,7 @@ public:
|
|||
void unlockSessionTables();
|
||||
bool userSessionExists(const QString &userName);
|
||||
bool usernameIsValid(const QString &user, QString & error);
|
||||
bool checkUserIsBanned(const QString &ipAddress, const QString &userName, QString &banReason, int &banSecondsRemaining);
|
||||
bool checkUserIsBanned(const QString &ipAddress, const QString &userName, const QString &clientId, QString &banReason, int &banSecondsRemaining);
|
||||
|
||||
bool registerUser(const QString &userName, const QString &realName, ServerInfo_User_Gender const &gender,
|
||||
const QString &password, const QString &emailAddress, const QString &country, QString &token, bool active = false);
|
||||
|
|
|
@ -756,20 +756,40 @@ Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_Ban
|
|||
if (trustedSources.contains(address,Qt::CaseInsensitive))
|
||||
address = "";
|
||||
|
||||
QSqlQuery *query = sqlInterface->prepareQuery("insert into {prefix}_bans (user_name, ip_address, id_admin, time_from, minutes, reason, visible_reason) values(:user_name, :ip_address, :id_admin, NOW(), :minutes, :reason, :visible_reason)");
|
||||
QSqlQuery *query = sqlInterface->prepareQuery("insert into {prefix}_bans (user_name, ip_address, id_admin, time_from, minutes, reason, visible_reason, clientid) values(:user_name, :ip_address, :id_admin, NOW(), :minutes, :reason, :visible_reason, :client_id)");
|
||||
query->bindValue(":user_name", userName);
|
||||
query->bindValue(":ip_address", address);
|
||||
query->bindValue(":id_admin", userInfo->id());
|
||||
query->bindValue(":minutes", minutes);
|
||||
query->bindValue(":reason", QString::fromStdString(cmd.reason()));
|
||||
query->bindValue(":visible_reason", QString::fromStdString(cmd.visible_reason()));
|
||||
query->bindValue(":client_id", QString::fromStdString(cmd.clientid()));
|
||||
sqlInterface->execSqlQuery(query);
|
||||
|
||||
servatrice->clientsLock.lockForRead();
|
||||
QList<ServerSocketInterface *> userList = servatrice->getUsersWithAddressAsList(QHostAddress(address));
|
||||
ServerSocketInterface *user = static_cast<ServerSocketInterface *>(server->getUsers().value(userName));
|
||||
if (user && !userList.contains(user))
|
||||
|
||||
if (!userName.isEmpty()) {
|
||||
ServerSocketInterface *user = static_cast<ServerSocketInterface *>(server->getUsers().value(userName));
|
||||
userList.append(user);
|
||||
}
|
||||
|
||||
if (userName.isEmpty() && address.isEmpty()) {
|
||||
QSqlQuery *query = sqlInterface->prepareQuery("select name from {prefix}_users where clientid = :client_id");
|
||||
query->bindValue(":client_id", QString::fromStdString(cmd.clientid()));
|
||||
sqlInterface->execSqlQuery(query);
|
||||
if (!sqlInterface->execSqlQuery(query)){
|
||||
qDebug("ClientID username ban lookup failed: SQL Error");
|
||||
} else {
|
||||
while (query->next()) {
|
||||
userName = query->value(0).toString();
|
||||
ServerSocketInterface *user = static_cast<ServerSocketInterface *>(server->getUsers().value(userName));
|
||||
if (user && !userList.contains(user))
|
||||
userList.append(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!userList.isEmpty()) {
|
||||
Event_ConnectionClosed event;
|
||||
event.set_reason(Event_ConnectionClosed::BANNED);
|
||||
|
@ -792,6 +812,7 @@ Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_Ban
|
|||
Response::ResponseCode ServerSocketInterface::cmdRegisterAccount(const Command_Register &cmd, ResponseContainer &rc)
|
||||
{
|
||||
QString userName = QString::fromStdString(cmd.user_name());
|
||||
QString clientId = QString::fromStdString(cmd.clientid());
|
||||
qDebug() << "Got register command: " << userName;
|
||||
|
||||
bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool();
|
||||
|
@ -822,7 +843,7 @@ Response::ResponseCode ServerSocketInterface::cmdRegisterAccount(const Command_R
|
|||
|
||||
QString banReason;
|
||||
int banSecondsRemaining;
|
||||
if (sqlInterface->checkUserIsBanned(this->getAddress(), userName, banReason, banSecondsRemaining))
|
||||
if (sqlInterface->checkUserIsBanned(this->getAddress(), userName, clientId, banReason, banSecondsRemaining))
|
||||
{
|
||||
Response_Register *re = new Response_Register;
|
||||
re->set_denied_reason_str(banReason.toStdString());
|
||||
|
|
Loading…
Reference in a new issue