diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index 6fad7a0d..f5fd8308 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -444,7 +444,7 @@ void MainWindow::registerError(Response::ResponseCode r, QString reasonStr, quin QMessageBox::critical(this, tr("Registration denied"), tr("It's mandatory to specify a valid email address when registering.")); break; case Response::RespTooManyRequests: - QMessageBox::critical(this, tr("Registration denied"), tr("Too many registration attempts from your IP address.")); + QMessageBox::critical(this, tr("Registration denied"), tr("Too many registration attempts, please try again later or contact the server operator for further details.")); break; case Response::RespPasswordTooShort: QMessageBox::critical(this, tr("Registration denied"), tr("Password too short.")); diff --git a/common/server_database_interface.h b/common/server_database_interface.h index 960a454a..836c843e 100644 --- a/common/server_database_interface.h +++ b/common/server_database_interface.h @@ -45,6 +45,7 @@ public: enum LogMessage_TargetType { MessageTargetRoom, MessageTargetGame, MessageTargetChat, MessageTargetIslRoom }; virtual void logMessage(const int /* senderId */, const QString & /* senderName */, const QString & /* senderIp */, const QString & /* logMessage */, LogMessage_TargetType /* targetType */, const int /* targetId */, const QString & /* targetName */) { }; bool checkUserIsBanned(Server_ProtocolHandler *session, QString &banReason, int &banSecondsRemaining); + virtual int checkNumberOfUserAccounts(const QString & /* email */) { return 0; }; virtual bool changeUserPassword(const QString & /* user */, const QString & /* oldPassword */, const QString & /* newPassword */) { return true; }; virtual QChar getGenderChar(ServerInfo_User_Gender const & /* gender */) { return QChar('u'); }; }; diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index 0029775a..75bb33a4 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -140,6 +140,10 @@ disallowedregexp="" ; account activated. Default true. ;requireemailactivation=true +; Set this number to the maximum number of accounts any one user can use to create new accounts +; using the same email address. 0 = Unlimited number of accounts (default). +;maxaccountsperemail=0 + [smtp] ; Enable the internal smtp client to send registration emails. If you would like to diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 936132ef..e3c77086 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -242,6 +242,7 @@ bool Servatrice::initServer() if (getRegistrationEnabled()) { qDebug() << "Require email address to register: " << getRequireEmailForRegistrationEnabled(); qDebug() << "Require email activation via token: " << getRequireEmailActivationEnabled(); + if (getMaxAccountsPerEmail()) { qDebug() << "Maximum number of accounts per email: " << getMaxAccountsPerEmail(); } else { qDebug() << "Maximum number of accounts per email: unlimited"; } qDebug() << "Enable Internal SMTP Client: " << getEnableInternalSMTPClient(); if (!getEnableInternalSMTPClient()) { @@ -836,6 +837,10 @@ bool Servatrice::getEnableLogQuery() const { return settingsCache->value("logging/enablelogquery", false).toBool(); } +int Servatrice::getMaxAccountsPerEmail() const { + return settingsCache->value("registration/maxaccountsperemail", 0).toInt(); +} + bool Servatrice::getEnableInternalSMTPClient() const { return settingsCache->value("smtp/enableinternalsmtpclient", true).toBool(); } \ No newline at end of file diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 93207326..4eb2e17e 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -207,6 +207,7 @@ public: int getMaxTcpUserLimit() const; int getMaxWebSocketUserLimit() const; int getUsersWithAddress(const QHostAddress &address) const; + int getMaxAccountsPerEmail() const; QList getUsersWithAddressAsList(const QHostAddress &address) const; void incTxBytes(quint64 num); void incRxBytes(quint64 num); diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index 8065e9a7..cb8d834c 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -1109,3 +1109,22 @@ QList Servatrice_DatabaseInterface::getMessageLogHistory return results; } + +int Servatrice_DatabaseInterface::checkNumberOfUserAccounts(const QString &email) +{ + if (!checkSql()) + return 0; + + QSqlQuery *query = prepareQuery("SELECT count(email) FROM {prefix}_users WHERE email = :user_email"); + query->bindValue(":user_email", email); + + if (!execSqlQuery(query)) { + qDebug("Failed to identify the number of users accounts for users email address: SQL Error"); + return 0; + } + + if (query->next()) + return query->value(0).toInt(); + + return 0; +} diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 8d921b46..e770738a 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -69,7 +69,7 @@ public: bool userSessionExists(const QString &userName); bool usernameIsValid(const QString &user, QString & error); bool checkUserIsBanned(const QString &ipAddress, const QString &userName, const QString &clientId, QString &banReason, int &banSecondsRemaining); - + int checkNumberOfUserAccounts(const QString &email); 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); bool activateUser(const QString &userName, const QString &token); diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index d749108a..dcfecd94 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -906,6 +906,11 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C if(sqlInterface->userExists(userName)) return Response::RespUserAlreadyExists; + if (servatrice->getMaxAccountsPerEmail() && !(sqlInterface->checkNumberOfUserAccounts(emailAddress) < servatrice->getMaxAccountsPerEmail())) + { + return Response::RespTooManyRequests; + } + QString banReason; int banSecondsRemaining; if (sqlInterface->checkUserIsBanned(this->getAddress(), userName, clientId, banReason, banSecondsRemaining))