diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index b73091a8..cdeee600 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -35,7 +35,6 @@ #include "QtNetwork/QNetworkInterface" #include - #include "main.h" #include "window_main.h" #include "dlg_settings.h" @@ -100,7 +99,7 @@ bool settingsValid() !settingsCache->getPicsPath().isEmpty(); } -void generateClientID() +QString const generateClientID() { QString macList; foreach(QNetworkInterface interface, QNetworkInterface::allInterfaces()) @@ -110,7 +109,7 @@ void generateClientID() macList += interface.hardwareAddress() + "."; } QString strClientID = QCryptographicHash::hash(macList.toUtf8(), QCryptographicHash::Sha1).toHex().right(15); - settingsCache->setClientID(strClientID); + return strClientID; } int main(int argc, char *argv[]) @@ -220,7 +219,7 @@ int main(int argc, char *argv[]) QIcon icon(":/resources/appicon.svg"); ui.setWindowIcon(icon); - generateClientID(); //generate the users client id + settingsCache->setClientID(generateClientID()); qDebug() << "ClientID In Cache: " << settingsCache->getClientID(); ui.showMaximized(); diff --git a/cockatrice/src/main.h b/cockatrice/src/main.h index 3ecb71fd..71feb9a7 100644 --- a/cockatrice/src/main.h +++ b/cockatrice/src/main.h @@ -7,14 +7,14 @@ class QSystemTrayIcon; class SoundEngine; extern CardDatabase *db; - extern QSystemTrayIcon *trayIcon; extern QTranslator *translator; extern const QString translationPrefix; extern QString translationPath; void installNewTranslator(); -void generateClientID(); + +QString const generateClientID(); bool settingsValid(); diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index c4fc9c52..47dccd51 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -316,6 +316,9 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 actRegister(); } break; + case Response::RespClientIdRequired: + QMessageBox::critical(this, tr("Error"), tr("This server requires client ID's. Your client is either failing to generate an ID or you are running a modified client.\nPlease close and reopen your client to try again.")); + break; case Response::RespAccountNotActivated: { bool ok = false; QString token = QInputDialog::getText(this, tr("Account activation"), tr("Your account has not been activated yet.\nYou need to provide the activation token received in the activation email"), QLineEdit::Normal, QString(), &ok); diff --git a/common/pb/response.proto b/common/pb/response.proto index 09a68275..ae4ff040 100644 --- a/common/pb/response.proto +++ b/common/pb/response.proto @@ -35,7 +35,7 @@ message Response { RespActivationAccepted = 31; // Server accepted a reg user activation token RespActivationFailed = 32; // Server didn't accept a reg user activation token RespRegistrationAcceptedNeedsActivation = 33; // Server accepted cient registration, but it will need token activation - RespClientIDRequired = 34; // Server require's client to generate and send its client id before allowing access + RespClientIdRequired = 34; // Server requires client to generate and send its client id before allowing access } enum ResponseType { JOIN_ROOM = 1000; diff --git a/common/server.cpp b/common/server.cpp index ce9e9abd..e07db95e 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -170,9 +170,10 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true)); locker.unlock(); - // check if client id exists (older client compatibility) if (clientid.isEmpty()){ // client id is empty, either out dated client or client has been modified + if (getClientIdRequired()) + return ClientIdRequired; } else { // update users database table with client id diff --git a/common/server.h b/common/server.h index adf1c3c1..46008fb0 100644 --- a/common/server.h +++ b/common/server.h @@ -28,7 +28,7 @@ class GameEventContainer; class CommandContainer; class Command_JoinGame; -enum AuthenticationResult { NotLoggedIn, PasswordRight, UnknownUser, WouldOverwriteOldSession, UserIsBanned, UsernameInvalid, RegistrationRequired, UserIsInactive }; +enum AuthenticationResult { NotLoggedIn, PasswordRight, UnknownUser, WouldOverwriteOldSession, UserIsBanned, UsernameInvalid, RegistrationRequired, UserIsInactive, ClientIdRequired }; class Server : public QObject { @@ -56,6 +56,7 @@ public: virtual QString getLoginMessage() const { return QString(); } virtual bool getGameShouldPing() const { return false; } + virtual bool getClientIdRequired() const { return false; } virtual int getPingClockInterval() const { return 0; } virtual int getMaxGameInactivityTime() const { return 9999999; } virtual int getMaxPlayerInactivityTime() const { return 9999999; } diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 70cb2126..073a3d95 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -381,12 +381,16 @@ Response::ResponseCode Server_ProtocolHandler::cmdPing(const Command_Ping & /*cm Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd, ResponseContainer &rc) { QString userName = QString::fromStdString(cmd.user_name()).simplified(); - QString clientid = QString::fromStdString(cmd.clientid()).simplified(); + QString clientId = QString::fromStdString(cmd.clientid()).simplified(); + if (userName.isEmpty() || (userInfo != 0)) return Response::RespContextError; + if (clientId.isEmpty()) + return Response::RespContextError; + QString reasonStr; int banSecondsLeft = 0; - AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft, clientid); + AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft, clientId); switch (res) { case UserIsBanned: { Response_Login *re = new Response_Login; @@ -405,6 +409,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd return Response::RespUsernameInvalid; } case RegistrationRequired: return Response::RespRegistrationRequired; + case ClientIdRequired: return Response::RespClientIdRequired; case UserIsInactive: return Response::RespAccountNotActivated; default: authState = res; } diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index f0388863..313001c7 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -46,6 +46,9 @@ clientkeepalive=1 ; considered disconnected; default is 15 max_player_inactivity_time=15 +; More modern clients generate client IDs based on specific client side information. Enable this option to +' require that clients report the client ID in order to log into the server. Default is false +requireclientid=false [authentication] diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index d30a8aaa..d218cfac 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -142,6 +142,7 @@ bool Servatrice::initServer() { serverName = settingsCache->value("server/name", "My Cockatrice server").toString(); serverId = settingsCache->value("server/id", 0).toInt(); + clientIdRequired = settingsCache->value("server/requireclientid",0).toBool(); bool regServerOnly = settingsCache->value("authentication/regonly", 0).toBool(); const QString authenticationMethodStr = settingsCache->value("authentication/method").toString(); @@ -160,7 +161,8 @@ bool Servatrice::initServer() qDebug() << "Authenticating method: none"; authenticationMethod = AuthenticationNone; } - + + qDebug() << "Client ID Required: " << clientIdRequired; bool maxUserLimitEnabled = settingsCache->value("security/enable_max_user_limit", false).toBool(); qDebug() << "Maximum user limit enabled: " << maxUserLimitEnabled; diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index a0421cd5..b097022c 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -43,125 +43,126 @@ class ServerSocketInterface; class IslInterface; class Servatrice_GameServer : public QTcpServer { - Q_OBJECT + Q_OBJECT private: - Servatrice *server; - QList connectionPools; + Servatrice *server; + QList connectionPools; public: - Servatrice_GameServer(Servatrice *_server, int _numberPools, const QSqlDatabase &_sqlDatabase, QObject *parent = 0); - ~Servatrice_GameServer(); + Servatrice_GameServer(Servatrice *_server, int _numberPools, const QSqlDatabase &_sqlDatabase, QObject *parent = 0); + ~Servatrice_GameServer(); protected: #if QT_VERSION < 0x050000 - void incomingConnection(int socketDescriptor); + void incomingConnection(int socketDescriptor); #else - void incomingConnection(qintptr socketDescriptor); + void incomingConnection(qintptr socketDescriptor); #endif }; class Servatrice_IslServer : public QTcpServer { - Q_OBJECT + Q_OBJECT private: - Servatrice *server; - QSslCertificate cert; - QSslKey privateKey; + Servatrice *server; + QSslCertificate cert; + QSslKey privateKey; public: - Servatrice_IslServer(Servatrice *_server, const QSslCertificate &_cert, const QSslKey &_privateKey, QObject *parent = 0) - : QTcpServer(parent), server(_server), cert(_cert), privateKey(_privateKey) { } + Servatrice_IslServer(Servatrice *_server, const QSslCertificate &_cert, const QSslKey &_privateKey, QObject *parent = 0) + : QTcpServer(parent), server(_server), cert(_cert), privateKey(_privateKey) { } protected: #if QT_VERSION < 0x050000 - void incomingConnection(int socketDescriptor); + void incomingConnection(int socketDescriptor); #else - void incomingConnection(qintptr socketDescriptor); + void incomingConnection(qintptr socketDescriptor); #endif }; class ServerProperties { public: - int id; - QSslCertificate cert; - QString hostname; - QHostAddress address; - int gamePort; - int controlPort; + int id; + QSslCertificate cert; + QString hostname; + QHostAddress address; + int gamePort; + int controlPort; - ServerProperties(int _id, const QSslCertificate &_cert, const QString &_hostname, const QHostAddress &_address, int _gamePort, int _controlPort) - : id(_id), cert(_cert), hostname(_hostname), address(_address), gamePort(_gamePort), controlPort(_controlPort) { } + ServerProperties(int _id, const QSslCertificate &_cert, const QString &_hostname, const QHostAddress &_address, int _gamePort, int _controlPort) + : id(_id), cert(_cert), hostname(_hostname), address(_address), gamePort(_gamePort), controlPort(_controlPort) { } }; class Servatrice : public Server { - Q_OBJECT + Q_OBJECT public: - enum AuthenticationMethod { AuthenticationNone, AuthenticationSql, AuthenticationPassword }; + enum AuthenticationMethod { AuthenticationNone, AuthenticationSql, AuthenticationPassword }; private slots: - void statusUpdate(); - void shutdownTimeout(); + void statusUpdate(); + void shutdownTimeout(); protected: - void doSendIslMessage(const IslMessage &msg, int serverId); + void doSendIslMessage(const IslMessage &msg, int serverId); private: - enum DatabaseType { DatabaseNone, DatabaseMySql }; - AuthenticationMethod authenticationMethod; - DatabaseType databaseType; - QTimer *pingClock, *statusUpdateClock; - Servatrice_GameServer *gameServer; - Servatrice_IslServer *islServer; - QString serverName; - mutable QMutex loginMessageMutex; - QString loginMessage; - QString dbPrefix; - Servatrice_DatabaseInterface *servatriceDatabaseInterface; - int serverId; - int uptime; - QMutex txBytesMutex, rxBytesMutex; - quint64 txBytes, rxBytes; - int maxGameInactivityTime, maxPlayerInactivityTime; - int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser, commandCountingInterval, maxCommandCountPerInterval, pingClockInterval; + enum DatabaseType { DatabaseNone, DatabaseMySql }; + AuthenticationMethod authenticationMethod; + DatabaseType databaseType; + QTimer *pingClock, *statusUpdateClock; + Servatrice_GameServer *gameServer; + Servatrice_IslServer *islServer; + QString serverName; + mutable QMutex loginMessageMutex; + QString loginMessage; + QString dbPrefix; + Servatrice_DatabaseInterface *servatriceDatabaseInterface; + int serverId; + int uptime; + QMutex txBytesMutex, rxBytesMutex; + quint64 txBytes, rxBytes; + int maxGameInactivityTime, maxPlayerInactivityTime; + int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser, commandCountingInterval, maxCommandCountPerInterval, pingClockInterval; - QString shutdownReason; - int shutdownMinutes; - QTimer *shutdownTimer; - bool isFirstShutdownMessage; + QString shutdownReason; + int shutdownMinutes; + QTimer *shutdownTimer; + bool isFirstShutdownMessage, clientIdRequired; - mutable QMutex serverListMutex; - QList serverList; - void updateServerList(); + mutable QMutex serverListMutex; + QList serverList; + void updateServerList(); - QMap islInterfaces; + QMap islInterfaces; public slots: - void scheduleShutdown(const QString &reason, int minutes); - void updateLoginMessage(); + void scheduleShutdown(const QString &reason, int minutes); + void updateLoginMessage(); public: - Servatrice(QObject *parent = 0); - ~Servatrice(); - bool initServer(); - QString getServerName() const { return serverName; } - QString getLoginMessage() const { QMutexLocker locker(&loginMessageMutex); return loginMessage; } - bool getGameShouldPing() const { return true; } - int getPingClockInterval() const { return pingClockInterval; } - int getMaxGameInactivityTime() const { return maxGameInactivityTime; } - int getMaxPlayerInactivityTime() const { return maxPlayerInactivityTime; } - int getMaxUsersPerAddress() const { return maxUsersPerAddress; } - int getMessageCountingInterval() const { return messageCountingInterval; } - int getMaxMessageCountPerInterval() const { return maxMessageCountPerInterval; } - int getMaxMessageSizePerInterval() const { return maxMessageSizePerInterval; } - int getMaxGamesPerUser() const { return maxGamesPerUser; } + Servatrice(QObject *parent = 0); + ~Servatrice(); + bool initServer(); + QString getServerName() const { return serverName; } + QString getLoginMessage() const { QMutexLocker locker(&loginMessageMutex); return loginMessage; } + bool getGameShouldPing() const { return true; } + bool getClientIdRequired() const { return clientIdRequired; } + int getPingClockInterval() const { return pingClockInterval; } + int getMaxGameInactivityTime() const { return maxGameInactivityTime; } + int getMaxPlayerInactivityTime() const { return maxPlayerInactivityTime; } + int getMaxUsersPerAddress() const { return maxUsersPerAddress; } + int getMessageCountingInterval() const { return messageCountingInterval; } + int getMaxMessageCountPerInterval() const { return maxMessageCountPerInterval; } + int getMaxMessageSizePerInterval() const { return maxMessageSizePerInterval; } + int getMaxGamesPerUser() const { return maxGamesPerUser; } int getCommandCountingInterval() const { return commandCountingInterval; } int getMaxCommandCountPerInterval() const { return maxCommandCountPerInterval; } - AuthenticationMethod getAuthenticationMethod() const { return authenticationMethod; } - QString getDbPrefix() const { return dbPrefix; } - int getServerId() const { return serverId; } - int getUsersWithAddress(const QHostAddress &address) const; - QList getUsersWithAddressAsList(const QHostAddress &address) const; - void incTxBytes(quint64 num); - void incRxBytes(quint64 num); - void addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface); + AuthenticationMethod getAuthenticationMethod() const { return authenticationMethod; } + QString getDbPrefix() const { return dbPrefix; } + int getServerId() const { return serverId; } + int getUsersWithAddress(const QHostAddress &address) const; + QList getUsersWithAddressAsList(const QHostAddress &address) const; + void incTxBytes(quint64 num); + void incRxBytes(quint64 num); + void addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface); - bool islConnectionExists(int serverId) const; - void addIslInterface(int serverId, IslInterface *interface); - void removeIslInterface(int serverId); - QReadWriteLock islLock; + bool islConnectionExists(int serverId) const; + void addIslInterface(int serverId, IslInterface *interface); + void removeIslInterface(int serverId); + QReadWriteLock islLock; - QList getServerList() const; + QList getServerList() const; }; #endif